Mercurial > repos > blastem
comparison genesis.c @ 2053:3414a4423de1 segacd
Merge from default
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 15 Jan 2022 13:15:21 -0800 |
parents | 5dacaef602a7 3748a2a8a4b7 |
children | 8ee7ecbf3f21 |
comparison
equal
deleted
inserted
replaced
1692:5dacaef602a7 | 2053:3414a4423de1 |
---|---|
17 #include "debug.h" | 17 #include "debug.h" |
18 #include "gdb_remote.h" | 18 #include "gdb_remote.h" |
19 #include "saves.h" | 19 #include "saves.h" |
20 #include "bindings.h" | 20 #include "bindings.h" |
21 #include "jcart.h" | 21 #include "jcart.h" |
22 #include "config.h" | |
23 #include "event_log.h" | |
22 #define MCLKS_NTSC 53693175 | 24 #define MCLKS_NTSC 53693175 |
23 #define MCLKS_PAL 53203395 | 25 #define MCLKS_PAL 53203395 |
24 | 26 |
25 uint32_t MCLKS_PER_68K; | 27 uint32_t MCLKS_PER_68K; |
26 #define MCLKS_PER_YM 7 | 28 #define MCLKS_PER_YM 7 |
32 | 34 |
33 //TODO: Figure out the exact value for this | 35 //TODO: Figure out the exact value for this |
34 #define LINES_NTSC 262 | 36 #define LINES_NTSC 262 |
35 #define LINES_PAL 313 | 37 #define LINES_PAL 313 |
36 | 38 |
37 #define MAX_SOUND_CYCLES 100000 | 39 #ifdef IS_LIB |
38 | 40 #define MAX_SOUND_CYCLES (MCLKS_PER_YM*NUM_OPERATORS*6*4) |
39 void genesis_serialize(genesis_context *gen, serialize_buffer *buf, uint32_t m68k_pc) | 41 #else |
40 { | 42 #define MAX_SOUND_CYCLES 100000 |
41 start_section(buf, SECTION_68000); | 43 #endif |
42 m68k_serialize(gen->m68k, m68k_pc, buf); | 44 |
43 end_section(buf); | 45 #ifdef NEW_CORE |
44 | 46 #define Z80_CYCLE cycles |
45 start_section(buf, SECTION_Z80); | 47 #define Z80_OPTS opts |
46 z80_serialize(gen->z80, buf); | 48 #define z80_handle_code_write(...) |
47 end_section(buf); | 49 #else |
48 | 50 #define Z80_CYCLE current_cycle |
51 #define Z80_OPTS options | |
52 #endif | |
53 | |
54 void genesis_serialize(genesis_context *gen, serialize_buffer *buf, uint32_t m68k_pc, uint8_t all) | |
55 { | |
56 if (all) { | |
57 start_section(buf, SECTION_68000); | |
58 m68k_serialize(gen->m68k, m68k_pc, buf); | |
59 end_section(buf); | |
60 | |
61 start_section(buf, SECTION_Z80); | |
62 z80_serialize(gen->z80, buf); | |
63 end_section(buf); | |
64 } | |
65 | |
49 start_section(buf, SECTION_VDP); | 66 start_section(buf, SECTION_VDP); |
50 vdp_serialize(gen->vdp, buf); | 67 vdp_serialize(gen->vdp, buf); |
51 end_section(buf); | 68 end_section(buf); |
52 | 69 |
53 start_section(buf, SECTION_YM2612); | 70 start_section(buf, SECTION_YM2612); |
54 ym_serialize(gen->ym, buf); | 71 ym_serialize(gen->ym, buf); |
55 end_section(buf); | 72 end_section(buf); |
56 | 73 |
57 start_section(buf, SECTION_PSG); | 74 start_section(buf, SECTION_PSG); |
58 psg_serialize(gen->psg, buf); | 75 psg_serialize(gen->psg, buf); |
59 end_section(buf); | 76 end_section(buf); |
60 | 77 |
61 start_section(buf, SECTION_GEN_BUS_ARBITER); | 78 if (all) { |
62 save_int8(buf, gen->z80->reset); | 79 start_section(buf, SECTION_GEN_BUS_ARBITER); |
63 save_int8(buf, gen->z80->busreq); | 80 save_int8(buf, gen->z80->reset); |
64 save_int16(buf, gen->z80->bank_reg); | 81 save_int8(buf, gen->z80->busreq); |
65 end_section(buf); | 82 save_int16(buf, gen->z80_bank_reg); |
66 | 83 end_section(buf); |
67 start_section(buf, SECTION_SEGA_IO_1); | 84 |
68 io_serialize(gen->io.ports, buf); | 85 start_section(buf, SECTION_SEGA_IO_1); |
69 end_section(buf); | 86 io_serialize(gen->io.ports, buf); |
70 | 87 end_section(buf); |
71 start_section(buf, SECTION_SEGA_IO_2); | 88 |
72 io_serialize(gen->io.ports + 1, buf); | 89 start_section(buf, SECTION_SEGA_IO_2); |
73 end_section(buf); | 90 io_serialize(gen->io.ports + 1, buf); |
74 | 91 end_section(buf); |
75 start_section(buf, SECTION_SEGA_IO_EXT); | 92 |
76 io_serialize(gen->io.ports + 2, buf); | 93 start_section(buf, SECTION_SEGA_IO_EXT); |
77 end_section(buf); | 94 io_serialize(gen->io.ports + 2, buf); |
78 | 95 end_section(buf); |
79 start_section(buf, SECTION_MAIN_RAM); | 96 |
80 save_int8(buf, RAM_WORDS * 2 / 1024); | 97 start_section(buf, SECTION_MAIN_RAM); |
81 save_buffer16(buf, gen->work_ram, RAM_WORDS); | 98 save_int8(buf, RAM_WORDS * 2 / 1024); |
82 end_section(buf); | 99 save_buffer16(buf, gen->work_ram, RAM_WORDS); |
83 | 100 end_section(buf); |
84 start_section(buf, SECTION_SOUND_RAM); | 101 |
85 save_int8(buf, Z80_RAM_BYTES / 1024); | 102 start_section(buf, SECTION_SOUND_RAM); |
86 save_buffer8(buf, gen->zram, Z80_RAM_BYTES); | 103 save_int8(buf, Z80_RAM_BYTES / 1024); |
87 end_section(buf); | 104 save_buffer8(buf, gen->zram, Z80_RAM_BYTES); |
88 | 105 end_section(buf); |
89 cart_serialize(&gen->header, buf); | 106 |
107 if (gen->version_reg & 0xF) { | |
108 //only save TMSS info if it's present | |
109 //that will allow a state saved on a model lacking TMSS | |
110 //to be loaded on a model that has it | |
111 start_section(buf, SECTION_TMSS); | |
112 save_int8(buf, gen->tmss); | |
113 save_buffer16(buf, gen->tmss_lock, 2); | |
114 end_section(buf); | |
115 } | |
116 | |
117 cart_serialize(&gen->header, buf); | |
118 } | |
119 } | |
120 | |
121 static uint8_t *serialize(system_header *sys, size_t *size_out) | |
122 { | |
123 genesis_context *gen = (genesis_context *)sys; | |
124 uint32_t address; | |
125 if (gen->m68k->resume_pc) { | |
126 gen->m68k->target_cycle = gen->m68k->current_cycle; | |
127 gen->header.save_state = SERIALIZE_SLOT+1; | |
128 resume_68k(gen->m68k); | |
129 if (size_out) { | |
130 *size_out = gen->serialize_size; | |
131 } | |
132 return gen->serialize_tmp; | |
133 } else { | |
134 serialize_buffer state; | |
135 init_serialize(&state); | |
136 uint32_t address = read_word(4, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen, gen->m68k) << 16; | |
137 address |= read_word(6, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen, gen->m68k); | |
138 genesis_serialize(gen, &state, address, 1); | |
139 if (size_out) { | |
140 *size_out = state.size; | |
141 } | |
142 return state.data; | |
143 } | |
90 } | 144 } |
91 | 145 |
92 static void ram_deserialize(deserialize_buffer *buf, void *vgen) | 146 static void ram_deserialize(deserialize_buffer *buf, void *vgen) |
93 { | 147 { |
94 genesis_context *gen = vgen; | 148 genesis_context *gen = vgen; |
111 z80_invalidate_code_range(gen->z80, 0, 0x4000); | 165 z80_invalidate_code_range(gen->z80, 0, 0x4000); |
112 } | 166 } |
113 | 167 |
114 static void update_z80_bank_pointer(genesis_context *gen) | 168 static void update_z80_bank_pointer(genesis_context *gen) |
115 { | 169 { |
116 if (gen->z80->bank_reg < 0x140) { | 170 if (gen->z80_bank_reg < 0x140) { |
117 gen->z80->mem_pointers[1] = get_native_pointer(gen->z80->bank_reg << 15, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen); | 171 gen->z80->mem_pointers[1] = get_native_pointer(gen->z80_bank_reg << 15, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen); |
118 } else { | 172 } else { |
119 gen->z80->mem_pointers[1] = NULL; | 173 gen->z80->mem_pointers[1] = NULL; |
120 } | 174 } |
175 z80_invalidate_code_range(gen->z80, 0x8000, 0xFFFF); | |
121 } | 176 } |
122 | 177 |
123 static void bus_arbiter_deserialize(deserialize_buffer *buf, void *vgen) | 178 static void bus_arbiter_deserialize(deserialize_buffer *buf, void *vgen) |
124 { | 179 { |
125 genesis_context *gen = vgen; | 180 genesis_context *gen = vgen; |
126 gen->z80->reset = load_int8(buf); | 181 gen->z80->reset = load_int8(buf); |
127 gen->z80->busreq = load_int8(buf); | 182 gen->z80->busreq = load_int8(buf); |
128 gen->z80->bank_reg = load_int16(buf) & 0x1FF; | 183 gen->z80_bank_reg = load_int16(buf) & 0x1FF; |
184 } | |
185 | |
186 static void tmss_deserialize(deserialize_buffer *buf, void *vgen) | |
187 { | |
188 genesis_context *gen = vgen; | |
189 gen->tmss = load_int8(buf); | |
190 load_buffer16(buf, gen->tmss_lock, 2); | |
129 } | 191 } |
130 | 192 |
131 static void adjust_int_cycle(m68k_context * context, vdp_context * v_context); | 193 static void adjust_int_cycle(m68k_context * context, vdp_context * v_context); |
194 static void check_tmss_lock(genesis_context *gen); | |
195 static void toggle_tmss_rom(genesis_context *gen); | |
132 void genesis_deserialize(deserialize_buffer *buf, genesis_context *gen) | 196 void genesis_deserialize(deserialize_buffer *buf, genesis_context *gen) |
133 { | 197 { |
134 register_section_handler(buf, (section_handler){.fun = m68k_deserialize, .data = gen->m68k}, SECTION_68000); | 198 register_section_handler(buf, (section_handler){.fun = m68k_deserialize, .data = gen->m68k}, SECTION_68000); |
135 register_section_handler(buf, (section_handler){.fun = z80_deserialize, .data = gen->z80}, SECTION_Z80); | 199 register_section_handler(buf, (section_handler){.fun = z80_deserialize, .data = gen->z80}, SECTION_Z80); |
136 register_section_handler(buf, (section_handler){.fun = vdp_deserialize, .data = gen->vdp}, SECTION_VDP); | 200 register_section_handler(buf, (section_handler){.fun = vdp_deserialize, .data = gen->vdp}, SECTION_VDP); |
141 register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = gen->io.ports + 1}, SECTION_SEGA_IO_2); | 205 register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = gen->io.ports + 1}, SECTION_SEGA_IO_2); |
142 register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = gen->io.ports + 2}, SECTION_SEGA_IO_EXT); | 206 register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = gen->io.ports + 2}, SECTION_SEGA_IO_EXT); |
143 register_section_handler(buf, (section_handler){.fun = ram_deserialize, .data = gen}, SECTION_MAIN_RAM); | 207 register_section_handler(buf, (section_handler){.fun = ram_deserialize, .data = gen}, SECTION_MAIN_RAM); |
144 register_section_handler(buf, (section_handler){.fun = zram_deserialize, .data = gen}, SECTION_SOUND_RAM); | 208 register_section_handler(buf, (section_handler){.fun = zram_deserialize, .data = gen}, SECTION_SOUND_RAM); |
145 register_section_handler(buf, (section_handler){.fun = cart_deserialize, .data = gen}, SECTION_MAPPER); | 209 register_section_handler(buf, (section_handler){.fun = cart_deserialize, .data = gen}, SECTION_MAPPER); |
210 register_section_handler(buf, (section_handler){.fun = tmss_deserialize, .data = gen}, SECTION_TMSS); | |
211 uint8_t tmss_old = gen->tmss; | |
212 gen->tmss = 0xFF; | |
146 while (buf->cur_pos < buf->size) | 213 while (buf->cur_pos < buf->size) |
147 { | 214 { |
148 load_section(buf); | 215 load_section(buf); |
149 } | 216 } |
217 if (gen->version_reg & 0xF) { | |
218 if (gen->tmss == 0xFF) { | |
219 //state lacked a TMSS section, assume that the game ROM is mapped in | |
220 //and that the VDP is unlocked | |
221 gen->tmss_lock[0] = 0x5345; | |
222 gen->tmss_lock[1] = 0x4741; | |
223 gen->tmss = 1; | |
224 } | |
225 if (gen->tmss != tmss_old) { | |
226 toggle_tmss_rom(gen); | |
227 } | |
228 check_tmss_lock(gen); | |
229 } | |
150 update_z80_bank_pointer(gen); | 230 update_z80_bank_pointer(gen); |
151 adjust_int_cycle(gen->m68k, gen->vdp); | 231 adjust_int_cycle(gen->m68k, gen->vdp); |
232 free(buf->handlers); | |
233 buf->handlers = NULL; | |
234 } | |
235 | |
236 #include "m68k_internal.h" //needed for get_native_address_trans, should be eliminated once handling of PC is cleaned up | |
237 static void deserialize(system_header *sys, uint8_t *data, size_t size) | |
238 { | |
239 genesis_context *gen = (genesis_context *)sys; | |
240 deserialize_buffer buffer; | |
241 init_deserialize(&buffer, data, size); | |
242 genesis_deserialize(&buffer, gen); | |
243 //HACK: Fix this once PC/IR is represented in a better way in 68K core | |
244 gen->m68k->resume_pc = get_native_address_trans(gen->m68k, gen->m68k->last_prefetch_address); | |
152 } | 245 } |
153 | 246 |
154 uint16_t read_dma_value(uint32_t address) | 247 uint16_t read_dma_value(uint32_t address) |
155 { | 248 { |
156 genesis_context *genesis = (genesis_context *)current_system; | 249 genesis_context *genesis = (genesis_context *)current_system; |
157 //TODO: Figure out what happens when you try to DMA from weird adresses like IO or banked Z80 area | 250 //TODO: Figure out what happens when you try to DMA from weird adresses like IO or banked Z80 area |
158 if ((address >= 0xA00000 && address < 0xB00000) || (address >= 0xC00000 && address <= 0xE00000)) { | 251 if ((address >= 0xA00000 && address < 0xB00000) || (address >= 0xC00000 && address <= 0xE00000)) { |
159 return 0; | 252 return 0; |
160 } | 253 } |
161 | 254 |
162 //addresses here are word addresses (i.e. bit 0 corresponds to A1), so no need to do multiply by 2 | 255 //addresses here are word addresses (i.e. bit 0 corresponds to A1), so no need to do multiply by 2 |
163 return read_word(address * 2, (void **)genesis->m68k->mem_pointers, &genesis->m68k->options->gen, genesis->m68k); | 256 return read_word(address * 2, (void **)genesis->m68k->mem_pointers, &genesis->m68k->options->gen, genesis->m68k); |
164 } | 257 } |
165 | 258 |
166 static uint16_t get_open_bus_value(system_header *system) | 259 static uint16_t get_open_bus_value(system_header *system) |
175 genesis_context *gen = context->system; | 268 genesis_context *gen = context->system; |
176 if (context->sync_cycle - context->current_cycle > gen->max_cycles) { | 269 if (context->sync_cycle - context->current_cycle > gen->max_cycles) { |
177 context->sync_cycle = context->current_cycle + gen->max_cycles; | 270 context->sync_cycle = context->current_cycle + gen->max_cycles; |
178 } | 271 } |
179 context->int_cycle = CYCLE_NEVER; | 272 context->int_cycle = CYCLE_NEVER; |
180 if ((context->status & 0x7) < 6) { | 273 uint8_t mask = context->status & 0x7; |
274 if (mask < 6) { | |
181 uint32_t next_vint = vdp_next_vint(v_context); | 275 uint32_t next_vint = vdp_next_vint(v_context); |
182 if (next_vint != CYCLE_NEVER) { | 276 if (next_vint != CYCLE_NEVER) { |
183 context->int_cycle = next_vint; | 277 context->int_cycle = next_vint; |
184 context->int_num = 6; | 278 context->int_num = 6; |
185 } | 279 } |
186 if ((context->status & 0x7) < 4) { | 280 if (mask < 4) { |
187 uint32_t next_hint = vdp_next_hint(v_context); | 281 uint32_t next_hint = vdp_next_hint(v_context); |
188 if (next_hint != CYCLE_NEVER) { | 282 if (next_hint != CYCLE_NEVER) { |
189 next_hint = next_hint < context->current_cycle ? context->current_cycle : next_hint; | 283 next_hint = next_hint < context->current_cycle ? context->current_cycle : next_hint; |
190 if (next_hint < context->int_cycle) { | 284 if (next_hint < context->int_cycle) { |
191 context->int_cycle = next_hint; | 285 context->int_cycle = next_hint; |
192 context->int_num = 4; | 286 context->int_num = 4; |
193 | 287 |
194 } | 288 } |
195 } | 289 } |
290 if (mask < 2 && (v_context->regs[REG_MODE_3] & BIT_EINT_EN)) { | |
291 uint32_t next_eint_port0 = io_next_interrupt(gen->io.ports, context->current_cycle); | |
292 uint32_t next_eint_port1 = io_next_interrupt(gen->io.ports + 1, context->current_cycle); | |
293 uint32_t next_eint_port2 = io_next_interrupt(gen->io.ports + 2, context->current_cycle); | |
294 uint32_t next_eint = next_eint_port0 < next_eint_port1 | |
295 ? (next_eint_port0 < next_eint_port2 ? next_eint_port0 : next_eint_port2) | |
296 : (next_eint_port1 < next_eint_port2 ? next_eint_port1 : next_eint_port2); | |
297 if (next_eint != CYCLE_NEVER) { | |
298 next_eint = next_eint < context->current_cycle ? context->current_cycle : next_eint; | |
299 if (next_eint < context->int_cycle) { | |
300 context->int_cycle = next_eint; | |
301 context->int_num = 2; | |
302 } | |
303 } | |
304 } | |
196 } | 305 } |
197 } | 306 } |
198 if (context->int_cycle > context->current_cycle && context->int_pending == INT_PENDING_SR_CHANGE) { | 307 if (context->int_cycle > context->current_cycle && context->int_pending == INT_PENDING_SR_CHANGE) { |
199 context->int_pending = INT_PENDING_NONE; | 308 context->int_pending = INT_PENDING_NONE; |
200 } | 309 } |
201 /*if (context->int_cycle != old_int_cycle) { | 310 /*if (context->int_cycle != old_int_cycle) { |
202 printf("int cycle changed to: %d, level: %d @ %d(%d), frame: %d, vcounter: %d, hslot: %d, mask: %d, hint_counter: %d\n", context->int_cycle, context->int_num, v_context->cycles, context->current_cycle, v_context->frame, v_context->vcounter, v_context->hslot, context->status & 0x7, v_context->hint_counter); | 311 printf("int cycle changed to: %d, level: %d @ %d(%d), frame: %d, vcounter: %d, hslot: %d, mask: %d, hint_counter: %d\n", context->int_cycle, context->int_num, v_context->cycles, context->current_cycle, v_context->frame, v_context->vcounter, v_context->hslot, context->status & 0x7, v_context->hint_counter); |
203 old_int_cycle = context->int_cycle; | 312 old_int_cycle = context->int_cycle; |
204 }*/ | 313 }*/ |
205 | 314 |
206 if (context->status & M68K_STATUS_TRACE || context->trace_pending) { | 315 if (context->status & M68K_STATUS_TRACE || context->trace_pending) { |
207 context->target_cycle = context->current_cycle; | 316 context->target_cycle = context->current_cycle; |
208 return; | 317 return; |
209 } | 318 } |
210 | 319 |
211 context->target_cycle = context->int_cycle < context->sync_cycle ? context->int_cycle : context->sync_cycle; | 320 context->target_cycle = context->int_cycle < context->sync_cycle ? context->int_cycle : context->sync_cycle; |
212 if (context->should_return) { | 321 if (context->should_return || gen->header.enter_debugger) { |
213 context->target_cycle = context->current_cycle; | 322 context->target_cycle = context->current_cycle; |
214 } else if (context->target_cycle < context->current_cycle) { | 323 } else if (context->target_cycle < context->current_cycle) { |
215 //Changes to SR can result in an interrupt cycle that's in the past | 324 //Changes to SR can result in an interrupt cycle that's in the past |
216 //This can cause issues with the implementation of STOP though | 325 //This can cause issues with the implementation of STOP though |
217 context->target_cycle = context->current_cycle; | 326 context->target_cycle = context->current_cycle; |
225 } else if ((context->target_cycle - context->current_cycle) > gen->int_latency_prev2) { | 334 } else if ((context->target_cycle - context->current_cycle) > gen->int_latency_prev2) { |
226 context->target_cycle = context->sync_cycle = context->int_cycle - gen->int_latency_prev2; | 335 context->target_cycle = context->sync_cycle = context->int_cycle - gen->int_latency_prev2; |
227 } else { | 336 } else { |
228 context->target_cycle = context->sync_cycle = context->current_cycle; | 337 context->target_cycle = context->sync_cycle = context->current_cycle; |
229 } | 338 } |
230 | 339 |
231 } | 340 } |
232 /*printf("Cyc: %d, Trgt: %d, Int Cyc: %d, Int: %d, Mask: %X, V: %d, H: %d, HICount: %d, HReg: %d, Line: %d\n", | 341 /*printf("Cyc: %d, Trgt: %d, Int Cyc: %d, Int: %d, Mask: %X, V: %d, H: %d, HICount: %d, HReg: %d, Line: %d\n", |
233 context->current_cycle, context->target_cycle, context->int_cycle, context->int_num, (context->status & 0x7), | 342 context->current_cycle, context->target_cycle, context->int_cycle, context->int_num, (context->status & 0x7), |
234 v_context->regs[REG_MODE_2] & 0x20, v_context->regs[REG_MODE_1] & 0x10, v_context->hint_counter, v_context->regs[REG_HINT], v_context->cycles / MCLKS_LINE);*/ | 343 v_context->regs[REG_MODE_2] & 0x20, v_context->regs[REG_MODE_1] & 0x10, v_context->hint_counter, v_context->regs[REG_HINT], v_context->cycles / MCLKS_LINE);*/ |
235 } | 344 } |
244 #endif | 353 #endif |
245 | 354 |
246 static void z80_next_int_pulse(z80_context * z_context) | 355 static void z80_next_int_pulse(z80_context * z_context) |
247 { | 356 { |
248 genesis_context * gen = z_context->system; | 357 genesis_context * gen = z_context->system; |
358 #ifdef NEW_CORE | |
359 z_context->int_cycle = vdp_next_vint_z80(gen->vdp); | |
360 z_context->int_end_cycle = z_context->int_cycle + Z80_INT_PULSE_MCLKS; | |
361 z_context->int_value = 0xFF; | |
362 z80_sync_cycle(z_context, z_context->sync_cycle); | |
363 #else | |
249 z_context->int_pulse_start = vdp_next_vint_z80(gen->vdp); | 364 z_context->int_pulse_start = vdp_next_vint_z80(gen->vdp); |
250 z_context->int_pulse_end = z_context->int_pulse_start + Z80_INT_PULSE_MCLKS; | 365 z_context->int_pulse_end = z_context->int_pulse_start + Z80_INT_PULSE_MCLKS; |
251 z_context->im2_vector = 0xFF; | 366 z_context->im2_vector = 0xFF; |
367 #endif | |
252 } | 368 } |
253 | 369 |
254 static void sync_z80(z80_context * z_context, uint32_t mclks) | 370 static void sync_z80(z80_context * z_context, uint32_t mclks) |
255 { | 371 { |
256 #ifndef NO_Z80 | 372 #ifndef NO_Z80 |
257 if (z80_enabled) { | 373 if (z80_enabled) { |
374 #ifdef NEW_CORE | |
375 if (z_context->int_cycle == 0xFFFFFFFFU) { | |
376 z80_next_int_pulse(z_context); | |
377 } | |
378 #endif | |
258 z80_run(z_context, mclks); | 379 z80_run(z_context, mclks); |
259 } else | 380 } else |
260 #endif | 381 #endif |
261 { | 382 { |
262 z_context->current_cycle = mclks; | 383 z_context->Z80_CYCLE = mclks; |
263 } | 384 } |
264 } | 385 } |
265 | 386 |
266 static void sync_sound(genesis_context * gen, uint32_t target) | 387 static void sync_sound(genesis_context * gen, uint32_t target) |
267 { | 388 { |
276 psg_run(gen->psg, target); | 397 psg_run(gen->psg, target); |
277 ym_run(gen->ym, target); | 398 ym_run(gen->ym, target); |
278 | 399 |
279 //printf("Target: %d, YM bufferpos: %d, PSG bufferpos: %d\n", target, gen->ym->buffer_pos, gen->psg->buffer_pos * 2); | 400 //printf("Target: %d, YM bufferpos: %d, PSG bufferpos: %d\n", target, gen->ym->buffer_pos, gen->psg->buffer_pos * 2); |
280 } | 401 } |
281 | |
282 //TODO: move this inside the system context | |
283 static uint32_t last_frame_num; | |
284 | 402 |
285 //My refresh emulation isn't currently good enough and causes more problems than it solves | 403 //My refresh emulation isn't currently good enough and causes more problems than it solves |
286 #define REFRESH_EMULATION | 404 #define REFRESH_EMULATION |
287 #ifdef REFRESH_EMULATION | 405 #ifdef REFRESH_EMULATION |
288 #define REFRESH_INTERVAL 128 | 406 #define REFRESH_INTERVAL 128 |
311 | 429 |
312 uint32_t mclks = context->current_cycle; | 430 uint32_t mclks = context->current_cycle; |
313 sync_z80(z_context, mclks); | 431 sync_z80(z_context, mclks); |
314 sync_sound(gen, mclks); | 432 sync_sound(gen, mclks); |
315 vdp_run_context(v_context, mclks); | 433 vdp_run_context(v_context, mclks); |
434 io_run(gen->io.ports, mclks); | |
435 io_run(gen->io.ports + 1, mclks); | |
436 io_run(gen->io.ports + 2, mclks); | |
316 if (mclks >= gen->reset_cycle) { | 437 if (mclks >= gen->reset_cycle) { |
317 gen->reset_requested = 1; | 438 gen->reset_requested = 1; |
318 context->should_return = 1; | 439 context->should_return = 1; |
319 gen->reset_cycle = CYCLE_NEVER; | 440 gen->reset_cycle = CYCLE_NEVER; |
320 } | 441 } |
321 if (v_context->frame != last_frame_num) { | 442 if (v_context->frame != gen->last_frame) { |
322 //printf("reached frame end %d | MCLK Cycles: %d, Target: %d, VDP cycles: %d, vcounter: %d, hslot: %d\n", last_frame_num, mclks, gen->frame_end, v_context->cycles, v_context->vcounter, v_context->hslot); | 443 //printf("reached frame end %d | MCLK Cycles: %d, Target: %d, VDP cycles: %d, vcounter: %d, hslot: %d\n", gen->last_frame, mclks, gen->frame_end, v_context->cycles, v_context->vcounter, v_context->hslot); |
323 last_frame_num = v_context->frame; | 444 gen->last_frame = v_context->frame; |
445 event_flush(mclks); | |
446 gen->last_flush_cycle = mclks; | |
324 | 447 |
325 if(exit_after){ | 448 if(exit_after){ |
326 --exit_after; | 449 --exit_after; |
327 if (!exit_after) { | 450 if (!exit_after) { |
328 exit(0); | 451 exit(0); |
337 if (gen->mapper_type == MAPPER_JCART) { | 460 if (gen->mapper_type == MAPPER_JCART) { |
338 jcart_adjust_cycles(gen, deduction); | 461 jcart_adjust_cycles(gen, deduction); |
339 } | 462 } |
340 context->current_cycle -= deduction; | 463 context->current_cycle -= deduction; |
341 z80_adjust_cycles(z_context, deduction); | 464 z80_adjust_cycles(z_context, deduction); |
342 gen->ym->current_cycle -= deduction; | 465 ym_adjust_cycles(gen->ym, deduction); |
466 if (gen->ym->vgm) { | |
467 vgm_adjust_cycles(gen->ym->vgm, deduction); | |
468 } | |
343 gen->psg->cycles -= deduction; | 469 gen->psg->cycles -= deduction; |
344 if (gen->ym->write_cycle != CYCLE_NEVER) { | |
345 gen->ym->write_cycle = gen->ym->write_cycle >= deduction ? gen->ym->write_cycle - deduction : 0; | |
346 } | |
347 if (gen->reset_cycle != CYCLE_NEVER) { | 470 if (gen->reset_cycle != CYCLE_NEVER) { |
348 gen->reset_cycle -= deduction; | 471 gen->reset_cycle -= deduction; |
349 } | 472 } |
350 } | 473 event_cycle_adjust(mclks, deduction); |
474 gen->last_flush_cycle -= deduction; | |
475 } | |
476 } else if (mclks - gen->last_flush_cycle > gen->soft_flush_cycles) { | |
477 event_soft_flush(mclks); | |
478 gen->last_flush_cycle = mclks; | |
351 } | 479 } |
352 gen->frame_end = vdp_cycles_to_frame_end(v_context); | 480 gen->frame_end = vdp_cycles_to_frame_end(v_context); |
353 context->sync_cycle = gen->frame_end; | 481 context->sync_cycle = gen->frame_end; |
354 //printf("Set sync cycle to: %d @ %d, vcounter: %d, hslot: %d\n", context->sync_cycle, context->current_cycle, v_context->vcounter, v_context->hslot); | 482 //printf("Set sync cycle to: %d @ %d, vcounter: %d, hslot: %d\n", context->sync_cycle, context->current_cycle, v_context->vcounter, v_context->hslot); |
355 if (context->int_ack) { | 483 if (context->int_ack) { |
365 context->target_cycle = gen->reset_cycle; | 493 context->target_cycle = gen->reset_cycle; |
366 } | 494 } |
367 if (address) { | 495 if (address) { |
368 if (gen->header.enter_debugger) { | 496 if (gen->header.enter_debugger) { |
369 gen->header.enter_debugger = 0; | 497 gen->header.enter_debugger = 0; |
370 debugger(context, address); | 498 if (gen->header.debugger_type == DEBUGGER_NATIVE) { |
371 } | 499 debugger(context, address); |
500 } else { | |
501 gdb_debug_enter(context, address); | |
502 } | |
503 } | |
504 #ifdef NEW_CORE | |
505 if (gen->header.save_state) { | |
506 #else | |
372 if (gen->header.save_state && (z_context->pc || !z_context->native_pc || z_context->reset || !z_context->busreq)) { | 507 if (gen->header.save_state && (z_context->pc || !z_context->native_pc || z_context->reset || !z_context->busreq)) { |
508 #endif | |
373 uint8_t slot = gen->header.save_state - 1; | 509 uint8_t slot = gen->header.save_state - 1; |
374 gen->header.save_state = 0; | 510 gen->header.save_state = 0; |
511 #ifndef NEW_CORE | |
375 if (z_context->native_pc && !z_context->reset) { | 512 if (z_context->native_pc && !z_context->reset) { |
376 //advance Z80 core to the start of an instruction | 513 //advance Z80 core to the start of an instruction |
377 while (!z_context->pc) | 514 while (!z_context->pc) |
378 { | 515 { |
379 sync_z80(z_context, z_context->current_cycle + MCLKS_PER_Z80); | 516 sync_z80(z_context, z_context->current_cycle + MCLKS_PER_Z80); |
380 } | 517 } |
381 } | 518 } |
382 char *save_path = get_slot_name(&gen->header, slot, use_native_states ? "state" : "gst"); | 519 #endif |
383 if (use_native_states) { | 520 char *save_path = slot >= SERIALIZE_SLOT ? NULL : get_slot_name(&gen->header, slot, use_native_states ? "state" : "gst"); |
521 if (use_native_states || slot >= SERIALIZE_SLOT) { | |
384 serialize_buffer state; | 522 serialize_buffer state; |
385 init_serialize(&state); | 523 init_serialize(&state); |
386 genesis_serialize(gen, &state, address); | 524 genesis_serialize(gen, &state, address, slot != EVENTLOG_SLOT); |
387 save_to_file(&state, save_path); | 525 if (slot == SERIALIZE_SLOT) { |
388 free(state.data); | 526 gen->serialize_tmp = state.data; |
527 gen->serialize_size = state.size; | |
528 context->sync_cycle = context->current_cycle; | |
529 context->should_return = 1; | |
530 } else if (slot == EVENTLOG_SLOT) { | |
531 event_state(context->current_cycle, &state); | |
532 } else { | |
533 save_to_file(&state, save_path); | |
534 free(state.data); | |
535 } | |
389 } else { | 536 } else { |
390 save_gst(gen, save_path, address); | 537 save_gst(gen, save_path, address); |
391 } | 538 } |
392 printf("Saved state to %s\n", save_path); | 539 if (slot != SERIALIZE_SLOT) { |
540 debug_message("Saved state to %s\n", save_path); | |
541 } | |
393 free(save_path); | 542 free(save_path); |
394 } else if(gen->header.save_state) { | 543 } else if(gen->header.save_state) { |
395 context->sync_cycle = context->current_cycle + 1; | 544 context->sync_cycle = context->current_cycle + 1; |
396 } | 545 } |
397 } | 546 } |
403 | 552 |
404 static m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_t value) | 553 static m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_t value) |
405 { | 554 { |
406 if (vdp_port & 0x2700E0) { | 555 if (vdp_port & 0x2700E0) { |
407 fatal_error("machine freeze due to write to address %X\n", 0xC00000 | vdp_port); | 556 fatal_error("machine freeze due to write to address %X\n", 0xC00000 | vdp_port); |
557 } | |
558 genesis_context * gen = context->system; | |
559 if (!gen->vdp_unlocked) { | |
560 fatal_error("machine freeze due to VDP write to %X without TMSS unlock\n", 0xC00000 | vdp_port); | |
408 } | 561 } |
409 vdp_port &= 0x1F; | 562 vdp_port &= 0x1F; |
410 //printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle); | 563 //printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle); |
411 #ifdef REFRESH_EMULATION | 564 #ifdef REFRESH_EMULATION |
412 //do refresh check here so we can avoid adding a penalty for a refresh that happens during a VDP access | 565 //do refresh check here so we can avoid adding a penalty for a refresh that happens during a VDP access |
414 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL)); | 567 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL)); |
415 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); | 568 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); |
416 last_sync_cycle = context->current_cycle; | 569 last_sync_cycle = context->current_cycle; |
417 #endif | 570 #endif |
418 sync_components(context, 0); | 571 sync_components(context, 0); |
419 genesis_context * gen = context->system; | |
420 vdp_context *v_context = gen->vdp; | 572 vdp_context *v_context = gen->vdp; |
421 uint32_t before_cycle = v_context->cycles; | 573 uint32_t before_cycle = v_context->cycles; |
422 if (vdp_port < 0x10) { | 574 if (vdp_port < 0x10) { |
423 int blocked; | 575 int blocked; |
424 if (vdp_port < 4) { | 576 if (vdp_port < 4) { |
457 gen->bus_busy = 1; | 609 gen->bus_busy = 1; |
458 sync_components(context, 0); | 610 sync_components(context, 0); |
459 gen->bus_busy = 0; | 611 gen->bus_busy = 0; |
460 } | 612 } |
461 } | 613 } |
462 | 614 |
463 if (blocked < 0) { | 615 if (blocked < 0) { |
464 blocked = vdp_control_port_write(v_context, value); | 616 blocked = vdp_control_port_write(v_context, value); |
465 } else { | 617 } else { |
466 blocked = 0; | 618 blocked = 0; |
467 } | 619 } |
491 psg_write(gen->psg, value); | 643 psg_write(gen->psg, value); |
492 } else { | 644 } else { |
493 vdp_test_port_write(gen->vdp, value); | 645 vdp_test_port_write(gen->vdp, value); |
494 } | 646 } |
495 #ifdef REFRESH_EMULATION | 647 #ifdef REFRESH_EMULATION |
496 last_sync_cycle -= 4; | 648 last_sync_cycle -= 4 * MCLKS_PER_68K; |
497 //refresh may have happened while we were waiting on the VDP, | 649 //refresh may have happened while we were waiting on the VDP, |
498 //so advance refresh_counter but don't add any delays | 650 //so advance refresh_counter but don't add any delays |
499 if (vdp_port >= 4 && vdp_port < 8 && v_context->cycles != before_cycle) { | 651 if (vdp_port >= 4 && vdp_port < 8 && v_context->cycles != before_cycle) { |
500 refresh_counter = 0; | 652 refresh_counter = 0; |
501 } else { | 653 } else { |
521 fatal_error("machine freeze due to write to Z80 address %X\n", 0x7F00 | vdp_port); | 673 fatal_error("machine freeze due to write to Z80 address %X\n", 0x7F00 | vdp_port); |
522 } | 674 } |
523 if (vdp_port < 0x10) { | 675 if (vdp_port < 0x10) { |
524 //These probably won't currently interact well with the 68K accessing the VDP | 676 //These probably won't currently interact well with the 68K accessing the VDP |
525 if (vdp_port < 4) { | 677 if (vdp_port < 4) { |
526 vdp_run_context(gen->vdp, context->current_cycle); | 678 vdp_run_context(gen->vdp, context->Z80_CYCLE); |
527 vdp_data_port_write(gen->vdp, value << 8 | value); | 679 vdp_data_port_write(gen->vdp, value << 8 | value); |
528 } else if (vdp_port < 8) { | 680 } else if (vdp_port < 8) { |
529 vdp_run_context_full(gen->vdp, context->current_cycle); | 681 vdp_run_context_full(gen->vdp, context->Z80_CYCLE); |
530 vdp_control_port_write(gen->vdp, value << 8 | value); | 682 vdp_control_port_write(gen->vdp, value << 8 | value); |
531 } else { | 683 } else { |
532 fatal_error("Illegal write to HV Counter port %X\n", vdp_port); | 684 fatal_error("Illegal write to HV Counter port %X\n", vdp_port); |
533 } | 685 } |
534 } else if (vdp_port < 0x18) { | 686 } else if (vdp_port < 0x18) { |
535 sync_sound(gen, context->current_cycle); | 687 sync_sound(gen, context->Z80_CYCLE); |
536 psg_write(gen->psg, value); | 688 psg_write(gen->psg, value); |
537 } else { | 689 } else { |
538 vdp_test_port_write(gen->vdp, value); | 690 vdp_test_port_write(gen->vdp, value); |
539 } | 691 } |
540 return context; | 692 return context; |
542 | 694 |
543 static uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context) | 695 static uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context) |
544 { | 696 { |
545 if (vdp_port & 0x2700E0) { | 697 if (vdp_port & 0x2700E0) { |
546 fatal_error("machine freeze due to read from address %X\n", 0xC00000 | vdp_port); | 698 fatal_error("machine freeze due to read from address %X\n", 0xC00000 | vdp_port); |
699 } | |
700 genesis_context *gen = context->system; | |
701 if (!gen->vdp_unlocked) { | |
702 fatal_error("machine freeze due to VDP read from %X without TMSS unlock\n", 0xC00000 | vdp_port); | |
547 } | 703 } |
548 vdp_port &= 0x1F; | 704 vdp_port &= 0x1F; |
549 uint16_t value; | 705 uint16_t value; |
550 #ifdef REFRESH_EMULATION | 706 #ifdef REFRESH_EMULATION |
551 //do refresh check here so we can avoid adding a penalty for a refresh that happens during a VDP access | 707 //do refresh check here so we can avoid adding a penalty for a refresh that happens during a VDP access |
553 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL)); | 709 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL)); |
554 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); | 710 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); |
555 last_sync_cycle = context->current_cycle; | 711 last_sync_cycle = context->current_cycle; |
556 #endif | 712 #endif |
557 sync_components(context, 0); | 713 sync_components(context, 0); |
558 genesis_context *gen = context->system; | |
559 vdp_context * v_context = gen->vdp; | 714 vdp_context * v_context = gen->vdp; |
560 uint32_t before_cycle = v_context->cycles; | 715 uint32_t before_cycle = v_context->cycles; |
561 if (vdp_port < 0x10) { | 716 if (vdp_port < 0x10) { |
562 if (vdp_port < 4) { | 717 if (vdp_port < 4) { |
563 value = vdp_data_port_read(v_context); | 718 value = vdp_data_port_read(v_context); |
568 //printf("HV Counter: %X at cycle %d\n", value, v_context->cycles); | 723 //printf("HV Counter: %X at cycle %d\n", value, v_context->cycles); |
569 } | 724 } |
570 } else if (vdp_port < 0x18){ | 725 } else if (vdp_port < 0x18){ |
571 fatal_error("Illegal read from PSG port %X\n", vdp_port); | 726 fatal_error("Illegal read from PSG port %X\n", vdp_port); |
572 } else { | 727 } else { |
573 value = vdp_test_port_read(v_context); | 728 value = get_open_bus_value(&gen->header); |
574 } | 729 } |
575 if (v_context->cycles != before_cycle) { | 730 if (v_context->cycles != before_cycle) { |
576 //printf("68K paused for %d (%d) cycles at cycle %d (%d) for read\n", v_context->cycles - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle); | 731 //printf("68K paused for %d (%d) cycles at cycle %d (%d) for read\n", v_context->cycles - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle); |
577 context->current_cycle = v_context->cycles; | 732 context->current_cycle = v_context->cycles; |
578 //Lock the Z80 out of the bus until the VDP access is complete | 733 //Lock the Z80 out of the bus until the VDP access is complete |
580 gen->bus_busy = 1; | 735 gen->bus_busy = 1; |
581 sync_z80(gen->z80, v_context->cycles); | 736 sync_z80(gen->z80, v_context->cycles); |
582 gen->bus_busy = 0; | 737 gen->bus_busy = 0; |
583 } | 738 } |
584 #ifdef REFRESH_EMULATION | 739 #ifdef REFRESH_EMULATION |
585 last_sync_cycle -= 4; | 740 last_sync_cycle -= 4 * MCLKS_PER_68K; |
586 //refresh may have happened while we were waiting on the VDP, | 741 //refresh may have happened while we were waiting on the VDP, |
587 //so advance refresh_counter but don't add any delays | 742 //so advance refresh_counter but don't add any delays |
588 refresh_counter += (context->current_cycle - last_sync_cycle); | 743 refresh_counter += (context->current_cycle - last_sync_cycle); |
589 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); | 744 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); |
590 last_sync_cycle = context->current_cycle; | 745 last_sync_cycle = context->current_cycle; |
609 fatal_error("machine freeze due to read from Z80 address %X\n", 0x7F00 | vdp_port); | 764 fatal_error("machine freeze due to read from Z80 address %X\n", 0x7F00 | vdp_port); |
610 } | 765 } |
611 genesis_context * gen = context->system; | 766 genesis_context * gen = context->system; |
612 //VDP access goes over the 68K bus like a bank area access | 767 //VDP access goes over the 68K bus like a bank area access |
613 //typical delay from bus arbitration | 768 //typical delay from bus arbitration |
614 context->current_cycle += 3 * MCLKS_PER_Z80; | 769 context->Z80_CYCLE += 3 * MCLKS_PER_Z80; |
615 //TODO: add cycle for an access right after a previous one | 770 //TODO: add cycle for an access right after a previous one |
616 //TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high | 771 //TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high |
617 // Needs a new logic analyzer capture to get the actual delay on the 68K side | 772 // Needs a new logic analyzer capture to get the actual delay on the 68K side |
618 gen->m68k->current_cycle += 8 * MCLKS_PER_68K; | 773 gen->m68k->current_cycle += 8 * MCLKS_PER_68K; |
619 | 774 |
620 | 775 |
621 vdp_port &= 0x1F; | 776 vdp_port &= 0x1F; |
622 uint16_t ret; | 777 uint16_t ret; |
623 if (vdp_port < 0x10) { | 778 if (vdp_port < 0x10) { |
624 //These probably won't currently interact well with the 68K accessing the VDP | 779 //These probably won't currently interact well with the 68K accessing the VDP |
625 vdp_run_context(gen->vdp, context->current_cycle); | 780 vdp_run_context(gen->vdp, context->Z80_CYCLE); |
626 if (vdp_port < 4) { | 781 if (vdp_port < 4) { |
627 ret = vdp_data_port_read(gen->vdp); | 782 ret = vdp_data_port_read(gen->vdp); |
628 } else if (vdp_port < 8) { | 783 } else if (vdp_port < 8) { |
629 ret = vdp_control_port_read(gen->vdp); | 784 ret = vdp_control_port_read(gen->vdp); |
630 } else { | 785 } else { |
641 static uint32_t zram_counter = 0; | 796 static uint32_t zram_counter = 0; |
642 | 797 |
643 static m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value) | 798 static m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value) |
644 { | 799 { |
645 genesis_context * gen = context->system; | 800 genesis_context * gen = context->system; |
801 #ifdef REFRESH_EMULATION | |
802 //do refresh check here so we can avoid adding a penalty for a refresh that happens during an IO area access | |
803 refresh_counter += context->current_cycle - 4*MCLKS_PER_68K - last_sync_cycle; | |
804 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL)); | |
805 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); | |
806 last_sync_cycle = context->current_cycle - 4*MCLKS_PER_68K; | |
807 #endif | |
646 if (location < 0x10000) { | 808 if (location < 0x10000) { |
647 //Access to Z80 memory incurs a one 68K cycle wait state | 809 //Access to Z80 memory incurs a one 68K cycle wait state |
648 context->current_cycle += MCLKS_PER_68K; | 810 context->current_cycle += MCLKS_PER_68K; |
649 if (!z80_enabled || z80_get_busack(gen->z80, context->current_cycle)) { | 811 if (!z80_enabled || z80_get_busack(gen->z80, context->current_cycle)) { |
650 location &= 0x7FFF; | 812 location &= 0x7FFF; |
661 ym_address_write_part2(gen->ym, value); | 823 ym_address_write_part2(gen->ym, value); |
662 } else { | 824 } else { |
663 ym_address_write_part1(gen->ym, value); | 825 ym_address_write_part1(gen->ym, value); |
664 } | 826 } |
665 } else if (location == 0x6000) { | 827 } else if (location == 0x6000) { |
666 gen->z80->bank_reg = (gen->z80->bank_reg >> 1 | value << 8) & 0x1FF; | 828 gen->z80_bank_reg = (gen->z80_bank_reg >> 1 | value << 8) & 0x1FF; |
667 if (gen->z80->bank_reg < 0x80) { | 829 if (gen->z80_bank_reg < 0x80) { |
668 gen->z80->mem_pointers[1] = (gen->z80->bank_reg << 15) + ((char *)gen->z80->mem_pointers[2]); | 830 gen->z80->mem_pointers[1] = (gen->z80_bank_reg << 15) + ((char *)gen->z80->mem_pointers[2]); |
669 } else { | 831 } else { |
670 gen->z80->mem_pointers[1] = NULL; | 832 gen->z80->mem_pointers[1] = NULL; |
671 } | 833 } |
672 } else { | 834 } else { |
673 fatal_error("68K write to unhandled Z80 address %X\n", location); | 835 fatal_error("68K write to unhandled Z80 address %X\n", location); |
674 } | 836 } |
675 } | 837 } |
676 } else { | 838 } else { |
677 location &= 0x1FFF; | 839 if (location < 0x10100) { |
678 if (location < 0x100) { | 840 switch(location >> 1 & 0xFF) |
679 switch(location/2) | |
680 { | 841 { |
681 case 0x1: | 842 case 0x1: |
682 io_data_write(gen->io.ports, value, context->current_cycle); | 843 io_data_write(gen->io.ports, value, context->current_cycle); |
683 break; | 844 break; |
684 case 0x2: | 845 case 0x2: |
695 break; | 856 break; |
696 case 0x6: | 857 case 0x6: |
697 io_control_write(gen->io.ports+2, value, context->current_cycle); | 858 io_control_write(gen->io.ports+2, value, context->current_cycle); |
698 break; | 859 break; |
699 case 0x7: | 860 case 0x7: |
700 gen->io.ports[0].serial_out = value; | 861 io_tx_write(gen->io.ports, value, context->current_cycle); |
701 break; | 862 break; |
702 case 0x8: | 863 case 0x8: |
703 case 0xB: | 864 case 0xB: |
704 case 0xE: | 865 case 0xE: |
705 //serial input port is not writeable | 866 //serial input port is not writeable |
706 break; | 867 break; |
707 case 0x9: | 868 case 0x9: |
869 io_sctrl_write(gen->io.ports, value, context->current_cycle); | |
708 gen->io.ports[0].serial_ctrl = value; | 870 gen->io.ports[0].serial_ctrl = value; |
709 break; | 871 break; |
710 case 0xA: | 872 case 0xA: |
711 gen->io.ports[1].serial_out = value; | 873 io_tx_write(gen->io.ports + 1, value, context->current_cycle); |
712 break; | 874 break; |
713 case 0xC: | 875 case 0xC: |
714 gen->io.ports[1].serial_ctrl = value; | 876 io_sctrl_write(gen->io.ports + 1, value, context->current_cycle); |
715 break; | 877 break; |
716 case 0xD: | 878 case 0xD: |
717 gen->io.ports[2].serial_out = value; | 879 io_tx_write(gen->io.ports + 2, value, context->current_cycle); |
718 break; | 880 break; |
719 case 0xF: | 881 case 0xF: |
720 gen->io.ports[2].serial_ctrl = value; | 882 io_sctrl_write(gen->io.ports + 2, value, context->current_cycle); |
721 break; | 883 break; |
722 } | 884 } |
723 } else { | 885 } else { |
724 if (location == 0x1100) { | 886 uint32_t masked = location & 0xFFF00; |
887 if (masked == 0x11100) { | |
725 if (value & 1) { | 888 if (value & 1) { |
726 dputs("bus requesting Z80"); | 889 dputs("bus requesting Z80"); |
727 if (z80_enabled) { | 890 if (z80_enabled) { |
728 z80_assert_busreq(gen->z80, context->current_cycle); | 891 z80_assert_busreq(gen->z80, context->current_cycle); |
729 } else { | 892 } else { |
744 z80_clear_busreq(gen->z80, context->current_cycle); | 907 z80_clear_busreq(gen->z80, context->current_cycle); |
745 } else { | 908 } else { |
746 gen->z80->busack = 0; | 909 gen->z80->busack = 0; |
747 } | 910 } |
748 } | 911 } |
749 } else if (location == 0x1200) { | 912 } else if (masked == 0x11200) { |
750 sync_z80(gen->z80, context->current_cycle); | 913 sync_z80(gen->z80, context->current_cycle); |
751 if (value & 1) { | 914 if (value & 1) { |
752 if (z80_enabled) { | 915 if (z80_enabled) { |
753 z80_clear_reset(gen->z80, context->current_cycle); | 916 z80_clear_reset(gen->z80, context->current_cycle); |
754 } else { | 917 } else { |
760 } else { | 923 } else { |
761 gen->z80->reset = 1; | 924 gen->z80->reset = 1; |
762 } | 925 } |
763 ym_reset(gen->ym); | 926 ym_reset(gen->ym); |
764 } | 927 } |
765 } | 928 } else if (masked != 0x11300 && masked != 0x11000) { |
766 } | 929 fatal_error("Machine freeze due to unmapped write to address %X\n", location | 0xA00000); |
767 } | 930 } |
931 } | |
932 } | |
933 #ifdef REFRESH_EMULATION | |
934 //no refresh delays during IO access | |
935 refresh_counter += context->current_cycle - last_sync_cycle; | |
936 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); | |
937 #endif | |
768 return context; | 938 return context; |
769 } | 939 } |
770 | 940 |
771 static m68k_context * io_write_w(uint32_t location, m68k_context * context, uint16_t value) | 941 static m68k_context * io_write_w(uint32_t location, m68k_context * context, uint16_t value) |
772 { | 942 { |
786 | 956 |
787 static uint8_t io_read(uint32_t location, m68k_context * context) | 957 static uint8_t io_read(uint32_t location, m68k_context * context) |
788 { | 958 { |
789 uint8_t value; | 959 uint8_t value; |
790 genesis_context *gen = context->system; | 960 genesis_context *gen = context->system; |
961 #ifdef REFRESH_EMULATION | |
962 //do refresh check here so we can avoid adding a penalty for a refresh that happens during an IO area access | |
963 refresh_counter += context->current_cycle - 4*MCLKS_PER_68K - last_sync_cycle; | |
964 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL)); | |
965 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); | |
966 last_sync_cycle = context->current_cycle - 4*MCLKS_PER_68K; | |
967 #endif | |
791 if (location < 0x10000) { | 968 if (location < 0x10000) { |
792 //Access to Z80 memory incurs a one 68K cycle wait state | 969 //Access to Z80 memory incurs a one 68K cycle wait state |
793 context->current_cycle += MCLKS_PER_68K; | 970 context->current_cycle += MCLKS_PER_68K; |
794 if (!z80_enabled || z80_get_busack(gen->z80, context->current_cycle)) { | 971 if (!z80_enabled || z80_get_busack(gen->z80, context->current_cycle)) { |
795 location &= 0x7FFF; | 972 location &= 0x7FFF; |
796 if (location < 0x4000) { | 973 if (location < 0x4000) { |
797 value = gen->zram[location & 0x1FFF]; | 974 value = gen->zram[location & 0x1FFF]; |
798 } else if (location < 0x6000) { | 975 } else if (location < 0x6000) { |
799 sync_sound(gen, context->current_cycle); | 976 sync_sound(gen, context->current_cycle); |
800 value = ym_read_status(gen->ym); | 977 value = ym_read_status(gen->ym, context->current_cycle, location); |
978 } else if (location < 0x7F00) { | |
979 value = 0xFF; | |
801 } else { | 980 } else { |
981 fatal_error("Machine freeze due to read of Z80 VDP memory window by 68K: %X\n", location | 0xA00000); | |
802 value = 0xFF; | 982 value = 0xFF; |
803 } | 983 } |
804 } else { | 984 } else { |
805 value = 0xFF; | 985 uint16_t word = get_open_bus_value(&gen->header); |
806 } | 986 value = location & 1 ? word : word >> 8; |
807 } else { | 987 } |
808 location &= 0x1FFF; | 988 } else { |
809 if (location < 0x100) { | 989 if (location < 0x10100) { |
810 switch(location/2) | 990 switch(location >> 1 & 0xFF) |
811 { | 991 { |
812 case 0x0: | 992 case 0x0: |
813 //version bits should be 0 for now since we're not emulating TMSS | 993 //version bits should be 0 for now since we're not emulating TMSS |
814 value = gen->version_reg; | 994 value = gen->version_reg; |
815 break; | 995 break; |
833 break; | 1013 break; |
834 case 0x7: | 1014 case 0x7: |
835 value = gen->io.ports[0].serial_out; | 1015 value = gen->io.ports[0].serial_out; |
836 break; | 1016 break; |
837 case 0x8: | 1017 case 0x8: |
838 value = gen->io.ports[0].serial_in; | 1018 value = io_rx_read(gen->io.ports, context->current_cycle); |
839 break; | 1019 break; |
840 case 0x9: | 1020 case 0x9: |
841 value = gen->io.ports[0].serial_ctrl; | 1021 value = io_sctrl_read(gen->io.ports, context->current_cycle); |
842 break; | 1022 break; |
843 case 0xA: | 1023 case 0xA: |
844 value = gen->io.ports[1].serial_out; | 1024 value = gen->io.ports[1].serial_out; |
845 break; | 1025 break; |
846 case 0xB: | 1026 case 0xB: |
847 value = gen->io.ports[1].serial_in; | 1027 value = io_rx_read(gen->io.ports + 1, context->current_cycle); |
848 break; | 1028 break; |
849 case 0xC: | 1029 case 0xC: |
850 value = gen->io.ports[1].serial_ctrl; | 1030 value = io_sctrl_read(gen->io.ports, context->current_cycle); |
851 break; | 1031 break; |
852 case 0xD: | 1032 case 0xD: |
853 value = gen->io.ports[2].serial_out; | 1033 value = gen->io.ports[2].serial_out; |
854 break; | 1034 break; |
855 case 0xE: | 1035 case 0xE: |
856 value = gen->io.ports[2].serial_in; | 1036 value = io_rx_read(gen->io.ports + 1, context->current_cycle); |
857 break; | 1037 break; |
858 case 0xF: | 1038 case 0xF: |
859 value = gen->io.ports[2].serial_ctrl; | 1039 value = io_sctrl_read(gen->io.ports, context->current_cycle); |
860 break; | 1040 break; |
861 default: | 1041 default: |
862 value = 0xFF; | 1042 value = get_open_bus_value(&gen->header) >> 8; |
863 } | 1043 } |
864 } else { | 1044 } else { |
865 if (location == 0x1100) { | 1045 uint32_t masked = location & 0xFFF00; |
1046 if (masked == 0x11100) { | |
866 value = z80_enabled ? !z80_get_busack(gen->z80, context->current_cycle) : !gen->z80->busack; | 1047 value = z80_enabled ? !z80_get_busack(gen->z80, context->current_cycle) : !gen->z80->busack; |
867 value |= (get_open_bus_value(&gen->header) >> 8) & 0xFE; | 1048 value |= (get_open_bus_value(&gen->header) >> 8) & 0xFE; |
868 dprintf("Byte read of BUSREQ returned %d @ %d (reset: %d)\n", value, context->current_cycle, gen->z80->reset); | 1049 dprintf("Byte read of BUSREQ returned %d @ %d (reset: %d)\n", value, context->current_cycle, gen->z80->reset); |
869 } else if (location == 0x1200) { | 1050 } else if (masked == 0x11200) { |
870 value = !gen->z80->reset; | 1051 value = !gen->z80->reset; |
1052 } else if (masked == 0x11300 || masked == 0x11000) { | |
1053 //A11300 is apparently completely unused | |
1054 //A11000 is the memory control register which I am assuming is write only | |
1055 value = get_open_bus_value(&gen->header) >> 8; | |
871 } else { | 1056 } else { |
1057 location |= 0xA00000; | |
1058 fatal_error("Machine freeze due to read of unmapped IO location %X\n", location); | |
872 value = 0xFF; | 1059 value = 0xFF; |
873 printf("Byte read of unknown IO location: %X\n", location); | 1060 } |
874 } | 1061 } |
875 } | 1062 } |
876 } | 1063 #ifdef REFRESH_EMULATION |
1064 //no refresh delays during IO access | |
1065 refresh_counter += context->current_cycle - last_sync_cycle; | |
1066 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); | |
1067 #endif | |
877 return value; | 1068 return value; |
878 } | 1069 } |
879 | 1070 |
880 static uint16_t io_read_w(uint32_t location, m68k_context * context) | 1071 static uint16_t io_read_w(uint32_t location, m68k_context * context) |
881 { | 1072 { |
892 | 1083 |
893 static void * z80_write_ym(uint32_t location, void * vcontext, uint8_t value) | 1084 static void * z80_write_ym(uint32_t location, void * vcontext, uint8_t value) |
894 { | 1085 { |
895 z80_context * context = vcontext; | 1086 z80_context * context = vcontext; |
896 genesis_context * gen = context->system; | 1087 genesis_context * gen = context->system; |
897 sync_sound(gen, context->current_cycle); | 1088 sync_sound(gen, context->Z80_CYCLE); |
898 if (location & 1) { | 1089 if (location & 1) { |
899 ym_data_write(gen->ym, value); | 1090 ym_data_write(gen->ym, value); |
900 } else if (location & 2) { | 1091 } else if (location & 2) { |
901 ym_address_write_part2(gen->ym, value); | 1092 ym_address_write_part2(gen->ym, value); |
902 } else { | 1093 } else { |
907 | 1098 |
908 static uint8_t z80_read_ym(uint32_t location, void * vcontext) | 1099 static uint8_t z80_read_ym(uint32_t location, void * vcontext) |
909 { | 1100 { |
910 z80_context * context = vcontext; | 1101 z80_context * context = vcontext; |
911 genesis_context * gen = context->system; | 1102 genesis_context * gen = context->system; |
912 sync_sound(gen, context->current_cycle); | 1103 sync_sound(gen, context->Z80_CYCLE); |
913 return ym_read_status(gen->ym); | 1104 return ym_read_status(gen->ym, context->Z80_CYCLE, location); |
914 } | 1105 } |
915 | 1106 |
916 static uint8_t z80_read_bank(uint32_t location, void * vcontext) | 1107 static uint8_t z80_read_bank(uint32_t location, void * vcontext) |
917 { | 1108 { |
918 z80_context * context = vcontext; | 1109 z80_context * context = vcontext; |
919 genesis_context *gen = context->system; | 1110 genesis_context *gen = context->system; |
920 if (gen->bus_busy) { | 1111 if (gen->bus_busy) { |
921 context->current_cycle = context->sync_cycle; | 1112 context->Z80_CYCLE = gen->m68k->current_cycle; |
922 } | 1113 } |
923 //typical delay from bus arbitration | 1114 //typical delay from bus arbitration |
924 context->current_cycle += 3 * MCLKS_PER_Z80; | 1115 context->Z80_CYCLE += 3 * MCLKS_PER_Z80; |
925 //TODO: add cycle for an access right after a previous one | 1116 //TODO: add cycle for an access right after a previous one |
926 //TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high | 1117 //TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high |
927 // Needs a new logic analyzer capture to get the actual delay on the 68K side | 1118 // Needs a new logic analyzer capture to get the actual delay on the 68K side |
928 gen->m68k->current_cycle += 8 * MCLKS_PER_68K; | 1119 gen->m68k->current_cycle += 8 * MCLKS_PER_68K; |
929 | 1120 |
930 location &= 0x7FFF; | 1121 location &= 0x7FFF; |
931 if (context->mem_pointers[1]) { | 1122 if (context->mem_pointers[1]) { |
932 return context->mem_pointers[1][location ^ 1]; | 1123 return context->mem_pointers[1][location ^ 1]; |
933 } | 1124 } |
934 uint32_t address = context->bank_reg << 15 | location; | 1125 uint32_t address = gen->z80_bank_reg << 15 | location; |
935 if (address >= 0xC00000 && address < 0xE00000) { | 1126 if (address >= 0xC00000 && address < 0xE00000) { |
936 return z80_vdp_port_read(location & 0xFF, context); | 1127 return z80_vdp_port_read(location & 0xFF, context); |
937 } else { | 1128 } else if (address >= 0xA10000 && address <= 0xA10001) { |
938 fprintf(stderr, "Unhandled read by Z80 from address %X through banked memory area (%X)\n", address, context->bank_reg << 15); | 1129 //Apparently version reg can be read through Z80 banked area |
1130 //TODO: Check rest of IO region addresses | |
1131 return gen->version_reg; | |
1132 } else { | |
1133 fprintf(stderr, "Unhandled read by Z80 from address %X through banked memory area (%X)\n", address, gen->z80_bank_reg << 15); | |
939 } | 1134 } |
940 return 0; | 1135 return 0; |
941 } | 1136 } |
942 | 1137 |
943 static void *z80_write_bank(uint32_t location, void * vcontext, uint8_t value) | 1138 static void *z80_write_bank(uint32_t location, void * vcontext, uint8_t value) |
944 { | 1139 { |
945 z80_context * context = vcontext; | 1140 z80_context * context = vcontext; |
946 genesis_context *gen = context->system; | 1141 genesis_context *gen = context->system; |
947 if (gen->bus_busy) { | 1142 if (gen->bus_busy) { |
948 context->current_cycle = context->sync_cycle; | 1143 context->Z80_CYCLE = gen->m68k->current_cycle; |
949 } | 1144 } |
950 //typical delay from bus arbitration | 1145 //typical delay from bus arbitration |
951 context->current_cycle += 3 * MCLKS_PER_Z80; | 1146 context->Z80_CYCLE += 3 * MCLKS_PER_Z80; |
952 //TODO: add cycle for an access right after a previous one | 1147 //TODO: add cycle for an access right after a previous one |
953 //TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high | 1148 //TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high |
954 // Needs a new logic analyzer capture to get the actual delay on the 68K side | 1149 // Needs a new logic analyzer capture to get the actual delay on the 68K side |
955 gen->m68k->current_cycle += 8 * MCLKS_PER_68K; | 1150 gen->m68k->current_cycle += 8 * MCLKS_PER_68K; |
956 | 1151 |
957 location &= 0x7FFF; | 1152 location &= 0x7FFF; |
958 uint32_t address = context->bank_reg << 15 | location; | 1153 uint32_t address = gen->z80_bank_reg << 15 | location; |
959 if (address >= 0xE00000) { | 1154 if (address >= 0xE00000) { |
960 address &= 0xFFFF; | 1155 address &= 0xFFFF; |
961 ((uint8_t *)gen->work_ram)[address ^ 1] = value; | 1156 ((uint8_t *)gen->work_ram)[address ^ 1] = value; |
962 } else if (address >= 0xC00000) { | 1157 } else if (address >= 0xC00000) { |
963 z80_vdp_port_write(location & 0xFF, context, value); | 1158 z80_vdp_port_write(location & 0xFF, context, value); |
968 } | 1163 } |
969 | 1164 |
970 static void *z80_write_bank_reg(uint32_t location, void * vcontext, uint8_t value) | 1165 static void *z80_write_bank_reg(uint32_t location, void * vcontext, uint8_t value) |
971 { | 1166 { |
972 z80_context * context = vcontext; | 1167 z80_context * context = vcontext; |
973 | 1168 genesis_context *gen = context->system; |
974 context->bank_reg = (context->bank_reg >> 1 | value << 8) & 0x1FF; | 1169 |
1170 gen->z80_bank_reg = (gen->z80_bank_reg >> 1 | value << 8) & 0x1FF; | |
975 update_z80_bank_pointer(context->system); | 1171 update_z80_bank_pointer(context->system); |
976 | 1172 |
977 return context; | 1173 return context; |
1174 } | |
1175 | |
1176 static uint16_t unused_read(uint32_t location, void *vcontext) | |
1177 { | |
1178 m68k_context *context = vcontext; | |
1179 genesis_context *gen = context->system; | |
1180 if (location < 0x800000 || (location >= 0xA13000 && location < 0xA13100) || (location >= 0xA12000 && location < 0xA12100)) { | |
1181 //Only called if the cart/exp doesn't have a more specific handler for this region | |
1182 return get_open_bus_value(&gen->header); | |
1183 } else if (location == 0xA14000 || location == 0xA14002) { | |
1184 if (gen->version_reg & 0xF) { | |
1185 return gen->tmss_lock[location >> 1 & 1]; | |
1186 } else { | |
1187 fatal_error("Machine freeze due to read from TMSS lock when TMSS is not present %X\n", location); | |
1188 return 0xFFFF; | |
1189 } | |
1190 } else if (location == 0xA14100) { | |
1191 if (gen->version_reg & 0xF) { | |
1192 return get_open_bus_value(&gen->header); | |
1193 } else { | |
1194 fatal_error("Machine freeze due to read from TMSS control when TMSS is not present %X\n", location); | |
1195 return 0xFFFF; | |
1196 } | |
1197 } else { | |
1198 fatal_error("Machine freeze due to unmapped read from %X\n", location); | |
1199 return 0xFFFF; | |
1200 } | |
1201 } | |
1202 | |
1203 static uint8_t unused_read_b(uint32_t location, void *vcontext) | |
1204 { | |
1205 uint16_t v = unused_read(location & 0xFFFFFE, vcontext); | |
1206 if (location & 1) { | |
1207 return v; | |
1208 } else { | |
1209 return v >> 8; | |
1210 } | |
1211 } | |
1212 | |
1213 static void check_tmss_lock(genesis_context *gen) | |
1214 { | |
1215 gen->vdp_unlocked = gen->tmss_lock[0] == 0x5345 && gen->tmss_lock[1] == 0x4741; | |
1216 } | |
1217 | |
1218 static void toggle_tmss_rom(genesis_context *gen) | |
1219 { | |
1220 m68k_context *context = gen->m68k; | |
1221 for (int i = 0; i < NUM_MEM_AREAS; i++) | |
1222 { | |
1223 uint16_t *tmp = context->mem_pointers[i]; | |
1224 context->mem_pointers[i] = gen->tmss_pointers[i]; | |
1225 gen->tmss_pointers[i] = tmp; | |
1226 } | |
1227 m68k_invalidate_code_range(context, 0, 0x400000); | |
1228 } | |
1229 | |
1230 static void *unused_write(uint32_t location, void *vcontext, uint16_t value) | |
1231 { | |
1232 m68k_context *context = vcontext; | |
1233 genesis_context *gen = context->system; | |
1234 uint8_t has_tmss = gen->version_reg & 0xF; | |
1235 if (has_tmss && (location == 0xA14000 || location == 0xA14002)) { | |
1236 gen->tmss_lock[location >> 1 & 1] = value; | |
1237 check_tmss_lock(gen); | |
1238 } else if (has_tmss && location == 0xA14100) { | |
1239 value &= 1; | |
1240 if (gen->tmss != value) { | |
1241 gen->tmss = value; | |
1242 toggle_tmss_rom(gen); | |
1243 } | |
1244 } else if (location < 0x800000 || (location >= 0xA13000 && location < 0xA13100) || (location >= 0xA12000 && location < 0xA12100)) { | |
1245 //these writes are ignored when no relevant hardware is present | |
1246 } else { | |
1247 fatal_error("Machine freeze due to unmapped write to %X\n", location); | |
1248 } | |
1249 return vcontext; | |
1250 } | |
1251 | |
1252 static void *unused_write_b(uint32_t location, void *vcontext, uint8_t value) | |
1253 { | |
1254 m68k_context *context = vcontext; | |
1255 genesis_context *gen = context->system; | |
1256 uint8_t has_tmss = gen->version_reg & 0xF; | |
1257 if (has_tmss && location >= 0xA14000 && location <= 0xA14003) { | |
1258 uint32_t offset = location >> 1 & 1; | |
1259 if (location & 1) { | |
1260 gen->tmss_lock[offset] &= 0xFF00; | |
1261 gen->tmss_lock[offset] |= value; | |
1262 } else { | |
1263 gen->tmss_lock[offset] &= 0xFF; | |
1264 gen->tmss_lock[offset] |= value << 8; | |
1265 } | |
1266 check_tmss_lock(gen); | |
1267 } else if (has_tmss && (location == 0xA14100 || location == 0xA14101)) { | |
1268 if (location & 1) { | |
1269 value &= 1; | |
1270 if (gen->tmss != value) { | |
1271 gen->tmss = value; | |
1272 toggle_tmss_rom(gen); | |
1273 } | |
1274 } | |
1275 } else if (location < 0x800000 || (location >= 0xA13000 && location < 0xA13100) || (location >= 0xA12000 && location < 0xA12100)) { | |
1276 //these writes are ignored when no relevant hardware is present | |
1277 } else { | |
1278 fatal_error("Machine freeze due to unmapped byte write to %X\n", location); | |
1279 } | |
1280 return vcontext; | |
978 } | 1281 } |
979 | 1282 |
980 static void set_speed_percent(system_header * system, uint32_t percent) | 1283 static void set_speed_percent(system_header * system, uint32_t percent) |
981 { | 1284 { |
982 genesis_context *context = (genesis_context *)system; | 1285 genesis_context *context = (genesis_context *)system; |
1004 } else if (region & REGION_J) { | 1307 } else if (region & REGION_J) { |
1005 gen->version_reg = NO_DISK | JAP; | 1308 gen->version_reg = NO_DISK | JAP; |
1006 } else { | 1309 } else { |
1007 gen->version_reg = NO_DISK | USA; | 1310 gen->version_reg = NO_DISK | USA; |
1008 } | 1311 } |
1009 | 1312 |
1010 if (region & HZ50) { | 1313 if (region & HZ50) { |
1011 gen->normal_clock = MCLKS_PAL; | 1314 gen->normal_clock = MCLKS_PAL; |
1315 gen->soft_flush_cycles = MCLKS_LINE * 262 / 3 + 2; | |
1012 } else { | 1316 } else { |
1013 gen->normal_clock = MCLKS_NTSC; | 1317 gen->normal_clock = MCLKS_NTSC; |
1318 gen->soft_flush_cycles = MCLKS_LINE * 313 / 3 + 2; | |
1014 } | 1319 } |
1015 gen->master_clock = gen->normal_clock; | 1320 gen->master_clock = gen->normal_clock; |
1016 } | 1321 } |
1017 | 1322 |
1018 #include "m68k_internal.h" //needed for get_native_address_trans, should be eliminated once handling of PC is cleaned up | |
1019 static uint8_t load_state(system_header *system, uint8_t slot) | 1323 static uint8_t load_state(system_header *system, uint8_t slot) |
1020 { | 1324 { |
1021 genesis_context *gen = (genesis_context *)system; | 1325 genesis_context *gen = (genesis_context *)system; |
1022 char *statepath = get_slot_name(system, slot, "state"); | 1326 char *statepath = get_slot_name(system, slot, "state"); |
1023 deserialize_buffer state; | 1327 deserialize_buffer state; |
1069 load_state(&gen->header, gen->header.delayed_load_slot - 1); | 1373 load_state(&gen->header, gen->header.delayed_load_slot - 1); |
1070 gen->header.delayed_load_slot = 0; | 1374 gen->header.delayed_load_slot = 0; |
1071 resume_68k(gen->m68k); | 1375 resume_68k(gen->m68k); |
1072 } | 1376 } |
1073 } | 1377 } |
1074 bindings_release_capture(); | 1378 if (gen->header.force_release || render_should_release_on_exit()) { |
1075 vdp_release_framebuffer(gen->vdp); | 1379 bindings_release_capture(); |
1076 render_pause_source(gen->ym->audio); | 1380 vdp_release_framebuffer(gen->vdp); |
1077 render_pause_source(gen->psg->audio); | 1381 render_pause_source(gen->ym->audio); |
1382 render_pause_source(gen->psg->audio); | |
1383 } | |
1078 } | 1384 } |
1079 | 1385 |
1080 static void start_genesis(system_header *system, char *statefile) | 1386 static void start_genesis(system_header *system, char *statefile) |
1081 { | 1387 { |
1082 genesis_context *gen = (genesis_context *)system; | 1388 genesis_context *gen = (genesis_context *)system; |
1116 } | 1422 } |
1117 | 1423 |
1118 static void resume_genesis(system_header *system) | 1424 static void resume_genesis(system_header *system) |
1119 { | 1425 { |
1120 genesis_context *gen = (genesis_context *)system; | 1426 genesis_context *gen = (genesis_context *)system; |
1121 render_set_video_standard((gen->version_reg & HZ50) ? VID_PAL : VID_NTSC); | 1427 if (gen->header.force_release || render_should_release_on_exit()) { |
1122 bindings_reacquire_capture(); | 1428 gen->header.force_release = 0; |
1123 vdp_reacquire_framebuffer(gen->vdp); | 1429 render_set_video_standard((gen->version_reg & HZ50) ? VID_PAL : VID_NTSC); |
1124 render_resume_source(gen->ym->audio); | 1430 bindings_reacquire_capture(); |
1125 render_resume_source(gen->psg->audio); | 1431 vdp_reacquire_framebuffer(gen->vdp); |
1432 render_resume_source(gen->ym->audio); | |
1433 render_resume_source(gen->psg->audio); | |
1434 } | |
1126 resume_68k(gen->m68k); | 1435 resume_68k(gen->m68k); |
1127 handle_reset_requests(gen); | 1436 handle_reset_requests(gen); |
1128 } | 1437 } |
1129 | 1438 |
1130 static void inc_debug_mode(system_header *system) | 1439 static void inc_debug_mode(system_header *system) |
1134 } | 1443 } |
1135 | 1444 |
1136 static void request_exit(system_header *system) | 1445 static void request_exit(system_header *system) |
1137 { | 1446 { |
1138 genesis_context *gen = (genesis_context *)system; | 1447 genesis_context *gen = (genesis_context *)system; |
1448 gen->m68k->target_cycle = gen->m68k->current_cycle; | |
1139 gen->m68k->should_return = 1; | 1449 gen->m68k->should_return = 1; |
1140 } | 1450 } |
1141 | 1451 |
1142 static void persist_save(system_header *system) | 1452 static void persist_save(system_header *system) |
1143 { | 1453 { |
1148 FILE * f = fopen(save_filename, "wb"); | 1458 FILE * f = fopen(save_filename, "wb"); |
1149 if (!f) { | 1459 if (!f) { |
1150 fprintf(stderr, "Failed to open %s file %s for writing\n", save_type_name(gen->save_type), save_filename); | 1460 fprintf(stderr, "Failed to open %s file %s for writing\n", save_type_name(gen->save_type), save_filename); |
1151 return; | 1461 return; |
1152 } | 1462 } |
1463 if (gen->save_type == RAM_FLAG_BOTH) { | |
1464 byteswap_rom(gen->save_size, (uint16_t *)gen->save_storage); | |
1465 } | |
1153 fwrite(gen->save_storage, 1, gen->save_size, f); | 1466 fwrite(gen->save_storage, 1, gen->save_size, f); |
1467 if (gen->save_type == RAM_FLAG_BOTH) { | |
1468 byteswap_rom(gen->save_size, (uint16_t *)gen->save_storage); | |
1469 } | |
1154 fclose(f); | 1470 fclose(f); |
1155 printf("Saved %s to %s\n", save_type_name(gen->save_type), save_filename); | 1471 printf("Saved %s to %s\n", save_type_name(gen->save_type), save_filename); |
1156 } | 1472 } |
1157 | 1473 |
1158 static void load_save(system_header *system) | 1474 static void load_save(system_header *system) |
1161 FILE * f = fopen(save_filename, "rb"); | 1477 FILE * f = fopen(save_filename, "rb"); |
1162 if (f) { | 1478 if (f) { |
1163 uint32_t read = fread(gen->save_storage, 1, gen->save_size, f); | 1479 uint32_t read = fread(gen->save_storage, 1, gen->save_size, f); |
1164 fclose(f); | 1480 fclose(f); |
1165 if (read > 0) { | 1481 if (read > 0) { |
1482 if (gen->save_type == RAM_FLAG_BOTH) { | |
1483 byteswap_rom(gen->save_size, (uint16_t *)gen->save_storage); | |
1484 } | |
1166 printf("Loaded %s from %s\n", save_type_name(gen->save_type), save_filename); | 1485 printf("Loaded %s from %s\n", save_type_name(gen->save_type), save_filename); |
1167 } | 1486 } |
1168 } | 1487 } |
1169 } | 1488 } |
1170 | 1489 |
1187 memmap_chunk *map = (memmap_chunk *)gen->m68k->options->gen.memmap; | 1506 memmap_chunk *map = (memmap_chunk *)gen->m68k->options->gen.memmap; |
1188 m68k_options_free(gen->m68k->options); | 1507 m68k_options_free(gen->m68k->options); |
1189 free(gen->cart); | 1508 free(gen->cart); |
1190 free(gen->m68k); | 1509 free(gen->m68k); |
1191 free(gen->work_ram); | 1510 free(gen->work_ram); |
1192 z80_options_free(gen->z80->options); | 1511 z80_options_free(gen->z80->Z80_OPTS); |
1193 free(gen->z80); | 1512 free(gen->z80); |
1194 free(gen->zram); | 1513 free(gen->zram); |
1195 ym_free(gen->ym); | 1514 ym_free(gen->ym); |
1196 psg_free(gen->psg); | 1515 psg_free(gen->psg); |
1197 free(gen->header.save_dir); | 1516 free(gen->header.save_dir); |
1198 free_rom_info(&gen->header.info); | 1517 free_rom_info(&gen->header.info); |
1199 free(gen->lock_on); | 1518 free(gen->lock_on); |
1519 if (gen->save_type != SAVE_NONE && gen->mapper_type != MAPPER_SEGA_MED_V2) { | |
1520 free(gen->save_storage); | |
1521 } | |
1200 free(gen); | 1522 free(gen); |
1201 } | 1523 } |
1202 | 1524 |
1203 static void gamepad_down(system_header *system, uint8_t gamepad_num, uint8_t button) | 1525 static void gamepad_down(system_header *system, uint8_t gamepad_num, uint8_t button) |
1204 { | 1526 { |
1252 { | 1574 { |
1253 genesis_context *gen = (genesis_context *)system; | 1575 genesis_context *gen = (genesis_context *)system; |
1254 io_keyboard_up(&gen->io, scancode); | 1576 io_keyboard_up(&gen->io, scancode); |
1255 } | 1577 } |
1256 | 1578 |
1579 static void set_audio_config(genesis_context *gen) | |
1580 { | |
1581 char *config_gain; | |
1582 config_gain = tern_find_path(config, "audio\0psg_gain\0", TVAL_PTR).ptrval; | |
1583 render_audio_source_gaindb(gen->psg->audio, config_gain ? atof(config_gain) : 0.0f); | |
1584 config_gain = tern_find_path(config, "audio\0fm_gain\0", TVAL_PTR).ptrval; | |
1585 render_audio_source_gaindb(gen->ym->audio, config_gain ? atof(config_gain) : 0.0f); | |
1586 | |
1587 char *config_dac = tern_find_path_default(config, "audio\0fm_dac\0", (tern_val){.ptrval="zero_offset"}, TVAL_PTR).ptrval; | |
1588 ym_enable_zero_offset(gen->ym, !strcmp(config_dac, "zero_offset")); | |
1589 } | |
1590 | |
1257 static void config_updated(system_header *system) | 1591 static void config_updated(system_header *system) |
1258 { | 1592 { |
1259 genesis_context *gen = (genesis_context *)system; | 1593 genesis_context *gen = (genesis_context *)system; |
1260 setup_io_devices(config, &system->info, &gen->io); | 1594 setup_io_devices(config, &system->info, &gen->io); |
1595 set_audio_config(gen); | |
1596 } | |
1597 | |
1598 static void start_vgm_log(system_header *system, char *filename) | |
1599 { | |
1600 genesis_context *gen = (genesis_context *)system; | |
1601 vgm_writer *vgm = vgm_write_open(filename, gen->version_reg & HZ50 ? 50 : 60, gen->master_clock, gen->m68k->current_cycle); | |
1602 if (vgm) { | |
1603 printf("Started logging VGM to %s\n", filename); | |
1604 sync_sound(gen, vgm->last_cycle); | |
1605 ym_vgm_log(gen->ym, gen->master_clock, vgm); | |
1606 psg_vgm_log(gen->psg, gen->master_clock, vgm); | |
1607 gen->header.vgm_logging = 1; | |
1608 } else { | |
1609 printf("Failed to start logging to %s\n", filename); | |
1610 } | |
1611 } | |
1612 | |
1613 static void stop_vgm_log(system_header *system) | |
1614 { | |
1615 puts("Stopped VGM log"); | |
1616 genesis_context *gen = (genesis_context *)system; | |
1617 vgm_close(gen->ym->vgm); | |
1618 gen->ym->vgm = gen->psg->vgm = NULL; | |
1619 gen->header.vgm_logging = 0; | |
1620 } | |
1621 | |
1622 static void *tmss_rom_write_16(uint32_t address, void *context, uint16_t value) | |
1623 { | |
1624 m68k_context *m68k = context; | |
1625 genesis_context *gen = m68k->system; | |
1626 if (gen->tmss) { | |
1627 return gen->tmss_write_16(address, context, value); | |
1628 } | |
1629 | |
1630 return context; | |
1631 } | |
1632 | |
1633 static void *tmss_rom_write_8(uint32_t address, void *context, uint8_t value) | |
1634 { | |
1635 m68k_context *m68k = context; | |
1636 genesis_context *gen = m68k->system; | |
1637 if (gen->tmss) { | |
1638 return gen->tmss_write_8(address, context, value); | |
1639 } | |
1640 | |
1641 return context; | |
1642 } | |
1643 | |
1644 static uint16_t tmss_rom_read_16(uint32_t address, void *context) | |
1645 { | |
1646 m68k_context *m68k = context; | |
1647 genesis_context *gen = m68k->system; | |
1648 if (gen->tmss) { | |
1649 return gen->tmss_read_16(address, context); | |
1650 } | |
1651 return ((uint16_t *)gen->tmss_buffer)[address >> 1]; | |
1652 } | |
1653 | |
1654 static uint8_t tmss_rom_read_8(uint32_t address, void *context) | |
1655 { | |
1656 m68k_context *m68k = context; | |
1657 genesis_context *gen = m68k->system; | |
1658 if (gen->tmss) { | |
1659 return gen->tmss_read_8(address, context); | |
1660 } | |
1661 #ifdef BLASTEM_BIG_ENDIAN | |
1662 return gen->tmss_buffer[address]; | |
1663 #else | |
1664 return gen->tmss_buffer[address ^ 1]; | |
1665 #endif | |
1666 } | |
1667 | |
1668 static void *tmss_word_write_16(uint32_t address, void *context, uint16_t value) | |
1669 { | |
1670 m68k_context *m68k = context; | |
1671 genesis_context *gen = m68k->system; | |
1672 if (gen->tmss) { | |
1673 address += gen->tmss_write_offset; | |
1674 uint16_t *dest = get_native_pointer(address, (void **)m68k->mem_pointers, &m68k->options->gen); | |
1675 *dest = value; | |
1676 m68k_handle_code_write(address, m68k); | |
1677 } | |
1678 | |
1679 return context; | |
1680 } | |
1681 | |
1682 static void *tmss_word_write_8(uint32_t address, void *context, uint8_t value) | |
1683 { | |
1684 m68k_context *m68k = context; | |
1685 genesis_context *gen = m68k->system; | |
1686 if (gen->tmss) { | |
1687 address += gen->tmss_write_offset; | |
1688 uint8_t *dest = get_native_pointer(address & ~1, (void **)m68k->mem_pointers, &m68k->options->gen); | |
1689 #ifdef BLASTEM_BIG_ENDIAN | |
1690 dest[address & 1] = value; | |
1691 #else | |
1692 dest[address & 1 ^ 1] = value; | |
1693 #endif | |
1694 m68k_handle_code_write(address & ~1, m68k); | |
1695 } | |
1696 | |
1697 return context; | |
1698 } | |
1699 | |
1700 static void *tmss_odd_write_16(uint32_t address, void *context, uint16_t value) | |
1701 { | |
1702 m68k_context *m68k = context; | |
1703 genesis_context *gen = m68k->system; | |
1704 if (gen->tmss) { | |
1705 memmap_chunk const *chunk = find_map_chunk(address + gen->tmss_write_offset, &m68k->options->gen, 0, NULL); | |
1706 address >>= 1; | |
1707 uint8_t *base = (uint8_t *)m68k->mem_pointers[chunk->ptr_index]; | |
1708 base[address] = value; | |
1709 } | |
1710 return context; | |
1711 } | |
1712 | |
1713 static void *tmss_odd_write_8(uint32_t address, void *context, uint8_t value) | |
1714 { | |
1715 m68k_context *m68k = context; | |
1716 genesis_context *gen = m68k->system; | |
1717 if (gen->tmss && (address & 1)) { | |
1718 memmap_chunk const *chunk = find_map_chunk(address + gen->tmss_write_offset, &m68k->options->gen, 0, NULL); | |
1719 address >>= 1; | |
1720 uint8_t *base = (uint8_t *)m68k->mem_pointers[chunk->ptr_index]; | |
1721 base[address] = value; | |
1722 } | |
1723 return context; | |
1724 } | |
1725 | |
1726 static void *tmss_even_write_16(uint32_t address, void *context, uint16_t value) | |
1727 { | |
1728 m68k_context *m68k = context; | |
1729 genesis_context *gen = m68k->system; | |
1730 if (gen->tmss) { | |
1731 memmap_chunk const *chunk = find_map_chunk(address + gen->tmss_write_offset, &m68k->options->gen, 0, NULL); | |
1732 address >>= 1; | |
1733 uint8_t *base = (uint8_t *)m68k->mem_pointers[chunk->ptr_index]; | |
1734 base[address] = value >> 8; | |
1735 } | |
1736 return context; | |
1737 } | |
1738 | |
1739 static void *tmss_even_write_8(uint32_t address, void *context, uint8_t value) | |
1740 { | |
1741 m68k_context *m68k = context; | |
1742 genesis_context *gen = m68k->system; | |
1743 if (gen->tmss && !(address & 1)) { | |
1744 memmap_chunk const *chunk = find_map_chunk(address + gen->tmss_write_offset, &m68k->options->gen, 0, NULL); | |
1745 address >>= 1; | |
1746 uint8_t *base = (uint8_t *)m68k->mem_pointers[chunk->ptr_index]; | |
1747 base[address] = value; | |
1748 } | |
1749 return context; | |
1261 } | 1750 } |
1262 | 1751 |
1263 static genesis_context *shared_init(uint32_t system_opts, rom_info *rom, uint8_t force_region) | 1752 static genesis_context *shared_init(uint32_t system_opts, rom_info *rom, uint8_t force_region) |
1264 { | 1753 { |
1265 static memmap_chunk z80_map[] = { | 1754 static memmap_chunk z80_map[] = { |
1267 { 0x8000, 0x10000, 0x7FFF, 0, 0, 0, NULL, NULL, NULL, z80_read_bank, z80_write_bank}, | 1756 { 0x8000, 0x10000, 0x7FFF, 0, 0, 0, NULL, NULL, NULL, z80_read_bank, z80_write_bank}, |
1268 { 0x4000, 0x6000, 0x0003, 0, 0, 0, NULL, NULL, NULL, z80_read_ym, z80_write_ym}, | 1757 { 0x4000, 0x6000, 0x0003, 0, 0, 0, NULL, NULL, NULL, z80_read_ym, z80_write_ym}, |
1269 { 0x6000, 0x6100, 0xFFFF, 0, 0, 0, NULL, NULL, NULL, NULL, z80_write_bank_reg}, | 1758 { 0x6000, 0x6100, 0xFFFF, 0, 0, 0, NULL, NULL, NULL, NULL, z80_write_bank_reg}, |
1270 { 0x7F00, 0x8000, 0x00FF, 0, 0, 0, NULL, NULL, NULL, z80_vdp_port_read, z80_vdp_port_write} | 1759 { 0x7F00, 0x8000, 0x00FF, 0, 0, 0, NULL, NULL, NULL, z80_vdp_port_read, z80_vdp_port_write} |
1271 }; | 1760 }; |
1272 | 1761 |
1273 char *m68k_divider = tern_find_path(config, "clocks\0m68k_divider\0", TVAL_PTR).ptrval; | 1762 char *m68k_divider = tern_find_path(config, "clocks\0m68k_divider\0", TVAL_PTR).ptrval; |
1274 if (!m68k_divider) { | 1763 if (!m68k_divider) { |
1275 m68k_divider = "7"; | 1764 m68k_divider = "7"; |
1276 } | 1765 } |
1277 MCLKS_PER_68K = atoi(m68k_divider); | 1766 MCLKS_PER_68K = atoi(m68k_divider); |
1278 if (!MCLKS_PER_68K) { | 1767 if (!MCLKS_PER_68K) { |
1279 MCLKS_PER_68K = 7; | 1768 MCLKS_PER_68K = 7; |
1280 } | 1769 } |
1281 | 1770 |
1282 genesis_context *gen = calloc(1, sizeof(genesis_context)); | 1771 genesis_context *gen = calloc(1, sizeof(genesis_context)); |
1283 gen->header.set_speed_percent = set_speed_percent; | 1772 gen->header.set_speed_percent = set_speed_percent; |
1284 gen->header.start_context = start_genesis; | 1773 gen->header.start_context = start_genesis; |
1285 gen->header.resume_context = resume_genesis; | 1774 gen->header.resume_context = resume_genesis; |
1286 gen->header.load_save = load_save; | 1775 gen->header.load_save = load_save; |
1298 gen->header.mouse_motion_absolute = mouse_motion_absolute; | 1787 gen->header.mouse_motion_absolute = mouse_motion_absolute; |
1299 gen->header.mouse_motion_relative = mouse_motion_relative; | 1788 gen->header.mouse_motion_relative = mouse_motion_relative; |
1300 gen->header.keyboard_down = keyboard_down; | 1789 gen->header.keyboard_down = keyboard_down; |
1301 gen->header.keyboard_up = keyboard_up; | 1790 gen->header.keyboard_up = keyboard_up; |
1302 gen->header.config_updated = config_updated; | 1791 gen->header.config_updated = config_updated; |
1792 gen->header.serialize = serialize; | |
1793 gen->header.deserialize = deserialize; | |
1794 gen->header.start_vgm_log = start_vgm_log; | |
1795 gen->header.stop_vgm_log = stop_vgm_log; | |
1303 gen->header.type = SYSTEM_GENESIS; | 1796 gen->header.type = SYSTEM_GENESIS; |
1304 gen->header.info = *rom; | 1797 gen->header.info = *rom; |
1305 set_region(gen, rom, force_region); | 1798 set_region(gen, rom, force_region); |
1306 | 1799 tern_node *model = get_model(config, SYSTEM_GENESIS); |
1307 gen->vdp = init_vdp_context(gen->version_reg & 0x40); | 1800 uint8_t tmss = !strcmp(tern_find_ptr_default(model, "tmss", "off"), "on"); |
1801 if (tmss) { | |
1802 gen->version_reg |= 1; | |
1803 } else { | |
1804 gen->vdp_unlocked = 1; | |
1805 } | |
1806 | |
1807 uint8_t max_vsram = !strcmp(tern_find_ptr_default(model, "vsram", "40"), "64"); | |
1808 gen->vdp = init_vdp_context(gen->version_reg & 0x40, max_vsram); | |
1308 gen->vdp->system = &gen->header; | 1809 gen->vdp->system = &gen->header; |
1309 gen->frame_end = vdp_cycles_to_frame_end(gen->vdp); | 1810 gen->frame_end = vdp_cycles_to_frame_end(gen->vdp); |
1310 char * config_cycles = tern_find_path(config, "clocks\0max_cycles\0", TVAL_PTR).ptrval; | 1811 char * config_cycles = tern_find_path(config, "clocks\0max_cycles\0", TVAL_PTR).ptrval; |
1311 gen->max_cycles = config_cycles ? atoi(config_cycles) : DEFAULT_SYNC_INTERVAL; | 1812 gen->max_cycles = config_cycles ? atoi(config_cycles) : DEFAULT_SYNC_INTERVAL; |
1312 gen->int_latency_prev1 = MCLKS_PER_68K * 32; | 1813 gen->int_latency_prev1 = MCLKS_PER_68K * 32; |
1313 gen->int_latency_prev2 = MCLKS_PER_68K * 16; | 1814 gen->int_latency_prev2 = MCLKS_PER_68K * 16; |
1314 | 1815 |
1315 render_set_video_standard((gen->version_reg & HZ50) ? VID_PAL : VID_NTSC); | 1816 render_set_video_standard((gen->version_reg & HZ50) ? VID_PAL : VID_NTSC); |
1316 | 1817 event_system_start(SYSTEM_GENESIS, (gen->version_reg & HZ50) ? VID_PAL : VID_NTSC, rom->name); |
1818 | |
1317 gen->ym = malloc(sizeof(ym2612_context)); | 1819 gen->ym = malloc(sizeof(ym2612_context)); |
1820 char *fm = tern_find_ptr_default(model, "fm", "discrete 2612"); | |
1821 if (!strcmp(fm + strlen(fm) -4, "3834")) { | |
1822 system_opts |= YM_OPT_3834; | |
1823 } | |
1318 ym_init(gen->ym, gen->master_clock, MCLKS_PER_YM, system_opts); | 1824 ym_init(gen->ym, gen->master_clock, MCLKS_PER_YM, system_opts); |
1319 | 1825 |
1320 gen->psg = malloc(sizeof(psg_context)); | 1826 gen->psg = malloc(sizeof(psg_context)); |
1321 psg_init(gen->psg, gen->master_clock, MCLKS_PER_PSG); | 1827 psg_init(gen->psg, gen->master_clock, MCLKS_PER_PSG); |
1828 | |
1829 set_audio_config(gen); | |
1322 | 1830 |
1323 z80_map[0].buffer = gen->zram = calloc(1, Z80_RAM_BYTES); | 1831 z80_map[0].buffer = gen->zram = calloc(1, Z80_RAM_BYTES); |
1324 #ifndef NO_Z80 | 1832 #ifndef NO_Z80 |
1325 z80_options *z_opts = malloc(sizeof(z80_options)); | 1833 z80_options *z_opts = malloc(sizeof(z80_options)); |
1326 init_z80_opts(z_opts, z80_map, 5, NULL, 0, MCLKS_PER_Z80, 0xFFFF); | 1834 init_z80_opts(z_opts, z80_map, 5, NULL, 0, MCLKS_PER_Z80, 0xFFFF); |
1327 gen->z80 = init_z80_context(z_opts); | 1835 gen->z80 = init_z80_context(z_opts); |
1836 #ifndef NEW_CORE | |
1328 gen->z80->next_int_pulse = z80_next_int_pulse; | 1837 gen->z80->next_int_pulse = z80_next_int_pulse; |
1838 #endif | |
1329 z80_assert_reset(gen->z80, 0); | 1839 z80_assert_reset(gen->z80, 0); |
1330 #else | 1840 #else |
1331 gen->z80 = calloc(1, sizeof(z80_context)); | 1841 gen->z80 = calloc(1, sizeof(z80_context)); |
1332 #endif | 1842 #endif |
1333 | 1843 |
1334 gen->z80->system = gen; | 1844 gen->z80->system = gen; |
1335 gen->z80->mem_pointers[0] = gen->zram; | 1845 gen->z80->mem_pointers[0] = gen->zram; |
1336 gen->z80->mem_pointers[1] = gen->z80->mem_pointers[2] = NULL; | 1846 gen->z80->mem_pointers[1] = gen->z80->mem_pointers[2] = NULL; |
1337 | 1847 |
1338 gen->work_ram = calloc(2, RAM_WORDS); | 1848 gen->work_ram = calloc(2, RAM_WORDS); |
1339 if (!strcmp("random", tern_find_path_default(config, "system\0ram_init\0", (tern_val){.ptrval = "zero"}, TVAL_PTR).ptrval)) | 1849 if (!strcmp("random", tern_find_path_default(config, "system\0ram_init\0", (tern_val){.ptrval = "zero"}, TVAL_PTR).ptrval)) |
1340 { | 1850 { |
1341 srand(time(NULL)); | 1851 srand(time(NULL)); |
1342 for (int i = 0; i < RAM_WORDS; i++) | 1852 for (int i = 0; i < RAM_WORDS; i++) |
1357 } | 1867 } |
1358 for (int i = 0; i < CRAM_SIZE; i++) | 1868 for (int i = 0; i < CRAM_SIZE; i++) |
1359 { | 1869 { |
1360 write_cram_internal(gen->vdp, i, rand()); | 1870 write_cram_internal(gen->vdp, i, rand()); |
1361 } | 1871 } |
1362 for (int i = 0; i < VSRAM_SIZE; i++) | 1872 for (int i = 0; i < gen->vdp->vsram_size; i++) |
1363 { | 1873 { |
1364 gen->vdp->vsram[i] = rand(); | 1874 gen->vdp->vsram[i] = rand(); |
1365 } | 1875 } |
1366 } | 1876 } |
1367 | 1877 |
1368 return gen; | 1878 return gen; |
1369 } | 1879 } |
1370 | 1880 |
1371 genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on, uint32_t system_opts, uint8_t force_region) | 1881 genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on, uint32_t system_opts, uint8_t force_region) |
1372 { | 1882 { |
1373 genesis_context *gen = shared_init(system_opts, rom, force_region); | 1883 genesis_context *gen = shared_init(system_opts, rom, force_region); |
1374 gen->z80->mem_pointers[1] = gen->z80->mem_pointers[2] = (uint8_t *)main_rom; | 1884 gen->z80->mem_pointers[1] = gen->z80->mem_pointers[2] = (uint8_t *)main_rom; |
1375 | 1885 |
1376 gen->cart = main_rom; | 1886 gen->cart = main_rom; |
1377 gen->lock_on = lock_on; | 1887 gen->lock_on = lock_on; |
1378 | 1888 |
1379 setup_io_devices(config, rom, &gen->io); | 1889 setup_io_devices(config, rom, &gen->io); |
1380 gen->header.has_keyboard = io_has_keyboard(&gen->io); | 1890 gen->header.has_keyboard = io_has_keyboard(&gen->io); |
1381 gen->mapper_type = rom->mapper_type; | 1891 gen->mapper_type = rom->mapper_type; |
1382 gen->save_type = rom->save_type; | 1892 gen->save_type = rom->save_type; |
1383 if (gen->save_type != SAVE_NONE) { | 1893 if (gen->save_type != SAVE_NONE) { |
1393 //nor_flash_init(&gen->nor, gen->save_storage, gen->save_size, rom->save_page_size, rom->save_product_id, rom->save_bus); | 1903 //nor_flash_init(&gen->nor, gen->save_storage, gen->save_size, rom->save_page_size, rom->save_product_id, rom->save_bus); |
1394 } | 1904 } |
1395 } else { | 1905 } else { |
1396 gen->save_storage = NULL; | 1906 gen->save_storage = NULL; |
1397 } | 1907 } |
1398 | 1908 |
1909 gen->mapper_start_index = rom->mapper_start_index; | |
1910 | |
1911 tern_node *model = get_model(config, SYSTEM_GENESIS); | |
1912 uint8_t tmss = !strcmp(tern_find_ptr_default(model, "tmss", "off"), "on"); | |
1913 | |
1399 //This must happen before we generate memory access functions in init_m68k_opts | 1914 //This must happen before we generate memory access functions in init_m68k_opts |
1915 uint8_t next_ptr_index = 0; | |
1916 uint32_t tmss_min_alloc = 16 * 1024; | |
1400 for (int i = 0; i < rom->map_chunks; i++) | 1917 for (int i = 0; i < rom->map_chunks; i++) |
1401 { | 1918 { |
1402 if (rom->map[i].start == 0xE00000) { | 1919 if (rom->map[i].start == 0xE00000) { |
1403 rom->map[i].buffer = gen->work_ram; | 1920 rom->map[i].buffer = gen->work_ram; |
1404 break; | 1921 if (!tmss) { |
1405 } | 1922 break; |
1923 } | |
1924 } | |
1925 if (rom->map[i].flags & MMAP_PTR_IDX && rom->map[i].ptr_index >= next_ptr_index) { | |
1926 next_ptr_index = rom->map[i].ptr_index + 1; | |
1927 } | |
1928 if (rom->map[i].start < 0x400000 && rom->map[i].read_16 != unused_read) { | |
1929 uint32_t highest_offset = (rom->map[i].end & rom->map[i].mask) + 1; | |
1930 if (highest_offset > tmss_min_alloc) { | |
1931 tmss_min_alloc = highest_offset; | |
1932 } | |
1933 } | |
1934 } | |
1935 if (tmss) { | |
1936 char *tmss_path = tern_find_path_default(config, "system\0tmss_path\0", (tern_val){.ptrval = "tmss.md"}, TVAL_PTR).ptrval; | |
1937 uint8_t *buffer = malloc(tmss_min_alloc); | |
1938 uint32_t tmss_size; | |
1939 if (is_absolute_path(tmss_path)) { | |
1940 FILE *f = fopen(tmss_path, "rb"); | |
1941 if (!f) { | |
1942 fatal_error("Configured to use a model with TMSS, but failed to load the TMSS ROM from %s\n", tmss_path); | |
1943 } | |
1944 tmss_size = fread(buffer, 1, tmss_min_alloc, f); | |
1945 fclose(f); | |
1946 } else { | |
1947 char *tmp = read_bundled_file(tmss_path, &tmss_size); | |
1948 if (!tmp) { | |
1949 fatal_error("Configured to use a model with TMSS, but failed to load the TMSS ROM from %s\n", tmss_path); | |
1950 } | |
1951 memcpy(buffer, tmp, tmss_size); | |
1952 free(tmp); | |
1953 } | |
1954 for (uint32_t padded = nearest_pow2(tmss_size); tmss_size < padded; tmss_size++) | |
1955 { | |
1956 buffer[tmss_size] = 0xFF; | |
1957 } | |
1958 #ifndef BLASTEM_BIG_ENDIAN | |
1959 byteswap_rom(tmss_size, (uint16_t *)buffer); | |
1960 #endif | |
1961 //mirror TMSS ROM until we fill up to tmss_min_alloc | |
1962 for (uint32_t dst = tmss_size; dst < tmss_min_alloc; dst += tmss_size) | |
1963 { | |
1964 memcpy(buffer + dst, buffer, dst + tmss_size > tmss_min_alloc ? tmss_min_alloc - dst : tmss_size); | |
1965 } | |
1966 //modify mappings for ROM space to point to the TMSS ROM and fixup flags to allow switching back and forth | |
1967 //WARNING: This code makes some pretty big assumptions about the kinds of map chunks it will encounter | |
1968 for (int i = 0; i < rom->map_chunks; i++) | |
1969 { | |
1970 if (rom->map[i].start < 0x400000 && rom->map[i].read_16 != unused_read) { | |
1971 if (rom->map[i].flags == MMAP_READ) { | |
1972 //Normal ROM | |
1973 rom->map[i].flags |= MMAP_PTR_IDX | MMAP_CODE; | |
1974 rom->map[i].ptr_index = next_ptr_index++; | |
1975 if (rom->map[i].ptr_index >= NUM_MEM_AREAS) { | |
1976 fatal_error("Too many memmap chunks with MMAP_PTR_IDX after TMSS remap\n"); | |
1977 } | |
1978 gen->tmss_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; | |
1979 rom->map[i].buffer = buffer + (rom->map[i].start & ~rom->map[i].mask & (tmss_size - 1)); | |
1980 } else if (rom->map[i].flags & MMAP_PTR_IDX) { | |
1981 //Sega mapper page or multi-game mapper | |
1982 gen->tmss_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; | |
1983 rom->map[i].buffer = buffer + (rom->map[i].start & ~rom->map[i].mask & (tmss_size - 1)); | |
1984 if (rom->map[i].write_16) { | |
1985 if (!gen->tmss_write_16) { | |
1986 gen->tmss_write_16 = rom->map[i].write_16; | |
1987 gen->tmss_write_8 = rom->map[i].write_8; | |
1988 rom->map[i].write_16 = tmss_rom_write_16; | |
1989 rom->map[i].write_8 = tmss_rom_write_8; | |
1990 } else if (gen->tmss_write_16 == rom->map[i].write_16) { | |
1991 rom->map[i].write_16 = tmss_rom_write_16; | |
1992 rom->map[i].write_8 = tmss_rom_write_8; | |
1993 } else { | |
1994 warning("Chunk starting at %X has a write function, but we've already stored a different one for TMSS remap\n", rom->map[i].start); | |
1995 } | |
1996 } | |
1997 } else if ((rom->map[i].flags & (MMAP_READ | MMAP_WRITE)) == (MMAP_READ | MMAP_WRITE)) { | |
1998 //RAM or SRAM | |
1999 rom->map[i].flags |= MMAP_PTR_IDX; | |
2000 rom->map[i].ptr_index = next_ptr_index++; | |
2001 gen->tmss_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; | |
2002 rom->map[i].buffer = buffer + (rom->map[i].start & ~rom->map[i].mask & (tmss_size - 1)); | |
2003 if (!gen->tmss_write_offset || gen->tmss_write_offset == rom->map[i].start) { | |
2004 gen->tmss_write_offset = rom->map[i].start; | |
2005 rom->map[i].flags &= ~MMAP_WRITE; | |
2006 if (rom->map[i].flags & MMAP_ONLY_ODD) { | |
2007 rom->map[i].write_16 = tmss_odd_write_16; | |
2008 rom->map[i].write_8 = tmss_odd_write_8; | |
2009 } else if (rom->map[i].flags & MMAP_ONLY_EVEN) { | |
2010 rom->map[i].write_16 = tmss_even_write_16; | |
2011 rom->map[i].write_8 = tmss_even_write_8; | |
2012 } else { | |
2013 rom->map[i].write_16 = tmss_word_write_16; | |
2014 rom->map[i].write_8 = tmss_word_write_8; | |
2015 } | |
2016 } else { | |
2017 warning("Could not remap writes for chunk starting at %X for TMSS because write_offset is %X\n", rom->map[i].start, gen->tmss_write_offset); | |
2018 } | |
2019 } else if (rom->map[i].flags & MMAP_READ_CODE) { | |
2020 //NOR flash | |
2021 rom->map[i].flags |= MMAP_PTR_IDX; | |
2022 rom->map[i].ptr_index = next_ptr_index++; | |
2023 if (rom->map[i].ptr_index >= NUM_MEM_AREAS) { | |
2024 fatal_error("Too many memmap chunks with MMAP_PTR_IDX after TMSS remap\n"); | |
2025 } | |
2026 gen->tmss_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; | |
2027 rom->map[i].buffer = buffer + (rom->map[i].start & ~rom->map[i].mask & (tmss_size - 1)); | |
2028 if (!gen->tmss_write_16) { | |
2029 gen->tmss_write_16 = rom->map[i].write_16; | |
2030 gen->tmss_write_8 = rom->map[i].write_8; | |
2031 gen->tmss_read_16 = rom->map[i].read_16; | |
2032 gen->tmss_read_8 = rom->map[i].read_8; | |
2033 rom->map[i].write_16 = tmss_rom_write_16; | |
2034 rom->map[i].write_8 = tmss_rom_write_8; | |
2035 rom->map[i].read_16 = tmss_rom_read_16; | |
2036 rom->map[i].read_8 = tmss_rom_read_8; | |
2037 } else if (gen->tmss_write_16 == rom->map[i].write_16) { | |
2038 rom->map[i].write_16 = tmss_rom_write_16; | |
2039 rom->map[i].write_8 = tmss_rom_write_8; | |
2040 rom->map[i].read_16 = tmss_rom_read_16; | |
2041 rom->map[i].read_8 = tmss_rom_read_8; | |
2042 } else { | |
2043 warning("Chunk starting at %X has a write function, but we've already stored a different one for TMSS remap\n", rom->map[i].start); | |
2044 } | |
2045 } else { | |
2046 warning("Didn't remap chunk starting at %X for TMSS because it has flags %X\n", rom->map[i].start, rom->map[i].flags); | |
2047 } | |
2048 } | |
2049 } | |
2050 gen->tmss_buffer = buffer; | |
1406 } | 2051 } |
1407 | 2052 |
1408 m68k_options *opts = malloc(sizeof(m68k_options)); | 2053 m68k_options *opts = malloc(sizeof(m68k_options)); |
1409 init_m68k_opts(opts, rom->map, rom->map_chunks, MCLKS_PER_68K); | 2054 init_m68k_opts(opts, rom->map, rom->map_chunks, MCLKS_PER_68K); |
1410 //TODO: make this configurable | 2055 if (!strcmp(tern_find_ptr_default(model, "tas", "broken"), "broken")) { |
1411 opts->gen.flags |= M68K_OPT_BROKEN_READ_MODIFY; | 2056 opts->gen.flags |= M68K_OPT_BROKEN_READ_MODIFY; |
2057 } | |
1412 gen->m68k = init_68k_context(opts, NULL); | 2058 gen->m68k = init_68k_context(opts, NULL); |
1413 gen->m68k->system = gen; | 2059 gen->m68k->system = gen; |
1414 opts->address_log = (system_opts & OPT_ADDRESS_LOG) ? fopen("address.log", "w") : NULL; | 2060 opts->address_log = (system_opts & OPT_ADDRESS_LOG) ? fopen("address.log", "w") : NULL; |
1415 | 2061 |
1416 //This must happen after the 68K context has been allocated | 2062 //This must happen after the 68K context has been allocated |
1417 for (int i = 0; i < rom->map_chunks; i++) | 2063 for (int i = 0; i < rom->map_chunks; i++) |
1418 { | 2064 { |
1419 if (rom->map[i].flags & MMAP_PTR_IDX) { | 2065 if (rom->map[i].flags & MMAP_PTR_IDX) { |
1420 gen->m68k->mem_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; | 2066 gen->m68k->mem_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; |
1421 } | 2067 } |
1422 } | 2068 } |
1423 | 2069 |
1424 if (gen->mapper_type == MAPPER_SEGA) { | 2070 if (gen->mapper_type == MAPPER_SEGA) { |
1425 //initialize bank registers | 2071 //initialize bank registers |
1426 for (int i = 1; i < sizeof(gen->bank_regs); i++) | 2072 for (int i = 1; i < sizeof(gen->bank_regs); i++) |
1427 { | 2073 { |
1428 gen->bank_regs[i] = i; | 2074 gen->bank_regs[i] = i; |
1429 } | 2075 } |
1430 } | 2076 } |
2077 gen->reset_cycle = CYCLE_NEVER; | |
1431 | 2078 |
1432 return gen; | 2079 return gen; |
1433 } | 2080 } |
1434 | 2081 |
1435 static memmap_chunk base_map[] = { | 2082 static memmap_chunk base_map[] = { |
1436 {0xE00000, 0x1000000, 0xFFFF, 0, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, NULL, | 2083 {0xE00000, 0x1000000, 0xFFFF, 0, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, NULL, |
1437 NULL, NULL, NULL, NULL}, | 2084 NULL, NULL, NULL, NULL}, |
1438 {0xC00000, 0xE00000, 0x1FFFFF, 0, 0, 0, NULL, | 2085 {0xC00000, 0xE00000, 0x1FFFFF, 0, 0, 0, NULL, |
1439 (read_16_fun)vdp_port_read, (write_16_fun)vdp_port_write, | 2086 (read_16_fun)vdp_port_read, (write_16_fun)vdp_port_write, |
1440 (read_8_fun)vdp_port_read_b, (write_8_fun)vdp_port_write_b}, | 2087 (read_8_fun)vdp_port_read_b, (write_8_fun)vdp_port_write_b}, |
1441 {0xA00000, 0xA12000, 0x1FFFF, 0, 0, 0, NULL, | 2088 {0xA00000, 0xA12000, 0x1FFFF, 0, 0, 0, NULL, |
1442 (read_16_fun)io_read_w, (write_16_fun)io_write_w, | 2089 (read_16_fun)io_read_w, (write_16_fun)io_write_w, |
1443 (read_8_fun)io_read, (write_8_fun)io_write} | 2090 (read_8_fun)io_read, (write_8_fun)io_write}, |
1444 }; | 2091 {0x000000, 0xFFFFFF, 0xFFFFFF, 0, 0, 0, NULL, |
1445 const size_t base_chunks = sizeof(base_map)/sizeof(*base_map); | 2092 (read_16_fun)unused_read, (write_16_fun)unused_write, |
2093 (read_8_fun)unused_read_b, (write_8_fun)unused_write_b} | |
2094 }; | |
2095 const size_t base_chunks = sizeof(base_map)/sizeof(*base_map); | |
1446 | 2096 |
1447 genesis_context *alloc_config_genesis(void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, uint32_t ym_opts, uint8_t force_region) | 2097 genesis_context *alloc_config_genesis(void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, uint32_t ym_opts, uint8_t force_region) |
1448 { | 2098 { |
1449 tern_node *rom_db = get_rom_db(); | 2099 tern_node *rom_db = get_rom_db(); |
1450 rom_info info = configure_rom(rom_db, rom, rom_size, lock_on, lock_on_size, base_map, base_chunks); | 2100 rom_info info = configure_rom(rom_db, rom, rom_size, lock_on, lock_on_size, base_map, base_chunks); |
1469 | 2119 |
1470 genesis_context *alloc_config_genesis_cdboot(system_media *media, uint32_t system_opts, uint8_t force_region) | 2120 genesis_context *alloc_config_genesis_cdboot(system_media *media, uint32_t system_opts, uint8_t force_region) |
1471 { | 2121 { |
1472 tern_node *rom_db = get_rom_db(); | 2122 tern_node *rom_db = get_rom_db(); |
1473 rom_info info = configure_rom(rom_db, media->buffer, media->size, NULL, 0, base_map, base_chunks); | 2123 rom_info info = configure_rom(rom_db, media->buffer, media->size, NULL, 0, base_map, base_chunks); |
1474 | 2124 |
1475 segacd_context *cd = alloc_configure_segacd(media, system_opts, force_region, &info); | 2125 segacd_context *cd = alloc_configure_segacd(media, system_opts, force_region, &info); |
1476 genesis_context *gen = shared_init(system_opts, &info, force_region); | 2126 genesis_context *gen = shared_init(system_opts, &info, force_region); |
1477 gen->cart = gen->lock_on = NULL; | 2127 gen->cart = gen->lock_on = NULL; |
1478 gen->save_storage = NULL; | 2128 gen->save_storage = NULL; |
1479 gen->save_type = SAVE_NONE; | 2129 gen->save_type = SAVE_NONE; |
1480 gen->version_reg &= ~NO_DISK; | 2130 gen->version_reg &= ~NO_DISK; |
1481 | 2131 |
1482 gen->expansion = cd; | 2132 gen->expansion = cd; |
1483 setup_io_devices(config, &info, &gen->io); | 2133 setup_io_devices(config, &info, &gen->io); |
1484 | 2134 |
1485 uint32_t cd_chunks; | 2135 uint32_t cd_chunks; |
1486 memmap_chunk *cd_map = segacd_main_cpu_map(gen->expansion, &cd_chunks); | 2136 memmap_chunk *cd_map = segacd_main_cpu_map(gen->expansion, &cd_chunks); |
1487 memmap_chunk *map = malloc(sizeof(memmap_chunk) * (cd_chunks + base_chunks)); | 2137 memmap_chunk *map = malloc(sizeof(memmap_chunk) * (cd_chunks + base_chunks)); |
1488 memcpy(map, cd_map, sizeof(memmap_chunk) * cd_chunks); | 2138 memcpy(map, cd_map, sizeof(memmap_chunk) * cd_chunks); |
1489 memcpy(map + cd_chunks, base_map, sizeof(memmap_chunk) * base_chunks); | 2139 memcpy(map + cd_chunks, base_map, sizeof(memmap_chunk) * base_chunks); |
1490 map[cd_chunks].buffer = gen->work_ram; | 2140 map[cd_chunks].buffer = gen->work_ram; |
1491 uint32_t num_chunks = cd_chunks + base_chunks; | 2141 uint32_t num_chunks = cd_chunks + base_chunks; |
1492 | 2142 |
1493 m68k_options *opts = malloc(sizeof(m68k_options)); | 2143 m68k_options *opts = malloc(sizeof(m68k_options)); |
1494 init_m68k_opts(opts, map, num_chunks, MCLKS_PER_68K); | 2144 init_m68k_opts(opts, map, num_chunks, MCLKS_PER_68K); |
1495 //TODO: make this configurable | 2145 //TODO: make this configurable |
1496 opts->gen.flags |= M68K_OPT_BROKEN_READ_MODIFY; | 2146 opts->gen.flags |= M68K_OPT_BROKEN_READ_MODIFY; |
1497 gen->m68k = init_68k_context(opts, NULL); | 2147 gen->m68k = init_68k_context(opts, NULL); |
1498 gen->m68k->system = gen; | 2148 gen->m68k->system = gen; |
1499 opts->address_log = (system_opts & OPT_ADDRESS_LOG) ? fopen("address.log", "w") : NULL; | 2149 opts->address_log = (system_opts & OPT_ADDRESS_LOG) ? fopen("address.log", "w") : NULL; |
1500 | 2150 |
1501 //This must happen after the 68K context has been allocated | 2151 //This must happen after the 68K context has been allocated |
1502 for (int i = 0; i < num_chunks; i++) | 2152 for (int i = 0; i < num_chunks; i++) |
1503 { | 2153 { |
1504 if (map[i].flags & MMAP_PTR_IDX) { | 2154 if (map[i].flags & MMAP_PTR_IDX) { |
1505 gen->m68k->mem_pointers[map[i].ptr_index] = map[i].buffer; | 2155 gen->m68k->mem_pointers[map[i].ptr_index] = map[i].buffer; |