Mercurial > repos > blastem
comparison blastem.c @ 351:2f264d2a60c2
Support for SRAM with SEGA mapper. Half-finished support for SRAM without SEGA mapper.
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 21 May 2013 22:08:59 -0700 |
parents | aff29d50afd5 |
children | 15dd6418fe67 |
comparison
equal
deleted
inserted
replaced
350:91aa2aa05e68 | 351:2f264d2a60c2 |
---|---|
810 genesis_context * gen = context->system; | 810 genesis_context * gen = context->system; |
811 ym_run(gen->ym, (context->current_cycle * MCLKS_PER_Z80) / MCLKS_PER_68K); | 811 ym_run(gen->ym, (context->current_cycle * MCLKS_PER_Z80) / MCLKS_PER_68K); |
812 return ym_read_status(gen->ym); | 812 return ym_read_status(gen->ym); |
813 } | 813 } |
814 | 814 |
815 uint16_t read_sram_w(uint32_t address, m68k_context * context) | |
816 { | |
817 genesis_context * gen = context->system; | |
818 address &= gen->save_ram_mask; | |
819 switch(gen->save_flags) | |
820 { | |
821 case RAM_FLAG_BOTH: | |
822 return gen->save_ram[address] << 8 | gen->save_ram[address+1]; | |
823 case RAM_FLAG_EVEN: | |
824 return gen->save_ram[address >> 1] << 8 | 0xFF; | |
825 case RAM_FLAG_ODD: | |
826 return gen->save_ram[address >> 1] | 0xFF00; | |
827 } | |
828 return 0xFFFF;//We should never get here | |
829 } | |
830 | |
831 uint8_t read_sram_b(uint32_t address, m68k_context * context) | |
832 { | |
833 genesis_context * gen = context->system; | |
834 address &= gen->save_ram_mask; | |
835 switch(gen->save_flags) | |
836 { | |
837 case RAM_FLAG_BOTH: | |
838 return gen->save_ram[address]; | |
839 case RAM_FLAG_EVEN: | |
840 if (address & 1) { | |
841 return 0xFF; | |
842 } else { | |
843 return gen->save_ram[address >> 1]; | |
844 } | |
845 case RAM_FLAG_ODD: | |
846 if (address & 1) { | |
847 return gen->save_ram[address >> 1]; | |
848 } else { | |
849 return 0xFF; | |
850 } | |
851 } | |
852 return 0xFF;//We should never get here | |
853 } | |
854 | |
855 m68k_context * write_sram_area_w(uint32_t address, m68k_context * context, uint16_t value) | |
856 { | |
857 genesis_context * gen = context->system; | |
858 if ((gen->bank_regs[0] & 0x3) == 1) { | |
859 address &= gen->save_ram_mask; | |
860 switch(gen->save_flags) | |
861 { | |
862 case RAM_FLAG_BOTH: | |
863 gen->save_ram[address] = value >> 8; | |
864 gen->save_ram[address+1] = value; | |
865 break; | |
866 case RAM_FLAG_EVEN: | |
867 gen->save_ram[address >> 1] = value >> 8; | |
868 break; | |
869 case RAM_FLAG_ODD: | |
870 gen->save_ram[address >> 1] = value; | |
871 break; | |
872 } | |
873 } | |
874 return context; | |
875 } | |
876 | |
877 m68k_context * write_sram_area_b(uint32_t address, m68k_context * context, uint8_t value) | |
878 { | |
879 genesis_context * gen = context->system; | |
880 if ((gen->bank_regs[0] & 0x3) == 1) { | |
881 address &= gen->save_ram_mask; | |
882 switch(gen->save_flags) | |
883 { | |
884 case RAM_FLAG_BOTH: | |
885 gen->save_ram[address] = value; | |
886 break; | |
887 case RAM_FLAG_EVEN: | |
888 if (!(address & 1)) { | |
889 gen->save_ram[address >> 1] = value; | |
890 } | |
891 break; | |
892 case RAM_FLAG_ODD: | |
893 if (address & 1) { | |
894 gen->save_ram[address >> 1] = value; | |
895 } | |
896 break; | |
897 } | |
898 } | |
899 return context; | |
900 } | |
901 | |
902 m68k_context * write_bank_reg_w(uint32_t address, m68k_context * context, uint16_t value) | |
903 { | |
904 genesis_context * gen = context->system; | |
905 address &= 0xE; | |
906 address >>= 1; | |
907 gen->bank_regs[address] = value; | |
908 if (!address) { | |
909 if (value & 1) { | |
910 context->mem_pointers[2] = NULL; | |
911 } else { | |
912 context->mem_pointers[2] = cart + 0x200000/2; | |
913 } | |
914 } | |
915 return context; | |
916 } | |
917 | |
918 m68k_context * write_bank_reg_b(uint32_t address, m68k_context * context, uint8_t value) | |
919 { | |
920 if (address & 1) { | |
921 genesis_context * gen = context->system; | |
922 address &= 0xE; | |
923 address >>= 1; | |
924 gen->bank_regs[address] = value; | |
925 if (!address) { | |
926 if (value & 1) { | |
927 context->mem_pointers[2] = NULL; | |
928 } else { | |
929 context->mem_pointers[2] = cart + 0x200000/2; | |
930 } | |
931 } | |
932 } | |
933 return context; | |
934 } | |
935 | |
815 typedef struct bp_def { | 936 typedef struct bp_def { |
816 struct bp_def * next; | 937 struct bp_def * next; |
817 uint32_t address; | 938 uint32_t address; |
818 uint32_t index; | 939 uint32_t index; |
819 } bp_def; | 940 } bp_def; |
1052 } | 1173 } |
1053 } | 1174 } |
1054 return context; | 1175 return context; |
1055 } | 1176 } |
1056 | 1177 |
1057 void init_run_cpu(genesis_context * gen, int debug, FILE * address_log) | 1178 #define ROM_END 0x1A4 |
1058 { | 1179 #define RAM_ID 0x1B0 |
1059 m68k_context context; | 1180 #define RAM_FLAGS 0x1B2 |
1060 x86_68k_options opts; | 1181 #define RAM_START 0x1B4 |
1061 gen->m68k = &context; | 1182 #define RAM_END 0x1B8 |
1062 memmap_chunk memmap[] = { | 1183 #define MAX_MAP_CHUNKS (4+7+1) |
1063 {0, 0x400000, 0xFFFFFF, 0, MMAP_READ | MMAP_WRITE, cart, | 1184 #define RAM_FLAG_MASK 0x1800 |
1185 | |
1186 const memmap_chunk static_map[] = { | |
1187 {0, 0x400000, 0xFFFFFF, 0, MMAP_READ, cart, | |
1064 NULL, NULL, NULL, NULL}, | 1188 NULL, NULL, NULL, NULL}, |
1065 {0xE00000, 0x1000000, 0xFFFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, ram, | 1189 {0xE00000, 0x1000000, 0xFFFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, ram, |
1066 NULL, NULL, NULL, NULL}, | 1190 NULL, NULL, NULL, NULL}, |
1067 {0xC00000, 0xE00000, 0x1FFFFF, 0, 0, NULL, | 1191 {0xC00000, 0xE00000, 0x1FFFFF, 0, 0, NULL, |
1068 (read_16_fun)vdp_port_read, (write_16_fun)vdp_port_write, | 1192 (read_16_fun)vdp_port_read, (write_16_fun)vdp_port_write, |
1069 (read_8_fun)vdp_port_read_b, (write_8_fun)vdp_port_write_b}, | 1193 (read_8_fun)vdp_port_read_b, (write_8_fun)vdp_port_write_b}, |
1070 {0xA00000, 0xA12000, 0x1FFFF, 0, 0, NULL, | 1194 {0xA00000, 0xA12000, 0x1FFFF, 0, 0, NULL, |
1071 (read_16_fun)io_read_w, (write_16_fun)io_write_w, | 1195 (read_16_fun)io_read_w, (write_16_fun)io_write_w, |
1072 (read_8_fun)io_read, (write_8_fun)io_write} | 1196 (read_8_fun)io_read, (write_8_fun)io_write} |
1073 }; | 1197 }; |
1074 init_x86_68k_opts(&opts, memmap, sizeof(memmap)/sizeof(memmap_chunk)); | 1198 |
1199 char * sram_filename; | |
1200 genesis_context * genesis; | |
1201 void save_sram() | |
1202 { | |
1203 FILE * f = fopen(sram_filename, "wb"); | |
1204 if (!f) { | |
1205 fprintf(stderr, "Failed to open SRAM file %s for writing\n", sram_filename); | |
1206 return; | |
1207 } | |
1208 uint32_t size = genesis->save_ram_mask+1; | |
1209 if (genesis->save_flags != RAM_FLAG_BOTH) { | |
1210 size/= 2; | |
1211 } | |
1212 fwrite(genesis->save_ram, 1, size, f); | |
1213 fclose(f); | |
1214 printf("Saved SRAM to %s\n", sram_filename); | |
1215 } | |
1216 | |
1217 void init_run_cpu(genesis_context * gen, int debug, FILE * address_log) | |
1218 { | |
1219 m68k_context context; | |
1220 x86_68k_options opts; | |
1221 gen->m68k = &context; | |
1222 memmap_chunk memmap[MAX_MAP_CHUNKS]; | |
1223 uint32_t num_chunks; | |
1224 void * initial_mapped = NULL; | |
1225 gen->save_ram = NULL; | |
1226 //TODO: Handle carts larger than 4MB | |
1227 //TODO: Handle non-standard mappers | |
1228 uint32_t size; | |
1229 if ((cart[RAM_ID/2] & 0xFF) == 'A' && (cart[RAM_ID/2] >> 8) == 'R') { | |
1230 //Cart has save RAM | |
1231 uint32_t rom_end = ((cart[ROM_END/2] << 16) | cart[ROM_END/2+1]) + 1; | |
1232 uint32_t ram_start = (cart[RAM_START/2] << 16) | cart[RAM_START/2+1]; | |
1233 uint32_t ram_end = (cart[RAM_END/2] << 16) | cart[RAM_END/2+1]; | |
1234 uint16_t ram_flags = cart[RAM_FLAGS/2]; | |
1235 gen->save_flags = ram_flags & RAM_FLAG_MASK; | |
1236 memset(memmap, 0, sizeof(memmap_chunk)*2); | |
1237 if (ram_start >= rom_end) { | |
1238 memmap[0].end = rom_end; | |
1239 memmap[0].mask = 0xFFFFFF; | |
1240 memmap[0].flags = MMAP_READ; | |
1241 memmap[0].buffer = cart; | |
1242 | |
1243 ram_start &= 0xFFFFFE; | |
1244 ram_end |= 1; | |
1245 memmap[1].start = ram_start; | |
1246 gen->save_ram_mask = memmap[1].mask = ram_end-ram_start; | |
1247 ram_end += 1; | |
1248 memmap[1].end = ram_end; | |
1249 memmap[1].flags = MMAP_READ | MMAP_WRITE; | |
1250 size = ram_end-ram_start; | |
1251 if ((ram_flags & RAM_FLAG_MASK) == RAM_FLAG_ODD) { | |
1252 memmap[1].flags |= MMAP_ONLY_ODD; | |
1253 size /= 2; | |
1254 } else if((ram_flags & RAM_FLAG_MASK) == RAM_FLAG_EVEN) { | |
1255 memmap[1].flags |= MMAP_ONLY_EVEN; | |
1256 size /= 2; | |
1257 } | |
1258 memmap[1].buffer = gen->save_ram = malloc(size); | |
1259 | |
1260 memcpy(memmap+2, static_map+1, sizeof(static_map)-sizeof(static_map[0])); | |
1261 num_chunks = sizeof(static_map)/sizeof(memmap_chunk)+1; | |
1262 } else { | |
1263 //Assume the standard Sega mapper for now | |
1264 memmap[0].end = 0x200000; | |
1265 memmap[0].mask = 0xFFFFFF; | |
1266 memmap[0].flags = MMAP_READ; | |
1267 memmap[0].buffer = cart; | |
1268 | |
1269 memmap[1].start = 0x200000; | |
1270 memmap[1].end = 0x400000; | |
1271 memmap[1].mask = 0x1FFFFF; | |
1272 ram_start &= 0xFFFFFE; | |
1273 ram_end |= 1; | |
1274 gen->save_ram_mask = ram_end-ram_start; | |
1275 memmap[1].flags = MMAP_READ | MMAP_PTR_IDX | MMAP_FUNC_NULL; | |
1276 memmap[1].ptr_index = 2; | |
1277 memmap[1].read_16 = (read_16_fun)read_sram_w;//these will only be called when mem_pointers[2] == NULL | |
1278 memmap[1].read_8 = (read_8_fun)read_sram_b; | |
1279 memmap[1].write_16 = (write_16_fun)write_sram_area_w;//these will be called all writes to the area | |
1280 memmap[1].write_8 = (write_8_fun)write_sram_area_b; | |
1281 memcpy(memmap+2, static_map+1, sizeof(static_map)-sizeof(static_map[0])); | |
1282 num_chunks = sizeof(static_map)/sizeof(memmap_chunk)+1; | |
1283 memset(memmap+num_chunks, 0, sizeof(memmap[num_chunks])); | |
1284 memmap[num_chunks].start = 0xA13000; | |
1285 memmap[num_chunks].end = 0xA13100; | |
1286 memmap[num_chunks].mask = 0xFF; | |
1287 memmap[num_chunks].write_16 = (write_16_fun)write_bank_reg_w; | |
1288 memmap[num_chunks].write_8 = (write_8_fun)write_bank_reg_b; | |
1289 num_chunks++; | |
1290 ram_end++; | |
1291 size = ram_end-ram_start; | |
1292 if ((ram_flags & RAM_FLAG_MASK) != RAM_FLAG_BOTH) { | |
1293 size /= 2; | |
1294 } | |
1295 gen->save_ram = malloc(size); | |
1296 memmap[1].buffer = initial_mapped = cart + 0x200000/2; | |
1297 } | |
1298 } else { | |
1299 memcpy(memmap, static_map, sizeof(static_map)); | |
1300 num_chunks = sizeof(static_map)/sizeof(memmap_chunk); | |
1301 } | |
1302 if (gen->save_ram) { | |
1303 memset(gen->save_ram, 0, size); | |
1304 FILE * f = fopen(sram_filename, "rb"); | |
1305 if (f) { | |
1306 uint32_t read = fread(gen->save_ram, 1, size, f); | |
1307 fclose(f); | |
1308 if (read > 0) { | |
1309 printf("Loaded SRAM from %s\n", sram_filename); | |
1310 } | |
1311 } | |
1312 atexit(save_sram); | |
1313 } | |
1314 init_x86_68k_opts(&opts, memmap, num_chunks); | |
1075 opts.address_log = address_log; | 1315 opts.address_log = address_log; |
1076 init_68k_context(&context, opts.native_code_map, &opts); | 1316 init_68k_context(&context, opts.native_code_map, &opts); |
1077 | 1317 |
1078 context.video_context = gen->vdp; | 1318 context.video_context = gen->vdp; |
1079 context.system = gen; | 1319 context.system = gen; |
1080 //cartridge ROM | 1320 //cartridge ROM |
1081 context.mem_pointers[0] = cart; | 1321 context.mem_pointers[0] = cart; |
1082 context.target_cycle = context.sync_cycle = mclks_per_frame/MCLKS_PER_68K; | 1322 context.target_cycle = context.sync_cycle = mclks_per_frame/MCLKS_PER_68K; |
1083 //work RAM | 1323 //work RAM |
1084 context.mem_pointers[1] = ram; | 1324 context.mem_pointers[1] = ram; |
1325 //save RAM/map | |
1326 context.mem_pointers[2] = initial_mapped; | |
1327 context.mem_pointers[3] = (uint16_t *)gen->save_ram; | |
1085 uint32_t address; | 1328 uint32_t address; |
1086 /*address = cart[0x68/2] << 16 | cart[0x6A/2]; | |
1087 translate_m68k_stream(address, &context); | |
1088 address = cart[0x70/2] << 16 | cart[0x72/2]; | |
1089 translate_m68k_stream(address, &context); | |
1090 address = cart[0x78/2] << 16 | cart[0x7A/2]; | |
1091 translate_m68k_stream(address, &context);*/ | |
1092 address = cart[2] << 16 | cart[3]; | 1329 address = cart[2] << 16 | cart[3]; |
1093 translate_m68k_stream(address, &context); | 1330 translate_m68k_stream(address, &context); |
1094 if (debug) { | 1331 if (debug) { |
1095 insert_breakpoint(&context, address, (uint8_t *)debugger); | 1332 insert_breakpoint(&context, address, (uint8_t *)debugger); |
1096 } | 1333 } |
1247 z_context.mem_pointers[1] = z_context.mem_pointers[2] = (uint8_t *)cart; | 1484 z_context.mem_pointers[1] = z_context.mem_pointers[2] = (uint8_t *)cart; |
1248 | 1485 |
1249 gen.z80 = &z_context; | 1486 gen.z80 = &z_context; |
1250 gen.vdp = &v_context; | 1487 gen.vdp = &v_context; |
1251 gen.ym = &y_context; | 1488 gen.ym = &y_context; |
1489 genesis = &gen; | |
1490 | |
1491 int fname_size = strlen(argv[1]); | |
1492 sram_filename = malloc(fname_size+6); | |
1493 memcpy(sram_filename, argv[1], fname_size); | |
1494 int i; | |
1495 for (i = fname_size-1; fname_size >= 0; --i) { | |
1496 if (sram_filename[i] == '.') { | |
1497 strcpy(sram_filename + i + 1, "sram"); | |
1498 break; | |
1499 } | |
1500 } | |
1501 if (i < 0) { | |
1502 strcpy(sram_filename + fname_size, ".sram"); | |
1503 } | |
1252 | 1504 |
1253 init_run_cpu(&gen, debug, address_log); | 1505 init_run_cpu(&gen, debug, address_log); |
1254 return 0; | 1506 return 0; |
1255 } | 1507 } |