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 }