Mercurial > repos > blastem
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; |