Mercurial > repos > blastem
comparison blastem.c @ 652:f822d9216968
Merge
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 30 Dec 2014 19:11:34 -0800 |
parents | 649db9397fa1 d77c79cec800 |
children | 759c38bf97f8 |
comparison
equal
deleted
inserted
replaced
620:9d6fed6501ba | 652:f822d9216968 |
---|---|
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; | 36 uint32_t mclk_target = 0; |
37 | 37 |
38 uint16_t cart[CARTRIDGE_WORDS]; | 38 uint16_t cart[CARTRIDGE_WORDS]; |
39 uint16_t ram[RAM_WORDS]; | 39 uint16_t ram[RAM_WORDS]; |
40 uint8_t z80_ram[Z80_RAM_BYTES]; | 40 uint8_t z80_ram[Z80_RAM_BYTES]; |
41 | 41 |
189 if (z_context->current_cycle < z_context->sync_cycle) { | 189 if (z_context->current_cycle < z_context->sync_cycle) { |
190 if (need_reset) { | 190 if (need_reset) { |
191 z80_reset(z_context); | 191 z80_reset(z_context); |
192 need_reset = 0; | 192 need_reset = 0; |
193 } | 193 } |
194 uint32_t vint_cycle = vdp_next_vint_z80(gen->vdp) / MCLKS_PER_Z80; | 194 |
195 while (z_context->current_cycle < z_context->sync_cycle) { | 195 while (z_context->current_cycle < z_context->sync_cycle) { |
196 if (z_context->iff1 && z_context->current_cycle < (vint_cycle + Z80_VINT_DURATION)) { | 196 if (z_context->int_pulse_end < z_context->current_cycle || z_context->int_pulse_end == CYCLE_NEVER) { |
197 z_context->int_cycle = vint_cycle < z_context->int_enable_cycle ? z_context->int_enable_cycle : vint_cycle; | 197 z_context->int_pulse_start = vdp_next_vint_z80(gen->vdp) / MCLKS_PER_Z80; |
198 z_context->int_pulse_end = z_context->int_pulse_start + Z80_VINT_DURATION; | |
199 } | |
200 if (z_context->iff1) { | |
201 z_context->int_cycle = z_context->int_pulse_start < z_context->int_enable_cycle ? z_context->int_enable_cycle : z_context->int_pulse_start; | |
198 } else { | 202 } else { |
199 z_context->int_cycle = CYCLE_NEVER; | 203 z_context->int_cycle = CYCLE_NEVER; |
200 } | 204 } |
201 z_context->target_cycle = z_context->sync_cycle < z_context->int_cycle ? z_context->sync_cycle : z_context->int_cycle; | 205 z_context->target_cycle = z_context->sync_cycle < z_context->int_cycle ? z_context->sync_cycle : z_context->int_cycle; |
202 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); | 206 dprintf("Running Z80 from cycle %d to cycle %d. Int cycle: %d\n", z_context->current_cycle, z_context->sync_cycle, z_context->int_cycle); |
203 z_context->run(z_context); | 207 z_context->run(z_context); |
204 dprintf("Z80 ran to cycle %d\n", z_context->current_cycle); | 208 dprintf("Z80 ran to cycle %d\n", z_context->current_cycle); |
205 } | 209 } |
206 } | 210 } |
207 } else | 211 } else |
234 genesis_context * gen = context->system; | 238 genesis_context * gen = context->system; |
235 vdp_context * v_context = gen->vdp; | 239 vdp_context * v_context = gen->vdp; |
236 z80_context * z_context = gen->z80; | 240 z80_context * z_context = gen->z80; |
237 uint32_t mclks = context->current_cycle * MCLKS_PER_68K; | 241 uint32_t mclks = context->current_cycle * MCLKS_PER_68K; |
238 sync_z80(z_context, mclks); | 242 sync_z80(z_context, mclks); |
239 if (mclks >= mclks_per_frame) { | 243 if (mclks >= mclk_target) { |
240 sync_sound(gen, mclks); | 244 sync_sound(gen, mclks); |
241 gen->ym->current_cycle -= mclks_per_frame; | 245 gen->ym->current_cycle -= mclk_target; |
242 gen->psg->cycles -= mclks_per_frame; | 246 gen->psg->cycles -= mclk_target; |
243 if (gen->ym->write_cycle != CYCLE_NEVER) { | 247 if (gen->ym->write_cycle != CYCLE_NEVER) { |
244 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; | 248 gen->ym->write_cycle = gen->ym->write_cycle >= mclk_target/MCLKS_PER_68K ? gen->ym->write_cycle - mclk_target/MCLKS_PER_68K : 0; |
245 } | 249 } |
246 //printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, mclks); | 250 //printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, mclks); |
247 vdp_run_context(v_context, mclks_per_frame); | 251 vdp_run_context(v_context, mclk_target); |
248 | 252 |
249 if (!headless) { | 253 if (!headless) { |
250 break_on_sync |= wait_render_frame(v_context, frame_limit); | 254 break_on_sync |= wait_render_frame(v_context, frame_limit); |
251 } else if(exit_after){ | 255 } else if(exit_after){ |
252 --exit_after; | 256 --exit_after; |
253 if (!exit_after) { | 257 if (!exit_after) { |
254 exit(0); | 258 exit(0); |
255 } | 259 } |
256 } | 260 } |
257 frame++; | 261 frame++; |
258 mclks -= mclks_per_frame; | 262 mclks -= mclk_target; |
259 vdp_adjust_cycles(v_context, mclks_per_frame); | 263 vdp_adjust_cycles(v_context, mclk_target); |
260 io_adjust_cycles(gen->ports, context->current_cycle, mclks_per_frame/MCLKS_PER_68K); | 264 io_adjust_cycles(gen->ports, context->current_cycle, mclk_target/MCLKS_PER_68K); |
261 io_adjust_cycles(gen->ports+1, context->current_cycle, mclks_per_frame/MCLKS_PER_68K); | 265 io_adjust_cycles(gen->ports+1, context->current_cycle, mclk_target/MCLKS_PER_68K); |
262 io_adjust_cycles(gen->ports+2, context->current_cycle, mclks_per_frame/MCLKS_PER_68K); | 266 io_adjust_cycles(gen->ports+2, context->current_cycle, mclk_target/MCLKS_PER_68K); |
263 if (busack_cycle != CYCLE_NEVER) { | 267 if (busack_cycle != CYCLE_NEVER) { |
264 if (busack_cycle > mclks_per_frame/MCLKS_PER_68K) { | 268 if (busack_cycle > mclk_target/MCLKS_PER_68K) { |
265 busack_cycle -= mclks_per_frame/MCLKS_PER_68K; | 269 busack_cycle -= mclk_target/MCLKS_PER_68K; |
266 } else { | 270 } else { |
267 busack_cycle = CYCLE_NEVER; | 271 busack_cycle = CYCLE_NEVER; |
268 busack = new_busack; | 272 busack = new_busack; |
269 } | 273 } |
270 } | 274 } |
271 context->current_cycle -= mclks_per_frame/MCLKS_PER_68K; | 275 context->current_cycle -= mclk_target/MCLKS_PER_68K; |
272 if (z_context->current_cycle >= mclks_per_frame/MCLKS_PER_Z80) { | 276 if (z_context->current_cycle >= mclk_target/MCLKS_PER_Z80) { |
273 z_context->current_cycle -= mclks_per_frame/MCLKS_PER_Z80; | 277 z_context->current_cycle -= mclk_target/MCLKS_PER_Z80; |
274 } else { | 278 } else { |
275 z_context->current_cycle = 0; | 279 z_context->current_cycle = 0; |
276 } | 280 } |
281 if (z_context->int_cycle != CYCLE_NEVER) { | |
282 if (z_context->int_cycle >= mclk_target/MCLKS_PER_Z80) { | |
283 z_context->int_cycle -= mclk_target/MCLKS_PER_Z80; | |
284 } else { | |
285 z_context->int_cycle = 0; | |
286 } | |
287 } | |
288 if (z_context->int_pulse_start != CYCLE_NEVER) { | |
289 if (z_context->int_pulse_end >= mclk_target/MCLKS_PER_Z80) { | |
290 z_context->int_pulse_end -= mclk_target/MCLKS_PER_Z80; | |
291 if (z_context->int_pulse_start >= mclk_target/MCLKS_PER_Z80) { | |
292 z_context->int_pulse_start -= mclk_target/MCLKS_PER_Z80; | |
293 } else { | |
294 z_context->int_pulse_start = 0; | |
295 } | |
296 } | |
297 } else { | |
298 z_context->int_pulse_start = CYCLE_NEVER; | |
299 z_context->int_pulse_end = CYCLE_NEVER; | |
300 } | |
301 if (z_context->int_enable_cycle >= mclk_target/MCLKS_PER_Z80) { | |
302 z_context->int_enable_cycle -= mclk_target/MCLKS_PER_Z80; | |
303 } else { | |
304 z_context->int_enable_cycle = 0; | |
305 } | |
277 if (mclks) { | 306 if (mclks) { |
278 vdp_run_context(v_context, mclks); | 307 vdp_run_context(v_context, mclks); |
279 } | 308 } |
309 mclk_target = vdp_cycles_to_frame_end(v_context); | |
280 } else { | 310 } else { |
281 //printf("running VDP for %d cycles\n", mclks - v_context->cycles); | 311 //printf("running VDP for %d cycles\n", mclks - v_context->cycles); |
282 vdp_run_context(v_context, mclks); | 312 vdp_run_context(v_context, mclks); |
283 sync_sound(gen, mclks); | 313 sync_sound(gen, mclks); |
284 } | 314 } |
320 uint32_t before_cycle = v_context->cycles; | 350 uint32_t before_cycle = v_context->cycles; |
321 if (vdp_port < 4) { | 351 if (vdp_port < 4) { |
322 gen->bus_busy = 1; | 352 gen->bus_busy = 1; |
323 while (vdp_data_port_write(v_context, value) < 0) { | 353 while (vdp_data_port_write(v_context, value) < 0) { |
324 while(v_context->flags & FLAG_DMA_RUN) { | 354 while(v_context->flags & FLAG_DMA_RUN) { |
325 vdp_run_dma_done(v_context, mclks_per_frame); | 355 vdp_run_dma_done(v_context, mclk_target); |
326 if (v_context->cycles >= mclks_per_frame) { | 356 if (v_context->cycles >= mclk_target) { |
327 context->current_cycle = v_context->cycles / MCLKS_PER_68K; | 357 context->current_cycle = v_context->cycles / MCLKS_PER_68K; |
328 if (context->current_cycle * MCLKS_PER_68K < mclks_per_frame) { | 358 if (context->current_cycle * MCLKS_PER_68K < mclk_target) { |
329 ++context->current_cycle; | 359 ++context->current_cycle; |
330 } | 360 } |
331 sync_components(context, 0); | 361 sync_components(context, 0); |
332 } | 362 } |
333 } | 363 } |
337 gen->bus_busy = 1; | 367 gen->bus_busy = 1; |
338 blocked = vdp_control_port_write(v_context, value); | 368 blocked = vdp_control_port_write(v_context, value); |
339 if (blocked) { | 369 if (blocked) { |
340 while (blocked) { | 370 while (blocked) { |
341 while(v_context->flags & FLAG_DMA_RUN) { | 371 while(v_context->flags & FLAG_DMA_RUN) { |
342 vdp_run_dma_done(v_context, mclks_per_frame); | 372 vdp_run_dma_done(v_context, mclk_target); |
343 if (v_context->cycles >= mclks_per_frame) { | 373 if (v_context->cycles >= mclk_target) { |
344 context->current_cycle = v_context->cycles / MCLKS_PER_68K; | 374 context->current_cycle = v_context->cycles / MCLKS_PER_68K; |
345 if (context->current_cycle * MCLKS_PER_68K < mclks_per_frame) { | 375 if (context->current_cycle * MCLKS_PER_68K < mclk_target) { |
346 ++context->current_cycle; | 376 ++context->current_cycle; |
347 } | 377 } |
348 sync_components(context, 0); | 378 sync_components(context, 0); |
349 } | 379 } |
350 } | 380 } |
1043 | 1073 |
1044 context.video_context = gen->vdp; | 1074 context.video_context = gen->vdp; |
1045 context.system = gen; | 1075 context.system = gen; |
1046 //cartridge ROM | 1076 //cartridge ROM |
1047 context.mem_pointers[0] = cart; | 1077 context.mem_pointers[0] = cart; |
1048 context.target_cycle = context.sync_cycle = mclks_per_frame/MCLKS_PER_68K; | 1078 context.target_cycle = context.sync_cycle = mclk_target/MCLKS_PER_68K; |
1049 //work RAM | 1079 //work RAM |
1050 context.mem_pointers[1] = ram; | 1080 context.mem_pointers[1] = ram; |
1051 //save RAM/map | 1081 //save RAM/map |
1052 context.mem_pointers[2] = initial_mapped; | 1082 context.mem_pointers[2] = initial_mapped; |
1053 context.mem_pointers[3] = (uint16_t *)gen->save_ram; | 1083 context.mem_pointers[3] = (uint16_t *)gen->save_ram; |
1298 } | 1328 } |
1299 width = width < 320 ? def_width : width; | 1329 width = width < 320 ? def_width : width; |
1300 height = height < 240 ? (width/320) * 240 : height; | 1330 height = height < 240 ? (width/320) * 240 : height; |
1301 uint32_t fps = 60; | 1331 uint32_t fps = 60; |
1302 if (version_reg & 0x40) { | 1332 if (version_reg & 0x40) { |
1303 mclks_per_frame = MCLKS_LINE * LINES_PAL; | |
1304 fps = 50; | 1333 fps = 50; |
1305 } | 1334 } |
1306 if (!headless) { | 1335 if (!headless) { |
1307 render_init(width, height, title, fps, fullscreen, use_gl); | 1336 render_init(width, height, title, fps, fullscreen, use_gl); |
1308 } | 1337 } |
1309 vdp_context v_context; | 1338 vdp_context v_context; |
1310 genesis_context gen; | 1339 genesis_context gen; |
1311 memset(&gen, 0, sizeof(gen)); | 1340 memset(&gen, 0, sizeof(gen)); |
1312 gen.master_clock = gen.normal_clock = fps == 60 ? MCLKS_NTSC : MCLKS_PAL; | 1341 gen.master_clock = gen.normal_clock = fps == 60 ? MCLKS_NTSC : MCLKS_PAL; |
1313 | 1342 |
1314 init_vdp_context(&v_context); | 1343 init_vdp_context(&v_context, version_reg & 0x40); |
1344 mclk_target = vdp_cycles_to_frame_end(&v_context); | |
1315 | 1345 |
1316 ym2612_context y_context; | 1346 ym2612_context y_context; |
1317 ym_init(&y_context, render_sample_rate(), gen.master_clock, MCLKS_PER_YM, render_audio_buffer(), ym_log ? YM_OPT_WAVE_LOG : 0); | 1347 ym_init(&y_context, render_sample_rate(), gen.master_clock, MCLKS_PER_YM, render_audio_buffer(), ym_log ? YM_OPT_WAVE_LOG : 0); |
1318 | 1348 |
1319 psg_context p_context; | 1349 psg_context p_context; |
1326 init_z80_context(&z_context, &z_opts); | 1356 init_z80_context(&z_context, &z_opts); |
1327 #endif | 1357 #endif |
1328 | 1358 |
1329 z_context.system = &gen; | 1359 z_context.system = &gen; |
1330 z_context.mem_pointers[0] = z80_ram; | 1360 z_context.mem_pointers[0] = z80_ram; |
1331 z_context.sync_cycle = z_context.target_cycle = mclks_per_frame/MCLKS_PER_Z80; | 1361 z_context.sync_cycle = z_context.target_cycle = mclk_target/MCLKS_PER_Z80; |
1332 z_context.int_cycle = CYCLE_NEVER; | 1362 z_context.int_cycle = CYCLE_NEVER; |
1333 z_context.mem_pointers[1] = z_context.mem_pointers[2] = (uint8_t *)cart; | 1363 z_context.mem_pointers[1] = z_context.mem_pointers[2] = (uint8_t *)cart; |
1334 | 1364 |
1335 gen.z80 = &z_context; | 1365 gen.z80 = &z_context; |
1336 gen.vdp = &v_context; | 1366 gen.vdp = &v_context; |
1349 } | 1379 } |
1350 } | 1380 } |
1351 if (i < 0) { | 1381 if (i < 0) { |
1352 strcpy(sram_filename + fname_size, ".sram"); | 1382 strcpy(sram_filename + fname_size, ".sram"); |
1353 } | 1383 } |
1354 set_keybindings(); | 1384 set_keybindings(gen.ports); |
1355 | 1385 |
1356 init_run_cpu(&gen, address_log, statefile, debuggerfun); | 1386 init_run_cpu(&gen, address_log, statefile, debuggerfun); |
1357 return 0; | 1387 return 0; |
1358 } | 1388 } |