comparison sms.c @ 2521:8cf7cadc17ee

Initial SC-3000 support
author Michael Pavone <pavone@retrodev.com>
date Fri, 11 Oct 2024 00:46:53 -0700
parents d44fe974fb85
children 1843adbe9899 90a40be940f7
comparison
equal deleted inserted replaced
2520:0e9d7ef03983 2521:8cf7cadc17ee
124 return (port_a & 0x40) | (port_b >> 2 & 0xF) | (port_b << 1 & 0x80) | 0x10; 124 return (port_a & 0x40) | (port_b >> 2 & 0xF) | (port_b << 1 & 0x80) | 0x10;
125 } 125 }
126 return 0xFF; 126 return 0xFF;
127 } 127 }
128 128
129 static void i8255_output_updated(i8255 *ppi, uint32_t cycle, uint32_t port, uint8_t data)
130 {
131 if (port == 2) {
132 sms_context *sms = ppi->system;
133 sms->kb_mux = data & 0x7;
134 }
135 }
136
137 static uint8_t i8255_input_poll(i8255 *ppi, uint32_t cycle, uint32_t port)
138 {
139 if (port > 1) {
140 return 0xFF;
141 }
142 sms_context *sms = ppi->system;
143 if (sms->kb_mux == 7) {
144 if (port) {
145 //TODO: cassette-in
146 //TODO: printer port BUSY/FAULT
147 uint8_t port_b = io_data_read(sms->io.ports+1, cycle);
148 return (port_b >> 2 & 0xF) | 0x10;
149 } else {
150 uint8_t port_a = io_data_read(sms->io.ports, cycle);
151 uint8_t port_b = io_data_read(sms->io.ports+1, cycle);
152 return (port_a & 0x3F) | (port_b << 6);
153 }
154 }
155 //TODO: keyboard matrix ghosting
156 if (port) {
157 //TODO: cassette-in
158 //TODO: printer port BUSY/FAULT
159 return (sms->keystate[sms->kb_mux] >> 8) | 0x10;
160 }
161 return sms->keystate[sms->kb_mux];
162 }
163
129 static void update_mem_map(uint32_t location, sms_context *sms, uint8_t value) 164 static void update_mem_map(uint32_t location, sms_context *sms, uint8_t value)
130 { 165 {
131 z80_context *z80 = sms->z80; 166 z80_context *z80 = sms->z80;
132 void *old_value; 167 void *old_value;
133 if (location) { 168 if (location) {
247 sms_context *sms = z80->system; 282 sms_context *sms = z80->system;
248 psg_run(sms->psg, z80->Z80_CYCLE); 283 psg_run(sms->psg, z80->Z80_CYCLE);
249 sms->psg->pan = value; 284 sms->psg->pan = value;
250 return vcontext; 285 return vcontext;
251 } 286 }
287
288 static void *ppi_write(uint32_t location, void *vcontext, uint8_t value)
289 {
290 z80_context *z80 = vcontext;
291 sms_context *sms = z80->system;
292 i8255_write(location, sms->i8255, value, z80->Z80_CYCLE);
293 return vcontext;
294 }
295
296 static uint8_t ppi_read(uint32_t location, void *vcontext)
297 {
298 z80_context *z80 = vcontext;
299 sms_context *sms = z80->system;
300 return i8255_read(location, sms->i8255, z80->Z80_CYCLE);
301 }
302
303 static void *all_write(uint32_t location, void *vcontext, uint8_t value)
304 {
305 vdp_write(location, vcontext, value);
306 sms_psg_write(location, vcontext, value);
307 return ppi_write(location, vcontext, value);
308 }
309
310 static uint8_t ppi_vdp_read(uint32_t location, void *vcontext)
311 {
312 //TODO: "corrupt" PPI value by VDP value
313 vdp_read(location, vcontext);
314 return ppi_read(location, vcontext);
315 }
316
317 static void *vdp_psg_write(uint32_t location, void *vcontext, uint8_t value)
318 {
319 vdp_write(location, vcontext, value);
320 return sms_psg_write(location, vcontext, value);
321 }
322
323 static void *ppi_psg_write(uint32_t location, void *vcontext, uint8_t value)
324 {
325 vdp_write(location, vcontext, value);
326 return ppi_write(location, vcontext, value);
327 }
328
329 static void *ppi_vdp_write(uint32_t location, void *vcontext, uint8_t value)
330 {
331 vdp_write(location, vcontext, value);
332 return ppi_write(location, vcontext, value);
333 }
334
252 static memmap_chunk io_map[] = { 335 static memmap_chunk io_map[] = {
253 {0x00, 0x40, 0xFF, .write_8 = memory_io_write}, 336 {0x00, 0x40, 0xFF, .write_8 = memory_io_write},
254 {0x40, 0x80, 0xFF, .read_8 = hv_read, .write_8 = sms_psg_write}, 337 {0x40, 0x80, 0xFF, .read_8 = hv_read, .write_8 = sms_psg_write},
255 {0x80, 0xC0, 0xFF, .read_8 = vdp_read, .write_8 = vdp_write}, 338 {0x80, 0xC0, 0xFF, .read_8 = vdp_read, .write_8 = vdp_write},
256 {0xC0, 0x100,0xFF, .read_8 = io_read} 339 {0xC0, 0x100,0xFF, .read_8 = io_read}
261 {0x06, 0x07, 0xFF, .write_8 = psg_pan_write}, 344 {0x06, 0x07, 0xFF, .write_8 = psg_pan_write},
262 {0x08, 0x40, 0xFF, .write_8 = memory_io_write}, 345 {0x08, 0x40, 0xFF, .write_8 = memory_io_write},
263 {0x40, 0x80, 0xFF, .read_8 = hv_read, .write_8 = sms_psg_write}, 346 {0x40, 0x80, 0xFF, .read_8 = hv_read, .write_8 = sms_psg_write},
264 {0x80, 0xC0, 0xFF, .read_8 = vdp_read, .write_8 = vdp_write}, 347 {0x80, 0xC0, 0xFF, .read_8 = vdp_read, .write_8 = vdp_write},
265 {0xC0, 0x100,0xFF, .read_8 = io_read} 348 {0xC0, 0x100,0xFF, .read_8 = io_read}
349 };
350
351 static memmap_chunk io_sc[] = {
352 {0x00, 0x20, 0x03, .read_8 = ppi_vdp_read, .write_8 = all_write},
353 {0x20, 0x40, 0xFF, .read_8 = vdp_read, .write_8 = vdp_psg_write},
354 {0x40, 0x60, 0x03, .read_8 = ppi_read, .write_8 = ppi_psg_write},
355 {0x60, 0x80, 0xFF, .write_8 = sms_psg_write},
356 {0x80, 0xA0, 0x03, .read_8 = ppi_vdp_read, .write_8 = ppi_vdp_write},
357 {0xA0, 0xC0, 0xFF, .read_8 = vdp_read, .write_8 = vdp_write},
358 {0xD0, 0x100, 0x03, .read_8 = ppi_read, .write_8 = ppi_write}
266 }; 359 };
267 360
268 static void set_speed_percent(system_header * system, uint32_t percent) 361 static void set_speed_percent(system_header * system, uint32_t percent)
269 { 362 {
270 sms_context *context = (sms_context *)system; 363 sms_context *context = (sms_context *)system;
587 sms_context *sms = (sms_context *)system; 680 sms_context *sms = (sms_context *)system;
588 vdp_free(sms->vdp); 681 vdp_free(sms->vdp);
589 z80_options_free(sms->z80->Z80_OPTS); 682 z80_options_free(sms->z80->Z80_OPTS);
590 free(sms->z80); 683 free(sms->z80);
591 psg_free(sms->psg); 684 psg_free(sms->psg);
685 free(sms->i8255);
592 free(sms); 686 free(sms);
593 } 687 }
594 688
595 static uint16_t get_open_bus_value(system_header *system) 689 static uint16_t get_open_bus_value(system_header *system)
596 { 690 {
668 { 762 {
669 sms_context *sms = (sms_context *)system; 763 sms_context *sms = (sms_context *)system;
670 io_mouse_motion_relative(&sms->io, mouse_num, x, y); 764 io_mouse_motion_relative(&sms->io, mouse_num, x, y);
671 } 765 }
672 766
767 uint16_t scancode_map[0x90] = {
768 [0x1C] = 0x0004,//A
769 [0x32] = 0x4008,//B
770 [0x21] = 0x2008,//C
771 [0x23] = 0x2004,//D
772 [0x24] = 0x2002,//E
773 [0x2B] = 0x3004,//F
774 [0x34] = 0x4004,//G
775 [0x33] = 0x5004,//H
776 [0x43] = 0x0080,//I
777 [0x3B] = 0x6004,//J
778 [0x42] = 0x0040,//K
779 [0x4B] = 0x1040,//L
780 [0x3A] = 0x6008,//M
781 [0x31] = 0x5008,//N
782 [0x44] = 0x1080,//O
783 [0x4D] = 0x2080,//P
784 [0x15] = 0x0002,//Q
785 [0x2D] = 0x3002,//R
786 [0x1B] = 0x1004,//S
787 [0x2C] = 0x4002,//T
788 [0x3C] = 0x6002,//U
789 [0x2A] = 0x3008,//V
790 [0x1D] = 0x1002,//W
791 [0x22] = 0x1008,//X
792 [0x35] = 0x5002,//Y
793 [0x1A] = 0x0008,//Z
794 [0x16] = 0x0001,//1
795 [0x1E] = 0x1001,//2
796 [0x26] = 0x2001,//3
797 [0x25] = 0x3001,//4
798 [0x2E] = 0x4001,//5
799 [0x36] = 0x5001,//6
800 [0x3D] = 0x6001,//7
801 [0x3E] = 0x0100,//8
802 [0x46] = 0x1100,//9
803 [0x45] = 0x2100,//0
804 [0x5A] = 0x5040,//return
805 [0x29] = 0x1010,//space
806 [0x0D] = 0x5800,//tab mapped to FUNC
807 [0x66] = 0x3010,//backspace mapped to INS/DEL
808 [0x4E] = 0x3100,// -
809 [0x55] = 0x4100,// = mapped to ^ based on position
810 [0x54] = 0x4080,// [
811 [0x5B] = 0x4040,// ]
812 [0x5D] = 0x5100,// \ mapped to Yen based on position/correspondence on PC keyboards
813 [0x4C] = 0x2040,// ;
814 [0x52] = 0x3040,// ' mapped to : based on position
815 [0x0E] = 0x3020,// ` mapped to PI because of lack of good options
816 [0x41] = 0x0020,// ,
817 [0x49] = 0x1020,// .
818 [0x4A] = 0x2020,// /
819 [0x14] = 0x6400,//lctrl mapped to ctrl
820 //rctrl is default keybind for toggle keyboard capture
821 //[0x18] = 0x6400,//rctrl mapped to ctrl
822 [0x12] = 0x6800,//lshift mapped to shift
823 [0x59] = 0x6800,//lshift mapped to shift
824 [0x11] = 0x6200,//lalt mapped to GRAPH
825 [0x17] = 0x6200,//ralt mapped to GRAPH
826 [0x81] = 0x0010,//insert mapped to kana/dieresis key
827 [0x86] = 0x5020,//left arrow
828 [0x87] = 0x2010,//home mapped to HOME/CLR
829 [0x88] = 0x6100,//end mapped to BREAK
830 [0x89] = 0x6040,//up arrow
831 [0x8A] = 0x4020,//down arrow
832 [0x8D] = 0x6020,//right arrow
833 };
834
673 static void keyboard_down(system_header *system, uint8_t scancode) 835 static void keyboard_down(system_header *system, uint8_t scancode)
674 { 836 {
675 sms_context *sms = (sms_context *)system; 837 sms_context *sms = (sms_context *)system;
676 io_keyboard_down(&sms->io, scancode); 838 io_keyboard_down(&sms->io, scancode);
839 if (sms->keystate && scancode < 0x90 && scancode_map[scancode]) {
840 uint16_t row = scancode_map[scancode] >> 12;
841 sms->keystate[row] &= ~(scancode_map[scancode] & 0xFFF);
842 }
677 } 843 }
678 844
679 static void keyboard_up(system_header *system, uint8_t scancode) 845 static void keyboard_up(system_header *system, uint8_t scancode)
680 { 846 {
681 sms_context *sms = (sms_context *)system; 847 sms_context *sms = (sms_context *)system;
682 io_keyboard_up(&sms->io, scancode); 848 io_keyboard_up(&sms->io, scancode);
849 if (sms->keystate && scancode < 0x90 && scancode_map[scancode]) {
850 uint16_t row = scancode_map[scancode] >> 12;
851 sms->keystate[row] |= scancode_map[scancode] & 0xFFF;
852 }
683 } 853 }
684 854
685 static void set_gain_config(sms_context *sms) 855 static void set_gain_config(sms_context *sms)
686 { 856 {
687 char *config_gain; 857 char *config_gain;
726 sms->header.info = configure_rom_sms(rom_db, media->buffer, media->size, base_map, sizeof(base_map)/sizeof(base_map[0])); 896 sms->header.info = configure_rom_sms(rom_db, media->buffer, media->size, base_map, sizeof(base_map)/sizeof(base_map[0]));
727 uint32_t rom_size = sms->header.info.rom_size; 897 uint32_t rom_size = sms->header.info.rom_size;
728 z80_options *zopts = malloc(sizeof(z80_options)); 898 z80_options *zopts = malloc(sizeof(z80_options));
729 tern_node *model_def; 899 tern_node *model_def;
730 uint8_t is_gamegear = !strcasecmp(media->extension, "gg"); 900 uint8_t is_gamegear = !strcasecmp(media->extension, "gg");
901 uint8_t is_sc3000 = !strcasecmp(media->extension, "sc");
731 if (is_gamegear) { 902 if (is_gamegear) {
732 model_def = tern_find_node(get_systems_config(), "gg"); 903 model_def = tern_find_node(get_systems_config(), "gg");
733 } else if (!strcasecmp(media->extension, "sg")) { 904 } else if (!strcasecmp(media->extension, "sg")) {
734 model_def = tern_find_node(get_systems_config(), "sg1000"); 905 model_def = tern_find_node(get_systems_config(), "sg1000");
906 } else if (is_sc3000) {
907 model_def = tern_find_node(get_systems_config(), "sc3000");
735 } else { 908 } else {
736 model_def = get_model(config, SYSTEM_SMS); 909 model_def = get_model(config, SYSTEM_SMS);
737 } 910 }
738 char *vdp_str = tern_find_ptr(model_def, "vdp"); 911 char *vdp_str = tern_find_ptr(model_def, "vdp");
739 uint8_t vdp_type = is_gamegear ? VDP_GENESIS : VDP_GAMEGEAR; 912 uint8_t vdp_type = is_gamegear ? VDP_GAMEGEAR : is_sc3000 ? VDP_TMS9918A : VDP_SMS2;
740 if (vdp_str) { 913 if (vdp_str) {
741 if (!strcmp(vdp_str, "sms1")) { 914 if (!strcmp(vdp_str, "sms1")) {
742 vdp_type = VDP_SMS; 915 vdp_type = VDP_SMS;
743 } else if (!strcmp(vdp_str, "sms2")) { 916 } else if (!strcmp(vdp_str, "sms2")) {
744 vdp_type = VDP_SMS2; 917 vdp_type = VDP_SMS2;
757 memmap_chunk *chunk = sms->header.info.map + i; 930 memmap_chunk *chunk = sms->header.info.map + i;
758 if ((chunk->flags == MMAP_READ) && !chunk->buffer && chunk->start > 0xC000) { 931 if ((chunk->flags == MMAP_READ) && !chunk->buffer && chunk->start > 0xC000) {
759 chunk->buffer = sms->ram + ((chunk->start - 0xC000) & 0x1FFF); 932 chunk->buffer = sms->ram + ((chunk->start - 0xC000) & 0x1FFF);
760 } 933 }
761 } 934 }
935 char *io_type = tern_find_ptr(model_def, "io");
936 if (io_type) {
937 if (!strcmp(io_type, "gamegear")) {
938 is_gamegear = 1;
939 is_sc3000 = 0;
940 } else if (!strcmp(io_type, "i8255")) {
941 is_gamegear = 0;
942 is_sc3000 = 1;
943 }
944 }
762 if (is_gamegear) { 945 if (is_gamegear) {
763 init_z80_opts(zopts, sms->header.info.map, sms->header.info.map_chunks, io_gg, 6, 15, 0xFF); 946 init_z80_opts(zopts, sms->header.info.map, sms->header.info.map_chunks, io_gg, 6, 15, 0xFF);
764 sms->start_button_region = 0xC0; 947 sms->start_button_region = 0xC0;
948 } else if (is_sc3000) {
949 sms->keystate = calloc(sizeof(uint16_t), 7);
950 memset(sms->keystate, 0xFF, sizeof(uint16_t) * 7);
951 sms->i8255 = calloc(1, sizeof(i8255));
952 i8255_init(sms->i8255, i8255_output_updated, i8255_input_poll);
953 sms->i8255->system = sms;
954 sms->kb_mux = 7;
955 init_z80_opts(zopts, sms->header.info.map, sms->header.info.map_chunks, io_sc, 7, 15, 0xFF);
765 } else { 956 } else {
766 init_z80_opts(zopts, sms->header.info.map, sms->header.info.map_chunks, io_map, 4, 15, 0xFF); 957 init_z80_opts(zopts, sms->header.info.map, sms->header.info.map_chunks, io_map, 4, 15, 0xFF);
767 } 958 }
768 sms->z80 = init_z80_context(zopts); 959 sms->z80 = init_z80_context(zopts);
769 sms->z80->system = sms; 960 sms->z80->system = sms;
801 if (io) { 992 if (io) {
802 io_config_root = sms_root; 993 io_config_root = sms_root;
803 } 994 }
804 } 995 }
805 setup_io_devices(io_config_root, &sms->header.info, &sms->io); 996 setup_io_devices(io_config_root, &sms->header.info, &sms->io);
806 sms->header.has_keyboard = io_has_keyboard(&sms->io); 997 sms->header.has_keyboard = io_has_keyboard(&sms->io) || sms->keystate;
807 998
808 sms->header.set_speed_percent = set_speed_percent; 999 sms->header.set_speed_percent = set_speed_percent;
809 sms->header.start_context = start_sms; 1000 sms->header.start_context = start_sms;
810 sms->header.resume_context = resume_sms; 1001 sms->header.resume_context = resume_sms;
811 sms->header.load_save = load_save; 1002 sms->header.load_save = load_save;