Mercurial > repos > blastem
comparison blastem.c @ 744:fc68992cf18d
Merge windows branch with latest changes
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Thu, 28 May 2015 21:19:55 -0700 |
parents | 535e97bad27f |
children | 296ddfcf0d43 |
comparison
equal
deleted
inserted
replaced
743:cf78cb045fa4 | 744:fc68992cf18d |
---|---|
31 #define LINES_NTSC 262 | 31 #define LINES_NTSC 262 |
32 #define LINES_PAL 312 | 32 #define LINES_PAL 312 |
33 | 33 |
34 #define MAX_SOUND_CYCLES 100000 | 34 #define MAX_SOUND_CYCLES 100000 |
35 | 35 |
36 uint32_t mclks_per_frame = MCLKS_LINE*LINES_NTSC; | |
37 | |
38 uint16_t cart[CARTRIDGE_WORDS]; | 36 uint16_t cart[CARTRIDGE_WORDS]; |
39 uint16_t ram[RAM_WORDS]; | 37 uint16_t ram[RAM_WORDS]; |
40 uint8_t z80_ram[Z80_RAM_BYTES]; | 38 uint8_t z80_ram[Z80_RAM_BYTES]; |
41 | 39 |
42 int headless = 0; | 40 int headless = 0; |
123 } | 121 } |
124 //TODO: Figure out what happens when you try to DMA from weird adresses like IO or banked Z80 area | 122 //TODO: Figure out what happens when you try to DMA from weird adresses like IO or banked Z80 area |
125 return 0; | 123 return 0; |
126 } | 124 } |
127 | 125 |
128 //TODO: Make these dependent on the video mode | |
129 //#define VINT_CYCLE ((MCLKS_LINE * 225 + (148 + 40) * 4)/MCLKS_PER_68K) | |
130 #define ZVINT_CYCLE ((MCLKS_LINE * 225 + (148 + 40) * 4)/MCLKS_PER_Z80) | |
131 //#define VINT_CYCLE ((MCLKS_LINE * 226)/MCLKS_PER_68K) | |
132 //#define ZVINT_CYCLE ((MCLKS_LINE * 226)/MCLKS_PER_Z80) | |
133 | |
134 void adjust_int_cycle(m68k_context * context, vdp_context * v_context) | 126 void adjust_int_cycle(m68k_context * context, vdp_context * v_context) |
135 { | 127 { |
128 //static int old_int_cycle = CYCLE_NEVER; | |
129 genesis_context *gen = context->system; | |
130 if (context->sync_cycle - context->current_cycle > gen->max_cycles) { | |
131 context->sync_cycle = context->current_cycle + gen->max_cycles; | |
132 } | |
136 context->int_cycle = CYCLE_NEVER; | 133 context->int_cycle = CYCLE_NEVER; |
137 if ((context->status & 0x7) < 6) { | 134 if ((context->status & 0x7) < 6) { |
138 uint32_t next_vint = vdp_next_vint(v_context); | 135 uint32_t next_vint = vdp_next_vint(v_context); |
139 if (next_vint != CYCLE_NEVER) { | 136 if (next_vint != CYCLE_NEVER) { |
140 next_vint /= MCLKS_PER_68K; | |
141 context->int_cycle = next_vint; | 137 context->int_cycle = next_vint; |
142 context->int_num = 6; | 138 context->int_num = 6; |
143 } | 139 } |
144 if ((context->status & 0x7) < 4) { | 140 if ((context->status & 0x7) < 4) { |
145 uint32_t next_hint = vdp_next_hint(v_context); | 141 uint32_t next_hint = vdp_next_hint(v_context); |
146 if (next_hint != CYCLE_NEVER) { | 142 if (next_hint != CYCLE_NEVER) { |
147 next_hint /= MCLKS_PER_68K; | |
148 if (next_hint < context->int_cycle) { | 143 if (next_hint < context->int_cycle) { |
149 context->int_cycle = next_hint; | 144 context->int_cycle = next_hint; |
150 context->int_num = 4; | 145 context->int_num = 4; |
151 | 146 |
152 } | 147 } |
153 } | 148 } |
154 } | 149 } |
155 } | 150 } |
151 /*if (context->int_cycle != old_int_cycle) { | |
152 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); | |
153 old_int_cycle = context->int_cycle; | |
154 }*/ | |
156 | 155 |
157 context->target_cycle = context->int_cycle < context->sync_cycle ? context->int_cycle : context->sync_cycle; | 156 context->target_cycle = context->int_cycle < context->sync_cycle ? context->int_cycle : context->sync_cycle; |
158 /*printf("Cyc: %d, Trgt: %d, Int Cyc: %d, Int: %d, Mask: %X, V: %d, H: %d, HICount: %d, HReg: %d, Line: %d\n", | 157 /*printf("Cyc: %d, Trgt: %d, Int Cyc: %d, Int: %d, Mask: %X, V: %d, H: %d, HICount: %d, HReg: %d, Line: %d\n", |
159 context->current_cycle, context->target_cycle, context->int_cycle, context->int_num, (context->status & 0x7), | 158 context->current_cycle, context->target_cycle, context->int_cycle, context->int_num, (context->status & 0x7), |
160 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);*/ | 159 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);*/ |
161 } | 160 } |
162 | 161 |
163 int break_on_sync = 0; | 162 int break_on_sync = 0; |
164 int save_state = 0; | 163 int save_state = 0; |
165 | 164 |
166 uint8_t reset = 1; | |
167 uint8_t need_reset = 0; | |
168 uint8_t busreq = 0; | |
169 uint8_t busack = 0; | |
170 uint32_t busack_cycle = CYCLE_NEVER; | |
171 uint8_t new_busack = 0; | |
172 //#define DO_DEBUG_PRINT | 165 //#define DO_DEBUG_PRINT |
173 #ifdef DO_DEBUG_PRINT | 166 #ifdef DO_DEBUG_PRINT |
174 #define dprintf printf | 167 #define dprintf printf |
175 #define dputs puts | 168 #define dputs puts |
176 #else | 169 #else |
178 #define dputs | 171 #define dputs |
179 #endif | 172 #endif |
180 | 173 |
181 #define Z80_VINT_DURATION 128 | 174 #define Z80_VINT_DURATION 128 |
182 | 175 |
176 void z80_next_int_pulse(z80_context * z_context) | |
177 { | |
178 genesis_context * gen = z_context->system; | |
179 z_context->int_pulse_start = vdp_next_vint_z80(gen->vdp); | |
180 z_context->int_pulse_end = z_context->int_pulse_start + Z80_VINT_DURATION * MCLKS_PER_Z80; | |
181 } | |
182 | |
183 void sync_z80(z80_context * z_context, uint32_t mclks) | 183 void sync_z80(z80_context * z_context, uint32_t mclks) |
184 { | 184 { |
185 #ifndef NO_Z80 | 185 #ifndef NO_Z80 |
186 if (z80_enabled && !reset && !busreq) { | 186 if (z80_enabled) { |
187 genesis_context * gen = z_context->system; | 187 z80_run(z_context, mclks); |
188 z_context->sync_cycle = mclks / MCLKS_PER_Z80; | |
189 if (z_context->current_cycle < z_context->sync_cycle) { | |
190 if (need_reset) { | |
191 z80_reset(z_context); | |
192 need_reset = 0; | |
193 } | |
194 uint32_t vint_cycle = vdp_next_vint_z80(gen->vdp) / MCLKS_PER_Z80; | |
195 while (z_context->current_cycle < z_context->sync_cycle) { | |
196 if (z_context->iff1 && z_context->current_cycle < (vint_cycle + Z80_VINT_DURATION)) { | |
197 z_context->int_cycle = vint_cycle < z_context->int_enable_cycle ? z_context->int_enable_cycle : vint_cycle; | |
198 } | |
199 z_context->target_cycle = z_context->sync_cycle < z_context->int_cycle ? z_context->sync_cycle : z_context->int_cycle; | |
200 dprintf("Running Z80 from cycle %d to cycle %d. Native PC: %p\n", z_context->current_cycle, z_context->sync_cycle, z_context->native_pc); | |
201 z80_run(z_context); | |
202 dprintf("Z80 ran to cycle %d\n", z_context->current_cycle); | |
203 } | |
204 } | |
205 } else | 188 } else |
206 #endif | 189 #endif |
207 { | 190 { |
208 z_context->current_cycle = mclks / MCLKS_PER_Z80; | 191 z_context->current_cycle = mclks; |
209 } | 192 } |
210 } | 193 } |
211 | 194 |
212 void sync_sound(genesis_context * gen, uint32_t target) | 195 void sync_sound(genesis_context * gen, uint32_t target) |
213 { | 196 { |
223 ym_run(gen->ym, target); | 206 ym_run(gen->ym, target); |
224 | 207 |
225 //printf("Target: %d, YM bufferpos: %d, PSG bufferpos: %d\n", target, gen->ym->buffer_pos, gen->psg->buffer_pos * 2); | 208 //printf("Target: %d, YM bufferpos: %d, PSG bufferpos: %d\n", target, gen->ym->buffer_pos, gen->psg->buffer_pos * 2); |
226 } | 209 } |
227 | 210 |
228 uint32_t frame=0; | 211 uint32_t last_frame_num; |
229 m68k_context * sync_components(m68k_context * context, uint32_t address) | 212 m68k_context * sync_components(m68k_context * context, uint32_t address) |
230 { | 213 { |
231 //TODO: Handle sync targets smaller than a single frame | |
232 genesis_context * gen = context->system; | 214 genesis_context * gen = context->system; |
233 vdp_context * v_context = gen->vdp; | 215 vdp_context * v_context = gen->vdp; |
234 z80_context * z_context = gen->z80; | 216 z80_context * z_context = gen->z80; |
235 uint32_t mclks = context->current_cycle * MCLKS_PER_68K; | 217 uint32_t mclks = context->current_cycle; |
236 sync_z80(z_context, mclks); | 218 sync_z80(z_context, mclks); |
237 if (mclks >= mclks_per_frame) { | 219 sync_sound(gen, mclks); |
220 while (context->current_cycle > mclks) { | |
221 mclks = context->current_cycle; | |
222 sync_z80(z_context, mclks); | |
238 sync_sound(gen, mclks); | 223 sync_sound(gen, mclks); |
239 gen->ym->current_cycle -= mclks_per_frame; | 224 } |
240 gen->psg->cycles -= mclks_per_frame; | 225 vdp_run_context(v_context, mclks); |
241 if (gen->ym->write_cycle != CYCLE_NEVER) { | 226 if (v_context->frame != last_frame_num) { |
242 gen->ym->write_cycle = gen->ym->write_cycle >= mclks_per_frame/MCLKS_PER_68K ? gen->ym->write_cycle - mclks_per_frame/MCLKS_PER_68K : 0; | 227 //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); |
243 } | 228 last_frame_num = v_context->frame; |
244 //printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, mclks); | |
245 vdp_run_context(v_context, mclks_per_frame); | |
246 | 229 |
247 if (!headless) { | 230 if (!headless) { |
248 break_on_sync |= wait_render_frame(v_context, frame_limit); | 231 break_on_sync |= wait_render_frame(v_context, frame_limit); |
249 } else if(exit_after){ | 232 } else if(exit_after){ |
250 --exit_after; | 233 --exit_after; |
251 if (!exit_after) { | 234 if (!exit_after) { |
252 exit(0); | 235 exit(0); |
253 } | 236 } |
254 } | 237 } |
255 frame++; | 238 |
256 mclks -= mclks_per_frame; | 239 vdp_adjust_cycles(v_context, mclks); |
257 vdp_adjust_cycles(v_context, mclks_per_frame); | 240 io_adjust_cycles(gen->ports, context->current_cycle, mclks); |
258 io_adjust_cycles(gen->ports, context->current_cycle, mclks_per_frame/MCLKS_PER_68K); | 241 io_adjust_cycles(gen->ports+1, context->current_cycle, mclks); |
259 io_adjust_cycles(gen->ports+1, context->current_cycle, mclks_per_frame/MCLKS_PER_68K); | 242 io_adjust_cycles(gen->ports+2, context->current_cycle, mclks); |
260 io_adjust_cycles(gen->ports+2, context->current_cycle, mclks_per_frame/MCLKS_PER_68K); | 243 context->current_cycle -= mclks; |
261 if (busack_cycle != CYCLE_NEVER) { | 244 z80_adjust_cycles(z_context, mclks); |
262 if (busack_cycle > mclks_per_frame/MCLKS_PER_68K) { | 245 gen->ym->current_cycle -= mclks; |
263 busack_cycle -= mclks_per_frame/MCLKS_PER_68K; | 246 gen->psg->cycles -= mclks; |
264 } else { | 247 if (gen->ym->write_cycle != CYCLE_NEVER) { |
265 busack_cycle = CYCLE_NEVER; | 248 gen->ym->write_cycle = gen->ym->write_cycle >= mclks ? gen->ym->write_cycle - mclks : 0; |
266 busack = new_busack; | 249 } |
267 } | 250 } |
268 } | 251 gen->frame_end = vdp_cycles_to_frame_end(v_context); |
269 context->current_cycle -= mclks_per_frame/MCLKS_PER_68K; | 252 context->sync_cycle = gen->frame_end; |
270 if (z_context->current_cycle >= mclks_per_frame/MCLKS_PER_Z80) { | 253 //printf("Set sync cycle to: %d @ %d, vcounter: %d, hslot: %d\n", context->sync_cycle, context->current_cycle, v_context->vcounter, v_context->hslot); |
271 z_context->current_cycle -= mclks_per_frame/MCLKS_PER_Z80; | |
272 } else { | |
273 z_context->current_cycle = 0; | |
274 } | |
275 if (mclks) { | |
276 vdp_run_context(v_context, mclks); | |
277 } | |
278 } else { | |
279 //printf("running VDP for %d cycles\n", mclks - v_context->cycles); | |
280 vdp_run_context(v_context, mclks); | |
281 sync_sound(gen, mclks); | |
282 } | |
283 if (context->int_ack) { | 254 if (context->int_ack) { |
255 //printf("acknowledging %d @ %d:%d, vcounter: %d, hslot: %d\n", context->int_ack, context->current_cycle, v_context->cycles, v_context->vcounter, v_context->hslot); | |
284 vdp_int_ack(v_context, context->int_ack); | 256 vdp_int_ack(v_context, context->int_ack); |
285 context->int_ack = 0; | 257 context->int_ack = 0; |
258 } | |
259 if (!address && (break_on_sync || save_state)) { | |
260 context->sync_cycle = context->current_cycle + 1; | |
286 } | 261 } |
287 adjust_int_cycle(context, v_context); | 262 adjust_int_cycle(context, v_context); |
288 if (address) { | 263 if (address) { |
289 if (break_on_sync) { | 264 if (break_on_sync) { |
290 break_on_sync = 0; | 265 break_on_sync = 0; |
291 debugger(context, address); | 266 debugger(context, address); |
292 } | 267 } |
293 if (save_state) { | 268 if (save_state && (z_context->pc || (!z_context->reset && !z_context->busreq))) { |
294 save_state = 0; | 269 save_state = 0; |
270 //advance Z80 core to the start of an instruction | |
295 while (!z_context->pc) | 271 while (!z_context->pc) |
296 { | 272 { |
297 sync_z80(z_context, z_context->current_cycle * MCLKS_PER_Z80 + MCLKS_PER_Z80); | 273 sync_z80(z_context, z_context->current_cycle + MCLKS_PER_Z80); |
298 } | 274 } |
299 save_gst(gen, "savestate.gst", address); | 275 save_gst(gen, "savestate.gst", address); |
276 puts("Saved state to savestate.gst"); | |
277 } else if(save_state) { | |
278 context->sync_cycle = context->current_cycle + 1; | |
300 } | 279 } |
301 } | 280 } |
302 return context; | 281 return context; |
303 } | 282 } |
304 | 283 |
315 genesis_context * gen = context->system; | 294 genesis_context * gen = context->system; |
316 if (vdp_port < 0x10) { | 295 if (vdp_port < 0x10) { |
317 int blocked; | 296 int blocked; |
318 uint32_t before_cycle = v_context->cycles; | 297 uint32_t before_cycle = v_context->cycles; |
319 if (vdp_port < 4) { | 298 if (vdp_port < 4) { |
320 gen->bus_busy = 1; | 299 |
321 while (vdp_data_port_write(v_context, value) < 0) { | 300 while (vdp_data_port_write(v_context, value) < 0) { |
322 while(v_context->flags & FLAG_DMA_RUN) { | 301 while(v_context->flags & FLAG_DMA_RUN) { |
323 vdp_run_dma_done(v_context, mclks_per_frame); | 302 vdp_run_dma_done(v_context, gen->frame_end); |
324 if (v_context->cycles >= mclks_per_frame) { | 303 if (v_context->cycles >= gen->frame_end) { |
325 context->current_cycle = v_context->cycles / MCLKS_PER_68K; | 304 context->current_cycle = v_context->cycles; |
326 if (context->current_cycle * MCLKS_PER_68K < mclks_per_frame) { | 305 gen->bus_busy = 1; |
327 ++context->current_cycle; | |
328 } | |
329 sync_components(context, 0); | 306 sync_components(context, 0); |
307 gen->bus_busy = 0; | |
330 } | 308 } |
331 } | 309 } |
332 //context->current_cycle = v_context->cycles / MCLKS_PER_68K; | 310 //context->current_cycle = v_context->cycles; |
333 } | 311 } |
334 } else if(vdp_port < 8) { | 312 } else if(vdp_port < 8) { |
335 gen->bus_busy = 1; | |
336 blocked = vdp_control_port_write(v_context, value); | 313 blocked = vdp_control_port_write(v_context, value); |
337 if (blocked) { | 314 if (blocked) { |
338 while (blocked) { | 315 while (blocked) { |
339 while(v_context->flags & FLAG_DMA_RUN) { | 316 while(v_context->flags & FLAG_DMA_RUN) { |
340 vdp_run_dma_done(v_context, mclks_per_frame); | 317 vdp_run_dma_done(v_context, gen->frame_end); |
341 if (v_context->cycles >= mclks_per_frame) { | 318 if (v_context->cycles >= gen->frame_end) { |
342 context->current_cycle = v_context->cycles / MCLKS_PER_68K; | 319 context->current_cycle = v_context->cycles; |
343 if (context->current_cycle * MCLKS_PER_68K < mclks_per_frame) { | 320 gen->bus_busy = 1; |
344 ++context->current_cycle; | |
345 } | |
346 sync_components(context, 0); | 321 sync_components(context, 0); |
322 gen->bus_busy = 0; | |
347 } | 323 } |
348 } | 324 } |
349 if (blocked < 0) { | 325 if (blocked < 0) { |
350 blocked = vdp_control_port_write(v_context, value); | 326 blocked = vdp_control_port_write(v_context, value); |
351 } else { | 327 } else { |
352 blocked = 0; | 328 blocked = 0; |
353 } | 329 } |
354 } | 330 } |
355 } else { | 331 } else { |
332 context->sync_cycle = gen->frame_end = vdp_cycles_to_frame_end(v_context); | |
333 //printf("Set sync cycle to: %d @ %d, vcounter: %d, hslot: %d\n", context->sync_cycle, context->current_cycle, v_context->vcounter, v_context->hslot); | |
356 adjust_int_cycle(context, v_context); | 334 adjust_int_cycle(context, v_context); |
357 } | 335 } |
358 } else { | 336 } else { |
359 printf("Illegal write to HV Counter port %X\n", vdp_port); | 337 printf("Illegal write to HV Counter port %X\n", vdp_port); |
360 exit(1); | 338 exit(1); |
361 } | 339 } |
362 if (v_context->cycles != before_cycle) { | 340 if (v_context->cycles != before_cycle) { |
363 //printf("68K paused for %d (%d) cycles at cycle %d (%d) for write\n", v_context->cycles / MCLKS_PER_68K - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle); | 341 //printf("68K paused for %d (%d) cycles at cycle %d (%d) for write\n", v_context->cycles - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle); |
364 context->current_cycle = v_context->cycles / MCLKS_PER_68K; | 342 context->current_cycle = v_context->cycles; |
343 //Lock the Z80 out of the bus until the VDP access is complete | |
344 gen->bus_busy = 1; | |
345 sync_z80(gen->z80, v_context->cycles); | |
346 gen->bus_busy = 0; | |
365 } | 347 } |
366 } else if (vdp_port < 0x18) { | 348 } else if (vdp_port < 0x18) { |
367 sync_sound(gen, context->current_cycle * MCLKS_PER_68K); | |
368 psg_write(gen->psg, value); | 349 psg_write(gen->psg, value); |
369 } else { | 350 } else { |
370 //TODO: Implement undocumented test register(s) | 351 //TODO: Implement undocumented test register(s) |
371 } | 352 } |
372 if (gen->bus_busy) | |
373 { | |
374 //Lock the Z80 out of the bus until the VDP access is complete | |
375 sync_z80(gen->z80, v_context->cycles); | |
376 gen->bus_busy = 0; | |
377 } | |
378 return context; | 353 return context; |
379 } | 354 } |
380 | 355 |
381 m68k_context * vdp_port_write_b(uint32_t vdp_port, m68k_context * context, uint8_t value) | 356 m68k_context * vdp_port_write_b(uint32_t vdp_port, m68k_context * context, uint8_t value) |
382 { | 357 { |
383 return vdp_port_write(vdp_port, context, vdp_port < 0x10 ? value | value << 8 : ((vdp_port & 1) ? value : 0)); | 358 return vdp_port_write(vdp_port, context, vdp_port < 0x10 ? value | value << 8 : ((vdp_port & 1) ? value : 0)); |
384 } | 359 } |
385 | 360 |
386 z80_context * z80_vdp_port_write(uint16_t vdp_port, z80_context * context, uint8_t value) | 361 void * z80_vdp_port_write(uint32_t vdp_port, void * vcontext, uint8_t value) |
387 { | 362 { |
363 z80_context * context = vcontext; | |
388 genesis_context * gen = context->system; | 364 genesis_context * gen = context->system; |
365 vdp_port &= 0xFF; | |
389 if (vdp_port & 0xE0) { | 366 if (vdp_port & 0xE0) { |
390 printf("machine freeze due to write to Z80 address %X\n", 0x7F00 | vdp_port); | 367 printf("machine freeze due to write to Z80 address %X\n", 0x7F00 | vdp_port); |
391 exit(1); | 368 exit(1); |
392 } | 369 } |
393 if (vdp_port < 0x10) { | 370 if (vdp_port < 0x10) { |
394 //These probably won't currently interact well with the 68K accessing the VDP | 371 //These probably won't currently interact well with the 68K accessing the VDP |
395 vdp_run_context(gen->vdp, context->current_cycle * MCLKS_PER_Z80); | 372 vdp_run_context(gen->vdp, context->current_cycle); |
396 if (vdp_port < 4) { | 373 if (vdp_port < 4) { |
397 vdp_data_port_write(gen->vdp, value << 8 | value); | 374 vdp_data_port_write(gen->vdp, value << 8 | value); |
398 } else if (vdp_port < 8) { | 375 } else if (vdp_port < 8) { |
399 vdp_control_port_write(gen->vdp, value << 8 | value); | 376 vdp_control_port_write(gen->vdp, value << 8 | value); |
400 } else { | 377 } else { |
401 printf("Illegal write to HV Counter port %X\n", vdp_port); | 378 printf("Illegal write to HV Counter port %X\n", vdp_port); |
402 exit(1); | 379 exit(1); |
403 } | 380 } |
404 } else if (vdp_port < 0x18) { | 381 } else if (vdp_port < 0x18) { |
405 sync_sound(gen, context->current_cycle * MCLKS_PER_Z80); | 382 sync_sound(gen, context->current_cycle); |
406 psg_write(gen->psg, value); | 383 psg_write(gen->psg, value); |
407 } else { | 384 } else { |
408 vdp_test_port_write(gen->vdp, value); | 385 vdp_test_port_write(gen->vdp, value); |
409 } | 386 } |
410 return context; | 387 return context; |
435 exit(1); | 412 exit(1); |
436 } else { | 413 } else { |
437 value = vdp_test_port_read(v_context); | 414 value = vdp_test_port_read(v_context); |
438 } | 415 } |
439 if (v_context->cycles != before_cycle) { | 416 if (v_context->cycles != before_cycle) { |
440 //printf("68K paused for %d (%d) cycles at cycle %d (%d) for read\n", v_context->cycles / MCLKS_PER_68K - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle); | 417 //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); |
441 context->current_cycle = v_context->cycles / MCLKS_PER_68K; | 418 context->current_cycle = v_context->cycles; |
419 //Lock the Z80 out of the bus until the VDP access is complete | |
420 genesis_context *gen = context->system; | |
421 gen->bus_busy = 1; | |
422 sync_z80(gen->z80, v_context->cycles); | |
423 gen->bus_busy = 0; | |
442 } | 424 } |
443 return value; | 425 return value; |
444 } | 426 } |
445 | 427 |
446 uint8_t vdp_port_read_b(uint32_t vdp_port, m68k_context * context) | 428 uint8_t vdp_port_read_b(uint32_t vdp_port, m68k_context * context) |
451 } else { | 433 } else { |
452 return value >> 8; | 434 return value >> 8; |
453 } | 435 } |
454 } | 436 } |
455 | 437 |
438 uint8_t z80_vdp_port_read(uint32_t vdp_port, void * vcontext) | |
439 { | |
440 z80_context * context = vcontext; | |
441 if (vdp_port & 0xE0) { | |
442 printf("machine freeze due to read from Z80 address %X\n", 0x7F00 | vdp_port); | |
443 exit(1); | |
444 } | |
445 genesis_context * gen = context->system; | |
446 //VDP access goes over the 68K bus like a bank area access | |
447 //typical delay from bus arbitration | |
448 context->current_cycle += 3 * MCLKS_PER_Z80; | |
449 //TODO: add cycle for an access right after a previous one | |
450 //TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high | |
451 // Needs a new logic analyzer capture to get the actual delay on the 68K side | |
452 gen->m68k->current_cycle += 8 * MCLKS_PER_68K; | |
453 | |
454 | |
455 vdp_port &= 0x1F; | |
456 uint16_t ret; | |
457 if (vdp_port < 0x10) { | |
458 //These probably won't currently interact well with the 68K accessing the VDP | |
459 vdp_run_context(gen->vdp, context->current_cycle); | |
460 if (vdp_port < 4) { | |
461 ret = vdp_data_port_read(gen->vdp); | |
462 } else if (vdp_port < 8) { | |
463 ret = vdp_control_port_read(gen->vdp); | |
464 } else { | |
465 printf("Illegal write to HV Counter port %X\n", vdp_port); | |
466 exit(1); | |
467 } | |
468 } else { | |
469 //TODO: Figure out the correct value today | |
470 ret = 0xFFFF; | |
471 } | |
472 return vdp_port & 1 ? ret : ret >> 8; | |
473 } | |
474 | |
456 uint32_t zram_counter = 0; | 475 uint32_t zram_counter = 0; |
457 #define Z80_ACK_DELAY 3 | |
458 #define Z80_BUSY_DELAY 1//TODO: Find the actual value for this | |
459 #define Z80_REQ_BUSY 1 | |
460 #define Z80_REQ_ACK 0 | |
461 #define Z80_RES_BUSACK reset | |
462 | 476 |
463 m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value) | 477 m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value) |
464 { | 478 { |
465 genesis_context * gen = context->system; | 479 genesis_context * gen = context->system; |
466 if (location < 0x10000) { | 480 if (location < 0x10000) { |
467 if (busack_cycle <= context->current_cycle) { | 481 if (!z80_enabled || z80_get_busack(gen->z80, context->current_cycle)) { |
468 busack = new_busack; | |
469 busack_cycle = CYCLE_NEVER; | |
470 } | |
471 if (!(busack || reset)) { | |
472 location &= 0x7FFF; | 482 location &= 0x7FFF; |
473 if (location < 0x4000) { | 483 if (location < 0x4000) { |
474 z80_ram[location & 0x1FFF] = value; | 484 z80_ram[location & 0x1FFF] = value; |
475 #ifndef NO_Z80 | 485 #ifndef NO_Z80 |
476 z80_handle_code_write(location & 0x1FFF, gen->z80); | 486 z80_handle_code_write(location & 0x1FFF, gen->z80); |
477 #endif | 487 #endif |
478 } else if (location < 0x6000) { | 488 } else if (location < 0x6000) { |
479 sync_sound(gen, context->current_cycle * MCLKS_PER_68K); | 489 sync_sound(gen, context->current_cycle); |
480 if (location & 1) { | 490 if (location & 1) { |
481 ym_data_write(gen->ym, value); | 491 ym_data_write(gen->ym, value); |
482 } else if(location & 2) { | 492 } else if(location & 2) { |
483 ym_address_write_part2(gen->ym, value); | 493 ym_address_write_part2(gen->ym, value); |
484 } else { | 494 } else { |
520 gen->ports[2].control = value; | 530 gen->ports[2].control = value; |
521 break; | 531 break; |
522 } | 532 } |
523 } else { | 533 } else { |
524 if (location == 0x1100) { | 534 if (location == 0x1100) { |
525 if (busack_cycle <= context->current_cycle) { | |
526 busack = new_busack; | |
527 busack_cycle = CYCLE_NEVER; | |
528 } | |
529 if (value & 1) { | 535 if (value & 1) { |
530 dputs("bus requesting Z80"); | 536 dputs("bus requesting Z80"); |
531 | 537 if (z80_enabled) { |
532 if(!reset && !busreq) { | 538 z80_assert_busreq(gen->z80, context->current_cycle); |
533 sync_z80(gen->z80, context->current_cycle * MCLKS_PER_68K + Z80_ACK_DELAY*MCLKS_PER_Z80); | 539 } else { |
534 busack_cycle = (gen->z80->current_cycle * MCLKS_PER_Z80) / MCLKS_PER_68K;//context->current_cycle + Z80_ACK_DELAY; | 540 gen->z80->busack = 1; |
535 new_busack = Z80_REQ_ACK; | |
536 } | 541 } |
537 busreq = 1; | |
538 } else { | 542 } else { |
539 sync_z80(gen->z80, context->current_cycle * MCLKS_PER_68K); | 543 if (gen->z80->busreq) { |
540 if (busreq) { | |
541 dputs("releasing z80 bus"); | 544 dputs("releasing z80 bus"); |
542 #ifdef DO_DEBUG_PRINT | 545 #ifdef DO_DEBUG_PRINT |
543 char fname[20]; | 546 char fname[20]; |
544 sprintf(fname, "zram-%d", zram_counter++); | 547 sprintf(fname, "zram-%d", zram_counter++); |
545 FILE * f = fopen(fname, "wb"); | 548 FILE * f = fopen(fname, "wb"); |
546 fwrite(z80_ram, 1, sizeof(z80_ram), f); | 549 fwrite(z80_ram, 1, sizeof(z80_ram), f); |
547 fclose(f); | 550 fclose(f); |
548 #endif | 551 #endif |
549 busack_cycle = ((gen->z80->current_cycle + Z80_BUSY_DELAY) * MCLKS_PER_Z80) / MCLKS_PER_68K; | |
550 new_busack = Z80_REQ_BUSY; | |
551 busreq = 0; | |
552 } | 552 } |
553 //busack_cycle = CYCLE_NEVER; | 553 if (z80_enabled) { |
554 //busack = Z80_REQ_BUSY; | 554 z80_clear_busreq(gen->z80, context->current_cycle); |
555 | 555 } else { |
556 gen->z80->busack = 0; | |
557 } | |
556 } | 558 } |
557 } else if (location == 0x1200) { | 559 } else if (location == 0x1200) { |
558 sync_z80(gen->z80, context->current_cycle * MCLKS_PER_68K); | 560 sync_z80(gen->z80, context->current_cycle); |
559 if (value & 1) { | 561 if (value & 1) { |
560 if (reset && busreq) { | 562 if (z80_enabled) { |
561 new_busack = 0; | 563 z80_clear_reset(gen->z80, context->current_cycle); |
562 busack_cycle = ((gen->z80->current_cycle + Z80_ACK_DELAY) * MCLKS_PER_Z80) / MCLKS_PER_68K;//context->current_cycle + Z80_ACK_DELAY; | 564 } else { |
565 gen->z80->reset = 0; | |
563 } | 566 } |
564 //TODO: Deal with the scenario in which reset is not asserted long enough | 567 } else { |
565 if (reset) { | 568 if (z80_enabled) { |
566 need_reset = 1; | 569 z80_assert_reset(gen->z80, context->current_cycle); |
567 //TODO: Add necessary delay between release of reset and start of execution | 570 } else { |
568 gen->z80->current_cycle = (context->current_cycle * MCLKS_PER_68K) / MCLKS_PER_Z80 + 16; | 571 gen->z80->reset = 1; |
569 } | 572 } |
570 reset = 0; | |
571 } else { | |
572 reset = 1; | |
573 } | 573 } |
574 } | 574 } |
575 } | 575 } |
576 } | 576 } |
577 return context; | 577 return context; |
595 uint8_t io_read(uint32_t location, m68k_context * context) | 595 uint8_t io_read(uint32_t location, m68k_context * context) |
596 { | 596 { |
597 uint8_t value; | 597 uint8_t value; |
598 genesis_context *gen = context->system; | 598 genesis_context *gen = context->system; |
599 if (location < 0x10000) { | 599 if (location < 0x10000) { |
600 if (busack_cycle <= context->current_cycle) { | 600 if (!z80_enabled || z80_get_busack(gen->z80, context->current_cycle)) { |
601 busack = new_busack; | |
602 busack_cycle = CYCLE_NEVER; | |
603 } | |
604 if (!(busack==Z80_REQ_BUSY || reset)) { | |
605 location &= 0x7FFF; | 601 location &= 0x7FFF; |
606 if (location < 0x4000) { | 602 if (location < 0x4000) { |
607 value = z80_ram[location & 0x1FFF]; | 603 value = z80_ram[location & 0x1FFF]; |
608 } else if (location < 0x6000) { | 604 } else if (location < 0x6000) { |
609 sync_sound(gen, context->current_cycle * MCLKS_PER_68K); | 605 sync_sound(gen, context->current_cycle); |
610 value = ym_read_status(gen->ym); | 606 value = ym_read_status(gen->ym); |
611 } else { | 607 } else { |
612 value = 0xFF; | 608 value = 0xFF; |
613 } | 609 } |
614 } else { | 610 } else { |
644 default: | 640 default: |
645 value = 0xFF; | 641 value = 0xFF; |
646 } | 642 } |
647 } else { | 643 } else { |
648 if (location == 0x1100) { | 644 if (location == 0x1100) { |
649 if (busack_cycle <= context->current_cycle) { | 645 value = z80_enabled ? !z80_get_busack(gen->z80, context->current_cycle) : !gen->z80->busack; |
650 busack = new_busack; | 646 dprintf("Byte read of BUSREQ returned %d @ %d (reset: %d)\n", value, context->current_cycle, gen->z80->reset); |
651 busack_cycle = CYCLE_NEVER; | |
652 } | |
653 value = Z80_RES_BUSACK || busack; | |
654 dprintf("Byte read of BUSREQ returned %d @ %d (reset: %d, busack: %d, busack_cycle %d)\n", value, context->current_cycle, reset, busack, busack_cycle); | |
655 } else if (location == 0x1200) { | 647 } else if (location == 0x1200) { |
656 value = !reset; | 648 value = !gen->z80->reset; |
657 } else { | 649 } else { |
658 value = 0xFF; | 650 value = 0xFF; |
659 printf("Byte read of unknown IO location: %X\n", location); | 651 printf("Byte read of unknown IO location: %X\n", location); |
660 } | 652 } |
661 } | 653 } |
672 value <<= 8; | 664 value <<= 8; |
673 } | 665 } |
674 return value; | 666 return value; |
675 } | 667 } |
676 | 668 |
677 z80_context * z80_write_ym(uint16_t location, z80_context * context, uint8_t value) | 669 void * z80_write_ym(uint32_t location, void * vcontext, uint8_t value) |
678 { | 670 { |
671 z80_context * context = vcontext; | |
679 genesis_context * gen = context->system; | 672 genesis_context * gen = context->system; |
680 sync_sound(gen, context->current_cycle * MCLKS_PER_Z80); | 673 sync_sound(gen, context->current_cycle); |
681 if (location & 1) { | 674 if (location & 1) { |
682 ym_data_write(gen->ym, value); | 675 ym_data_write(gen->ym, value); |
683 } else if (location & 2) { | 676 } else if (location & 2) { |
684 ym_address_write_part2(gen->ym, value); | 677 ym_address_write_part2(gen->ym, value); |
685 } else { | 678 } else { |
686 ym_address_write_part1(gen->ym, value); | 679 ym_address_write_part1(gen->ym, value); |
687 } | 680 } |
688 return context; | 681 return context; |
689 } | 682 } |
690 | 683 |
691 uint8_t z80_read_ym(uint16_t location, z80_context * context) | 684 uint8_t z80_read_ym(uint32_t location, void * vcontext) |
692 { | 685 { |
686 z80_context * context = vcontext; | |
693 genesis_context * gen = context->system; | 687 genesis_context * gen = context->system; |
694 sync_sound(gen, context->current_cycle * MCLKS_PER_Z80); | 688 sync_sound(gen, context->current_cycle); |
695 return ym_read_status(gen->ym); | 689 return ym_read_status(gen->ym); |
690 } | |
691 | |
692 uint8_t z80_read_bank(uint32_t location, void * vcontext) | |
693 { | |
694 z80_context * context = vcontext; | |
695 genesis_context *gen = context->system; | |
696 if (gen->bus_busy) { | |
697 context->current_cycle = context->sync_cycle; | |
698 } | |
699 //typical delay from bus arbitration | |
700 context->current_cycle += 3 * MCLKS_PER_Z80; | |
701 //TODO: add cycle for an access right after a previous one | |
702 //TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high | |
703 // Needs a new logic analyzer capture to get the actual delay on the 68K side | |
704 gen->m68k->current_cycle += 8 * MCLKS_PER_68K; | |
705 | |
706 location &= 0x7FFF; | |
707 if (context->mem_pointers[1]) { | |
708 return context->mem_pointers[1][location ^ 1]; | |
709 } | |
710 uint32_t address = context->bank_reg << 15 | location; | |
711 if (address >= 0xC00000 && address < 0xE00000) { | |
712 return z80_vdp_port_read(location & 0xFF, context); | |
713 } else { | |
714 fprintf(stderr, "Unhandled read by Z80 from address %X through banked memory area (%X)\n", address, context->bank_reg << 15); | |
715 } | |
716 return 0; | |
717 } | |
718 | |
719 void *z80_write_bank(uint32_t location, void * vcontext, uint8_t value) | |
720 { | |
721 z80_context * context = vcontext; | |
722 genesis_context *gen = context->system; | |
723 if (gen->bus_busy) { | |
724 context->current_cycle = context->sync_cycle; | |
725 } | |
726 //typical delay from bus arbitration | |
727 context->current_cycle += 3 * MCLKS_PER_Z80; | |
728 //TODO: add cycle for an access right after a previous one | |
729 //TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high | |
730 // Needs a new logic analyzer capture to get the actual delay on the 68K side | |
731 gen->m68k->current_cycle += 8 * MCLKS_PER_68K; | |
732 | |
733 location &= 0x7FFF; | |
734 uint32_t address = context->bank_reg << 15 | location; | |
735 if (address >= 0xE00000) { | |
736 address &= 0xFFFF; | |
737 ((uint8_t *)ram)[address ^ 1] = value; | |
738 } else if (address >= 0xC00000) { | |
739 z80_vdp_port_write(location & 0xFF, context, value); | |
740 } else { | |
741 fprintf(stderr, "Unhandled write by Z80 to address %X through banked memory area\n", address); | |
742 } | |
743 return context; | |
744 } | |
745 | |
746 void *z80_write_bank_reg(uint32_t location, void * vcontext, uint8_t value) | |
747 { | |
748 z80_context * context = vcontext; | |
749 | |
750 context->bank_reg = (context->bank_reg >> 1 | value << 8) & 0x1FF; | |
751 if (context->bank_reg < 0x80) { | |
752 genesis_context *gen = context->system; | |
753 context->mem_pointers[1] = get_native_pointer(context->bank_reg << 15, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen); | |
754 } else { | |
755 context->mem_pointers[1] = NULL; | |
756 } | |
757 | |
758 return context; | |
696 } | 759 } |
697 | 760 |
698 uint16_t read_sram_w(uint32_t address, m68k_context * context) | 761 uint16_t read_sram_w(uint32_t address, m68k_context * context) |
699 { | 762 { |
700 genesis_context * gen = context->system; | 763 genesis_context * gen = context->system; |
866 printf("Saved SRAM to %s\n", sram_filename); | 929 printf("Saved SRAM to %s\n", sram_filename); |
867 } | 930 } |
868 | 931 |
869 void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, uint8_t * debugger) | 932 void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, uint8_t * debugger) |
870 { | 933 { |
871 m68k_context context; | |
872 m68k_options opts; | 934 m68k_options opts; |
873 gen->m68k = &context; | |
874 memmap_chunk memmap[MAX_MAP_CHUNKS]; | 935 memmap_chunk memmap[MAX_MAP_CHUNKS]; |
875 uint32_t num_chunks; | 936 uint32_t num_chunks; |
876 void * initial_mapped = NULL; | 937 void * initial_mapped = NULL; |
877 gen->save_ram = NULL; | 938 gen->save_ram = NULL; |
878 //TODO: Handle carts larger than 4MB | 939 //TODO: Handle carts larger than 4MB |
961 printf("Loaded SRAM from %s\n", sram_filename); | 1022 printf("Loaded SRAM from %s\n", sram_filename); |
962 } | 1023 } |
963 } | 1024 } |
964 atexit(save_sram); | 1025 atexit(save_sram); |
965 } | 1026 } |
966 init_m68k_opts(&opts, memmap, num_chunks); | 1027 init_m68k_opts(&opts, memmap, num_chunks, MCLKS_PER_68K); |
967 opts.address_log = address_log; | 1028 opts.address_log = address_log; |
968 init_68k_context(&context, opts.gen.native_code_map, &opts); | 1029 m68k_context *context = init_68k_context(&opts); |
969 | 1030 gen->m68k = context; |
970 context.video_context = gen->vdp; | 1031 |
971 context.system = gen; | 1032 context->video_context = gen->vdp; |
1033 context->system = gen; | |
972 //cartridge ROM | 1034 //cartridge ROM |
973 context.mem_pointers[0] = cart; | 1035 context->mem_pointers[0] = cart; |
974 context.target_cycle = context.sync_cycle = mclks_per_frame/MCLKS_PER_68K; | 1036 context->target_cycle = context->sync_cycle = gen->frame_end > gen->max_cycles ? gen->frame_end : gen->max_cycles; |
975 //work RAM | 1037 //work RAM |
976 context.mem_pointers[1] = ram; | 1038 context->mem_pointers[1] = ram; |
977 //save RAM/map | 1039 //save RAM/map |
978 context.mem_pointers[2] = initial_mapped; | 1040 context->mem_pointers[2] = initial_mapped; |
979 context.mem_pointers[3] = (uint16_t *)gen->save_ram; | 1041 context->mem_pointers[3] = (uint16_t *)gen->save_ram; |
980 uint32_t address; | 1042 uint32_t address; |
981 address = cart[2] << 16 | cart[3]; | 1043 address = cart[2] << 16 | cart[3]; |
982 translate_m68k_stream(address, &context); | 1044 translate_m68k_stream(address, context); |
983 if (statefile) { | 1045 if (statefile) { |
984 uint32_t pc = load_gst(gen, statefile); | 1046 uint32_t pc = load_gst(gen, statefile); |
985 if (!pc) { | 1047 if (!pc) { |
986 fprintf(stderr, "Failed to load save state %s\n", statefile); | 1048 fprintf(stderr, "Failed to load save state %s\n", statefile); |
987 exit(1); | 1049 exit(1); |
988 } | 1050 } |
989 printf("Loaded %s\n", statefile); | 1051 printf("Loaded %s\n", statefile); |
990 if (debugger) { | 1052 if (debugger) { |
991 insert_breakpoint(&context, pc, debugger); | 1053 insert_breakpoint(context, pc, debugger); |
992 } | 1054 } |
993 adjust_int_cycle(gen->m68k, gen->vdp); | 1055 adjust_int_cycle(gen->m68k, gen->vdp); |
994 #ifndef NO_Z80 | 1056 start_68k_context(context, pc); |
995 gen->z80->native_pc = z80_get_native_address_trans(gen->z80, gen->z80->pc); | |
996 #endif | |
997 start_68k_context(&context, pc); | |
998 } else { | 1057 } else { |
999 if (debugger) { | 1058 if (debugger) { |
1000 insert_breakpoint(&context, address, debugger); | 1059 insert_breakpoint(context, address, debugger); |
1001 } | 1060 } |
1002 m68k_reset(&context); | 1061 m68k_reset(context); |
1003 } | 1062 } |
1004 } | 1063 } |
1005 | 1064 |
1006 char title[64]; | 1065 char title[64]; |
1007 | 1066 |
1070 break; | 1129 break; |
1071 } | 1130 } |
1072 } | 1131 } |
1073 } | 1132 } |
1074 } | 1133 } |
1134 #ifndef NO_Z80 | |
1135 const memmap_chunk z80_map[] = { | |
1136 { 0x0000, 0x4000, 0x1FFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, z80_ram, NULL, NULL, NULL, NULL }, | |
1137 { 0x8000, 0x10000, 0x7FFF, 0, 0, NULL, NULL, NULL, z80_read_bank, z80_write_bank}, | |
1138 { 0x4000, 0x6000, 0x0003, 0, 0, NULL, NULL, NULL, z80_read_ym, z80_write_ym}, | |
1139 { 0x6000, 0x6100, 0xFFFF, 0, 0, NULL, NULL, NULL, NULL, z80_write_bank_reg}, | |
1140 { 0x7F00, 0x8000, 0x00FF, 0, 0, NULL, NULL, NULL, z80_vdp_port_read, z80_vdp_port_write} | |
1141 }; | |
1142 #endif | |
1075 | 1143 |
1076 int main(int argc, char ** argv) | 1144 int main(int argc, char ** argv) |
1077 { | 1145 { |
1078 if (argc < 2) { | 1146 if (argc < 2) { |
1079 fputs("Usage: blastem [OPTIONS] ROMFILE [WIDTH] [HEIGHT]\n", stderr); | 1147 fputs("Usage: blastem [OPTIONS] ROMFILE [WIDTH] [HEIGHT]\n", stderr); |
1080 return 1; | 1148 return 1; |
1081 } | 1149 } |
1082 set_exe_str(argv[0]); | 1150 set_exe_str(argv[0]); |
1083 config = load_config(); | 1151 config = load_config(); |
1084 detect_region(); | |
1085 int width = -1; | 1152 int width = -1; |
1086 int height = -1; | 1153 int height = -1; |
1087 int debug = 0; | 1154 int debug = 0; |
1088 int ym_log = 0; | 1155 int ym_log = 0; |
1089 int loaded = 0; | 1156 int loaded = 0; |
1201 fputs("You must specify a ROM filename!\n", stderr); | 1268 fputs("You must specify a ROM filename!\n", stderr); |
1202 return 1; | 1269 return 1; |
1203 } | 1270 } |
1204 if (force_version) { | 1271 if (force_version) { |
1205 version_reg = force_version; | 1272 version_reg = force_version; |
1273 } else { | |
1274 detect_region(); | |
1206 } | 1275 } |
1207 update_title(); | 1276 update_title(); |
1208 int def_width = 0; | 1277 int def_width = 0; |
1209 char *config_width = tern_find_ptr(config, "videowidth"); | 1278 char *config_width = tern_find_ptr(config, "videowidth"); |
1210 if (config_width) { | 1279 if (config_width) { |
1215 } | 1284 } |
1216 width = width < 320 ? def_width : width; | 1285 width = width < 320 ? def_width : width; |
1217 height = height < 240 ? (width/320) * 240 : height; | 1286 height = height < 240 ? (width/320) * 240 : height; |
1218 uint32_t fps = 60; | 1287 uint32_t fps = 60; |
1219 if (version_reg & 0x40) { | 1288 if (version_reg & 0x40) { |
1220 mclks_per_frame = MCLKS_LINE * LINES_PAL; | |
1221 fps = 50; | 1289 fps = 50; |
1222 } | 1290 } |
1223 if (!headless) { | 1291 if (!headless) { |
1224 render_init(width, height, title, fps, fullscreen, use_gl); | 1292 render_init(width, height, title, fps, fullscreen); |
1225 } | 1293 } |
1226 vdp_context v_context; | 1294 vdp_context v_context; |
1227 genesis_context gen; | 1295 genesis_context gen; |
1228 memset(&gen, 0, sizeof(gen)); | 1296 memset(&gen, 0, sizeof(gen)); |
1229 gen.master_clock = gen.normal_clock = fps == 60 ? MCLKS_NTSC : MCLKS_PAL; | 1297 gen.master_clock = gen.normal_clock = fps == 60 ? MCLKS_NTSC : MCLKS_PAL; |
1230 | 1298 |
1231 init_vdp_context(&v_context); | 1299 init_vdp_context(&v_context, version_reg & 0x40); |
1300 gen.frame_end = vdp_cycles_to_frame_end(&v_context); | |
1301 char * config_cycles = tern_find_ptr(config, "clocksmax_cycles"); | |
1302 gen.max_cycles = config_cycles ? atoi(config_cycles) : 10000000; | |
1232 | 1303 |
1233 ym2612_context y_context; | 1304 ym2612_context y_context; |
1234 ym_init(&y_context, render_sample_rate(), gen.master_clock, MCLKS_PER_YM, render_audio_buffer(), ym_log ? YM_OPT_WAVE_LOG : 0); | 1305 ym_init(&y_context, render_sample_rate(), gen.master_clock, MCLKS_PER_YM, render_audio_buffer(), ym_log ? YM_OPT_WAVE_LOG : 0); |
1235 | 1306 |
1236 psg_context p_context; | 1307 psg_context p_context; |
1237 psg_init(&p_context, render_sample_rate(), gen.master_clock, MCLKS_PER_PSG, render_audio_buffer()); | 1308 psg_init(&p_context, render_sample_rate(), gen.master_clock, MCLKS_PER_PSG, render_audio_buffer()); |
1238 | 1309 |
1239 z80_context z_context; | 1310 z80_context z_context; |
1240 x86_z80_options z_opts; | |
1241 #ifndef NO_Z80 | 1311 #ifndef NO_Z80 |
1242 init_x86_z80_opts(&z_opts); | 1312 z80_options z_opts; |
1313 init_z80_opts(&z_opts, z80_map, 5, MCLKS_PER_Z80); | |
1243 init_z80_context(&z_context, &z_opts); | 1314 init_z80_context(&z_context, &z_opts); |
1315 z80_assert_reset(&z_context, 0); | |
1244 #endif | 1316 #endif |
1245 | 1317 |
1246 z_context.system = &gen; | 1318 z_context.system = &gen; |
1247 z_context.mem_pointers[0] = z80_ram; | 1319 z_context.mem_pointers[0] = z80_ram; |
1248 z_context.sync_cycle = z_context.target_cycle = mclks_per_frame/MCLKS_PER_Z80; | |
1249 z_context.int_cycle = CYCLE_NEVER; | |
1250 z_context.mem_pointers[1] = z_context.mem_pointers[2] = (uint8_t *)cart; | 1320 z_context.mem_pointers[1] = z_context.mem_pointers[2] = (uint8_t *)cart; |
1251 | 1321 |
1252 gen.z80 = &z_context; | 1322 gen.z80 = &z_context; |
1253 gen.vdp = &v_context; | 1323 gen.vdp = &v_context; |
1254 gen.ym = &y_context; | 1324 gen.ym = &y_context; |
1255 gen.psg = &p_context; | 1325 gen.psg = &p_context; |
1256 genesis = &gen; | 1326 genesis = &gen; |
1327 setup_io_devices(config, gen.ports); | |
1257 | 1328 |
1258 int fname_size = strlen(romfname); | 1329 int fname_size = strlen(romfname); |
1259 sram_filename = malloc(fname_size+6); | 1330 sram_filename = malloc(fname_size+6); |
1260 memcpy(sram_filename, romfname, fname_size); | 1331 memcpy(sram_filename, romfname, fname_size); |
1261 int i; | 1332 int i; |
1266 } | 1337 } |
1267 } | 1338 } |
1268 if (i < 0) { | 1339 if (i < 0) { |
1269 strcpy(sram_filename + fname_size, ".sram"); | 1340 strcpy(sram_filename + fname_size, ".sram"); |
1270 } | 1341 } |
1271 set_keybindings(); | 1342 set_keybindings(gen.ports); |
1272 | 1343 |
1273 init_run_cpu(&gen, address_log, statefile, debuggerfun); | 1344 init_run_cpu(&gen, address_log, statefile, debuggerfun); |
1274 return 0; | 1345 return 0; |
1275 } | 1346 } |