Mercurial > repos > blastem
comparison blastem.c @ 354:15dd6418fe67
Initial PSG support. Mostly works, noise channel is borked though.
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Thu, 23 May 2013 23:42:42 -0700 |
parents | 2f264d2a60c2 |
children | 79e4b466e7d0 |
comparison
equal
deleted
inserted
replaced
353:a60e527cd21f | 354:15dd6418fe67 |
---|---|
12 #define CARTRIDGE_WORDS 0x200000 | 12 #define CARTRIDGE_WORDS 0x200000 |
13 #define RAM_WORDS 32 * 1024 | 13 #define RAM_WORDS 32 * 1024 |
14 #define Z80_RAM_BYTES 8 * 1024 | 14 #define Z80_RAM_BYTES 8 * 1024 |
15 #define MCLKS_PER_68K 7 | 15 #define MCLKS_PER_68K 7 |
16 #define MCLKS_PER_Z80 15 | 16 #define MCLKS_PER_Z80 15 |
17 #define MCLKS_PER_PSG (MCLKS_PER_Z80*16) | |
17 //TODO: Figure out the exact value for this | 18 //TODO: Figure out the exact value for this |
18 #define CYCLE_NEVER 0xFFFFFFFF | 19 #define CYCLE_NEVER 0xFFFFFFFF |
19 #define LINES_NTSC 262 | 20 #define LINES_NTSC 262 |
20 #define LINES_PAL 312 | 21 #define LINES_PAL 312 |
21 | 22 |
198 if (mclks >= mclks_per_frame) { | 199 if (mclks >= mclks_per_frame) { |
199 ym_run(gen->ym, context->current_cycle); | 200 ym_run(gen->ym, context->current_cycle); |
200 gen->ym->current_cycle -= mclks_per_frame/MCLKS_PER_68K; | 201 gen->ym->current_cycle -= mclks_per_frame/MCLKS_PER_68K; |
201 //printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, mclks); | 202 //printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, mclks); |
202 vdp_run_context(v_context, mclks_per_frame); | 203 vdp_run_context(v_context, mclks_per_frame); |
204 psg_run(gen->psg, mclks/MCLKS_PER_PSG); | |
205 gen->psg->cycles -= mclks_per_frame/MCLKS_PER_PSG; | |
203 if (!headless) { | 206 if (!headless) { |
204 break_on_sync |= wait_render_frame(v_context, frame_limit); | 207 break_on_sync |= wait_render_frame(v_context, frame_limit); |
205 } | 208 } |
206 frame++; | 209 frame++; |
207 mclks -= mclks_per_frame; | 210 mclks -= mclks_per_frame; |
226 vdp_run_context(v_context, mclks); | 229 vdp_run_context(v_context, mclks); |
227 } | 230 } |
228 } else { | 231 } else { |
229 //printf("running VDP for %d cycles\n", mclks - v_context->cycles); | 232 //printf("running VDP for %d cycles\n", mclks - v_context->cycles); |
230 vdp_run_context(v_context, mclks); | 233 vdp_run_context(v_context, mclks); |
234 psg_run(gen->psg, mclks/MCLKS_PER_PSG); | |
231 } | 235 } |
232 if (context->int_ack) { | 236 if (context->int_ack) { |
233 vdp_int_ack(v_context, context->int_ack); | 237 vdp_int_ack(v_context, context->int_ack); |
234 context->int_ack = 0; | 238 context->int_ack = 0; |
235 } | 239 } |
316 } | 320 } |
317 if (v_context->cycles != before_cycle) { | 321 if (v_context->cycles != before_cycle) { |
318 context->current_cycle = v_context->cycles / MCLKS_PER_68K; | 322 context->current_cycle = v_context->cycles / MCLKS_PER_68K; |
319 } | 323 } |
320 } else if (vdp_port < 0x18) { | 324 } else if (vdp_port < 0x18) { |
321 //TODO: Implement PSG | 325 genesis_context * gen = context->system; |
326 psg_run(gen->psg, (context->current_cycle * MCLKS_PER_68K) / MCLKS_PER_PSG); | |
327 psg_write(gen->psg, value); | |
322 } else { | 328 } else { |
323 //TODO: Implement undocumented test register(s) | 329 //TODO: Implement undocumented test register(s) |
324 } | 330 } |
325 return context; | 331 return context; |
326 } | 332 } |
327 | 333 |
328 m68k_context * vdp_port_write_b(uint32_t vdp_port, m68k_context * context, uint8_t value) | 334 m68k_context * vdp_port_write_b(uint32_t vdp_port, m68k_context * context, uint8_t value) |
329 { | 335 { |
330 return vdp_port_write(vdp_port, context, value | value << 8); | 336 return vdp_port_write(vdp_port, context, vdp_port < 0x10 ? value | value << 8 : value); |
331 } | 337 } |
332 | 338 |
333 uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context) | 339 uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context) |
334 { | 340 { |
335 if (vdp_port & 0x2700E0) { | 341 if (vdp_port & 0x2700E0) { |
1383 } else if (detect_specific_region('E') || detect_specific_region('A')) { | 1389 } else if (detect_specific_region('E') || detect_specific_region('A')) { |
1384 version_reg = NO_DISK | EUR; | 1390 version_reg = NO_DISK | EUR; |
1385 } | 1391 } |
1386 } | 1392 } |
1387 | 1393 |
1394 #define PSG_CLKS_NTSC (3579545/16) | |
1395 #define PSG_CLKS_PAL (3546893/16) | |
1396 | |
1388 int main(int argc, char ** argv) | 1397 int main(int argc, char ** argv) |
1389 { | 1398 { |
1390 if (argc < 2) { | 1399 if (argc < 2) { |
1391 fputs("Usage: blastem FILENAME\n", stderr); | 1400 fputs("Usage: blastem FILENAME\n", stderr); |
1392 return 1; | 1401 return 1; |
1454 } | 1463 } |
1455 } | 1464 } |
1456 update_title(); | 1465 update_title(); |
1457 width = width < 320 ? 320 : width; | 1466 width = width < 320 ? 320 : width; |
1458 height = height < 240 ? (width/320) * 240 : height; | 1467 height = height < 240 ? (width/320) * 240 : height; |
1459 if (!headless) { | 1468 uint32_t fps = 60; |
1460 render_init(width, height, title); | |
1461 } | |
1462 if (version_reg & 0x40) { | 1469 if (version_reg & 0x40) { |
1463 mclks_per_frame = MCLKS_LINE * LINES_PAL; | 1470 mclks_per_frame = MCLKS_LINE * LINES_PAL; |
1464 render_fps(50); | 1471 fps = 50; |
1472 } | |
1473 if (!headless) { | |
1474 render_init(width, height, title, fps); | |
1465 } | 1475 } |
1466 vdp_context v_context; | 1476 vdp_context v_context; |
1467 | 1477 |
1468 init_vdp_context(&v_context); | 1478 init_vdp_context(&v_context); |
1469 | 1479 |
1470 ym2612_context y_context; | 1480 ym2612_context y_context; |
1471 ym_init(&y_context); | 1481 ym_init(&y_context); |
1482 | |
1483 psg_context p_context; | |
1484 psg_init(&p_context, render_sample_rate(), fps == 60 ? PSG_CLKS_NTSC : PSG_CLKS_PAL, render_audio_buffer()); | |
1472 | 1485 |
1473 z80_context z_context; | 1486 z80_context z_context; |
1474 x86_z80_options z_opts; | 1487 x86_z80_options z_opts; |
1475 init_x86_z80_opts(&z_opts); | 1488 init_x86_z80_opts(&z_opts); |
1476 init_z80_context(&z_context, &z_opts); | 1489 init_z80_context(&z_context, &z_opts); |
1484 z_context.mem_pointers[1] = z_context.mem_pointers[2] = (uint8_t *)cart; | 1497 z_context.mem_pointers[1] = z_context.mem_pointers[2] = (uint8_t *)cart; |
1485 | 1498 |
1486 gen.z80 = &z_context; | 1499 gen.z80 = &z_context; |
1487 gen.vdp = &v_context; | 1500 gen.vdp = &v_context; |
1488 gen.ym = &y_context; | 1501 gen.ym = &y_context; |
1502 gen.psg = &p_context; | |
1489 genesis = &gen; | 1503 genesis = &gen; |
1490 | 1504 |
1491 int fname_size = strlen(argv[1]); | 1505 int fname_size = strlen(argv[1]); |
1492 sram_filename = malloc(fname_size+6); | 1506 sram_filename = malloc(fname_size+6); |
1493 memcpy(sram_filename, argv[1], fname_size); | 1507 memcpy(sram_filename, argv[1], fname_size); |