Mercurial > repos > blastem
comparison blastem.c @ 260:625f8e4d5fd2
Initial stab at integartiong Z80 core
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 30 Apr 2013 00:39:31 -0700 |
parents | 2b1c2c28b261 |
children | 2989ed7b8608 |
comparison
equal
deleted
inserted
replaced
259:d9417261366f | 260:625f8e4d5fd2 |
---|---|
1 #include "68kinst.h" | 1 #include "68kinst.h" |
2 #include "m68k_to_x86.h" | 2 #include "m68k_to_x86.h" |
3 #include "z80_to_x86.h" | |
3 #include "mem.h" | 4 #include "mem.h" |
4 #include "vdp.h" | 5 #include "vdp.h" |
5 #include "render.h" | 6 #include "render.h" |
6 #include "blastem.h" | 7 #include "blastem.h" |
7 #include <stdio.h> | 8 #include <stdio.h> |
10 | 11 |
11 #define CARTRIDGE_WORDS 0x200000 | 12 #define CARTRIDGE_WORDS 0x200000 |
12 #define RAM_WORDS 32 * 1024 | 13 #define RAM_WORDS 32 * 1024 |
13 #define Z80_RAM_BYTES 8 * 1024 | 14 #define Z80_RAM_BYTES 8 * 1024 |
14 #define MCLKS_PER_68K 7 | 15 #define MCLKS_PER_68K 7 |
16 #define MCLKS_PER_Z80 15 | |
15 //TODO: Figure out the exact value for this | 17 //TODO: Figure out the exact value for this |
16 #define MCLKS_PER_FRAME (MCLKS_LINE*262) | 18 #define MCLKS_PER_FRAME (MCLKS_LINE*262) |
17 #define CYCLE_NEVER 0xFFFFFFFF | 19 #define CYCLE_NEVER 0xFFFFFFFF |
18 | 20 |
19 uint16_t cart[CARTRIDGE_WORDS]; | 21 uint16_t cart[CARTRIDGE_WORDS]; |
103 //TODO: Figure out what happens when you try to DMA from weird adresses like IO or banked Z80 area | 105 //TODO: Figure out what happens when you try to DMA from weird adresses like IO or banked Z80 area |
104 return 0; | 106 return 0; |
105 } | 107 } |
106 | 108 |
107 #define VINT_CYCLE ((MCLKS_LINE * 226)/MCLKS_PER_68K) | 109 #define VINT_CYCLE ((MCLKS_LINE * 226)/MCLKS_PER_68K) |
110 #define ZVINT_CYCLE ((MCLKS_LINE * 226)/MCLKS_PER_Z80) | |
108 | 111 |
109 void adjust_int_cycle(m68k_context * context, vdp_context * v_context) | 112 void adjust_int_cycle(m68k_context * context, vdp_context * v_context) |
110 { | 113 { |
111 if (!(v_context->regs[REG_MODE_2] & 0x20 && ((context->status & 0x7) < 6)) || context->current_cycle >= VINT_CYCLE) { | 114 if (!(v_context->regs[REG_MODE_2] & 0x20 && ((context->status & 0x7) < 6)) || context->current_cycle >= VINT_CYCLE) { |
112 context->int_cycle = CYCLE_NEVER; | 115 context->int_cycle = CYCLE_NEVER; |
119 } | 122 } |
120 } | 123 } |
121 } | 124 } |
122 | 125 |
123 int break_on_sync = 0; | 126 int break_on_sync = 0; |
127 #define Z80_ACK_DELAY 3 //TODO: Calculate this on the fly based on how synced up the Z80 and 68K clocks are | |
128 | |
129 uint8_t reset = 1; | |
130 uint8_t need_reset = 0; | |
131 uint8_t busreq = 0; | |
132 uint8_t busack = 0; | |
133 uint32_t busack_cycle = CYCLE_NEVER; | |
134 uint8_t new_busack = 0; | |
124 | 135 |
125 m68k_context * sync_components(m68k_context * context, uint32_t address) | 136 m68k_context * sync_components(m68k_context * context, uint32_t address) |
126 { | 137 { |
127 //TODO: Handle sync targets smaller than a single frame | 138 //TODO: Handle sync targets smaller than a single frame |
128 vdp_context * v_context = context->next_context; | 139 z80_context * z_context = context->next_context; |
140 vdp_context * v_context = z_context->next_context; | |
129 uint32_t mclks = context->current_cycle * MCLKS_PER_68K; | 141 uint32_t mclks = context->current_cycle * MCLKS_PER_68K; |
142 if (!reset && !busreq) { | |
143 if (need_reset) { | |
144 z80_reset(z_context); | |
145 need_reset = 0; | |
146 } | |
147 z_context->sync_cycle = mclks / MCLKS_PER_Z80; | |
148 while (z_context->current_cycle < z_context->sync_cycle) { | |
149 if (z_context->iff1 && z_context->current_cycle < ZVINT_CYCLE) { | |
150 z_context->int_cycle = ZVINT_CYCLE; | |
151 } | |
152 z_context->target_cycle = z_context->sync_cycle < z_context->int_cycle ? z_context->sync_cycle : z_context->int_cycle; | |
153 z80_run(z_context); | |
154 } | |
155 } | |
130 if (mclks >= MCLKS_PER_FRAME) { | 156 if (mclks >= MCLKS_PER_FRAME) { |
131 //printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, mclks); | 157 //printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, mclks); |
132 vdp_run_context(v_context, MCLKS_PER_FRAME); | 158 vdp_run_context(v_context, MCLKS_PER_FRAME); |
133 if (!headless) { | 159 if (!headless) { |
134 break_on_sync |= wait_render_frame(v_context); | 160 break_on_sync |= wait_render_frame(v_context); |
136 mclks -= MCLKS_PER_FRAME; | 162 mclks -= MCLKS_PER_FRAME; |
137 vdp_adjust_cycles(v_context, MCLKS_PER_FRAME); | 163 vdp_adjust_cycles(v_context, MCLKS_PER_FRAME); |
138 io_adjust_cycles(&gamepad_1, context->current_cycle, MCLKS_PER_FRAME/MCLKS_PER_68K); | 164 io_adjust_cycles(&gamepad_1, context->current_cycle, MCLKS_PER_FRAME/MCLKS_PER_68K); |
139 io_adjust_cycles(&gamepad_2, context->current_cycle, MCLKS_PER_FRAME/MCLKS_PER_68K); | 165 io_adjust_cycles(&gamepad_2, context->current_cycle, MCLKS_PER_FRAME/MCLKS_PER_68K); |
140 context->current_cycle -= MCLKS_PER_FRAME/MCLKS_PER_68K; | 166 context->current_cycle -= MCLKS_PER_FRAME/MCLKS_PER_68K; |
167 if (z_context->current_cycle >= MCLKS_PER_FRAME/MCLKS_PER_Z80) { | |
168 z_context->current_cycle -= MCLKS_PER_FRAME/MCLKS_PER_Z80; | |
169 } else { | |
170 z_context->current_cycle = 0; | |
171 } | |
141 if (mclks) { | 172 if (mclks) { |
142 vdp_run_context(v_context, mclks); | 173 vdp_run_context(v_context, mclks); |
143 } | 174 } |
144 } else { | 175 } else { |
145 //printf("running VDP for %d cycles\n", mclks - v_context->cycles); | 176 //printf("running VDP for %d cycles\n", mclks - v_context->cycles); |
155 | 186 |
156 m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_t value) | 187 m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_t value) |
157 { | 188 { |
158 //printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle); | 189 //printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle); |
159 sync_components(context, 0); | 190 sync_components(context, 0); |
160 vdp_context * v_context = context->next_context; | 191 z80_context * z_context = context->next_context; |
192 vdp_context * v_context = z_context->next_context; | |
161 if (vdp_port < 0x10) { | 193 if (vdp_port < 0x10) { |
162 int blocked; | 194 int blocked; |
163 if (vdp_port < 4) { | 195 if (vdp_port < 4) { |
164 while (vdp_data_port_write(v_context, value) < 0) { | 196 while (vdp_data_port_write(v_context, value) < 0) { |
165 while(v_context->flags & FLAG_DMA_RUN) { | 197 while(v_context->flags & FLAG_DMA_RUN) { |
214 } | 246 } |
215 | 247 |
216 m68k_context * vdp_port_read(uint32_t vdp_port, m68k_context * context) | 248 m68k_context * vdp_port_read(uint32_t vdp_port, m68k_context * context) |
217 { | 249 { |
218 sync_components(context, 0); | 250 sync_components(context, 0); |
219 vdp_context * v_context = context->next_context; | 251 z80_context * z_context = context->next_context; |
252 vdp_context * v_context = z_context->next_context; | |
220 if (vdp_port < 0x10) { | 253 if (vdp_port < 0x10) { |
221 if (vdp_port < 4) { | 254 if (vdp_port < 4) { |
222 context->value = vdp_data_port_read(v_context); | 255 context->value = vdp_data_port_read(v_context); |
223 } else if(vdp_port < 8) { | 256 } else if(vdp_port < 8) { |
224 context->value = vdp_control_port_read(v_context); | 257 context->value = vdp_control_port_read(v_context); |
234 return context; | 267 return context; |
235 } | 268 } |
236 | 269 |
237 #define TH 0x40 | 270 #define TH 0x40 |
238 #define TH_TIMEOUT 8000 | 271 #define TH_TIMEOUT 8000 |
239 #define Z80_ACK_DELAY 3 //TODO: Calculate this on the fly based on how synced up the Z80 and 68K clocks are | |
240 | |
241 uint8_t reset = 1; | |
242 uint8_t busreq = 0; | |
243 uint8_t busack = 0; | |
244 uint32_t busack_cycle = CYCLE_NEVER; | |
245 uint8_t new_busack = 0; | |
246 | 272 |
247 void io_adjust_cycles(io_port * pad, uint32_t current_cycle, uint32_t deduction) | 273 void io_adjust_cycles(io_port * pad, uint32_t current_cycle, uint32_t deduction) |
248 { | 274 { |
249 /*uint8_t control = pad->control | 0x80; | 275 /*uint8_t control = pad->control | 0x80; |
250 uint8_t th = control & pad->output; | 276 uint8_t th = control & pad->output; |
354 if(!reset) { | 380 if(!reset) { |
355 busack_cycle = context->current_cycle + Z80_ACK_DELAY; | 381 busack_cycle = context->current_cycle + Z80_ACK_DELAY; |
356 new_busack = 0; | 382 new_busack = 0; |
357 } | 383 } |
358 } else { | 384 } else { |
385 if (busreq) { | |
386 z80_context * z_context = context->next_context; | |
387 //TODO: Add necessary delay between release of busreq and resumption of execution | |
388 z_context->current_cycle = (context->current_cycle * MCLKS_PER_68K) / MCLKS_PER_Z80; | |
389 } | |
359 busreq = 0; | 390 busreq = 0; |
360 busack_cycle = CYCLE_NEVER; | 391 busack_cycle = CYCLE_NEVER; |
361 busack = 1; | 392 busack = 1; |
362 } | 393 } |
363 } else if (location == 0x1200) { | 394 } else if (location == 0x1200) { |
364 if (value & 1) { | 395 if (value & 1) { |
365 if (reset && busreq) { | 396 if (reset && busreq) { |
366 new_busack = 0; | 397 new_busack = 0; |
367 busack_cycle = context->current_cycle + Z80_ACK_DELAY; | 398 busack_cycle = context->current_cycle + Z80_ACK_DELAY; |
399 } | |
400 //TODO: Deal with the scenario in which reset is not asserted long enough | |
401 if (reset) { | |
402 z80_context * z_context = context->next_context; | |
403 need_reset = 1; | |
404 //TODO: Add necessary delay between release of reset and start of execution | |
405 z_context->current_cycle = (context->current_cycle * MCLKS_PER_68K) / MCLKS_PER_Z80; | |
368 } | 406 } |
369 reset = 0; | 407 reset = 0; |
370 } else { | 408 } else { |
371 reset = 1; | 409 reset = 1; |
372 } | 410 } |
421 if(!reset) { | 459 if(!reset) { |
422 busack_cycle = context->current_cycle + Z80_ACK_DELAY; | 460 busack_cycle = context->current_cycle + Z80_ACK_DELAY; |
423 new_busack = 0; | 461 new_busack = 0; |
424 } | 462 } |
425 } else { | 463 } else { |
464 if (busreq) { | |
465 z80_context * z_context = context->next_context; | |
466 //TODO: Add necessary delay between release of busreq and resumption of execution | |
467 z_context->current_cycle = (context->current_cycle * MCLKS_PER_68K) / MCLKS_PER_Z80; | |
468 } | |
426 busreq = 0; | 469 busreq = 0; |
427 busack_cycle = CYCLE_NEVER; | 470 busack_cycle = CYCLE_NEVER; |
428 busack = 1; | 471 busack = 1; |
429 } | 472 } |
430 } else if (location == 0x1200) { | 473 } else if (location == 0x1200) { |
431 if (value & 0x100) { | 474 if (value & 0x100) { |
432 if (reset && busreq) { | 475 if (reset && busreq) { |
433 new_busack = 0; | 476 new_busack = 0; |
434 busack_cycle = context->current_cycle + Z80_ACK_DELAY; | 477 busack_cycle = context->current_cycle + Z80_ACK_DELAY; |
478 } | |
479 //TODO: Deal with the scenario in which reset is not asserted long enough | |
480 if (reset) { | |
481 z80_context * z_context = context->next_context; | |
482 need_reset = 1; | |
483 //TODO: Add necessary delay between release of reset and start of execution | |
484 z_context->current_cycle = (context->current_cycle * MCLKS_PER_68K) / MCLKS_PER_Z80; | |
435 } | 485 } |
436 reset = 0; | 486 reset = 0; |
437 } else { | 487 } else { |
438 reset = 1; | 488 reset = 1; |
439 } | 489 } |
802 } | 852 } |
803 } | 853 } |
804 return context; | 854 return context; |
805 } | 855 } |
806 | 856 |
807 void init_run_cpu(vdp_context * vcontext, int debug, FILE * address_log) | 857 void init_run_cpu(z80_context * zcontext, int debug, FILE * address_log) |
808 { | 858 { |
809 m68k_context context; | 859 m68k_context context; |
810 x86_68k_options opts; | 860 x86_68k_options opts; |
811 init_x86_68k_opts(&opts); | 861 init_x86_68k_opts(&opts); |
812 opts.address_log = address_log; | 862 opts.address_log = address_log; |
813 init_68k_context(&context, opts.native_code_map, &opts); | 863 init_68k_context(&context, opts.native_code_map, &opts); |
814 | 864 |
815 context.next_context = vcontext; | 865 context.next_context = zcontext; |
816 //cartridge ROM | 866 //cartridge ROM |
817 context.mem_pointers[0] = cart; | 867 context.mem_pointers[0] = cart; |
818 context.target_cycle = context.sync_cycle = MCLKS_PER_FRAME/MCLKS_PER_68K; | 868 context.target_cycle = context.sync_cycle = MCLKS_PER_FRAME/MCLKS_PER_68K; |
819 //work RAM | 869 //work RAM |
820 context.mem_pointers[1] = ram; | 870 context.mem_pointers[1] = ram; |
875 render_init(width, height); | 925 render_init(width, height); |
876 } | 926 } |
877 vdp_context v_context; | 927 vdp_context v_context; |
878 | 928 |
879 init_vdp_context(&v_context); | 929 init_vdp_context(&v_context); |
880 init_run_cpu(&v_context, debug, address_log); | 930 |
931 z80_context z_context; | |
932 x86_z80_options z_opts; | |
933 init_x86_z80_opts(&z_opts); | |
934 init_z80_context(&z_context, &z_opts); | |
935 z_context.next_context = &v_context; | |
936 z_context.mem_pointers[0] = z80_ram; | |
937 z_context.sync_cycle = z_context.target_cycle = MCLKS_PER_FRAME/MCLKS_PER_Z80; | |
938 z_context.int_cycle = CYCLE_NEVER; | |
939 z_context.mem_pointers[1] = z_context.mem_pointers[2] = (uint8_t *)cart; | |
940 | |
941 init_run_cpu(&z_context, debug, address_log); | |
881 return 0; | 942 return 0; |
882 } | 943 } |