Mercurial > repos > blastem
comparison blastem.c @ 153:42c031184e8a
Implement access to Z80 RAM
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Fri, 04 Jan 2013 21:47:09 -0800 |
parents | 139e5dcd6aa3 |
children | a2ab895d9708 |
comparison
equal
deleted
inserted
replaced
152:79958b95526f | 153:42c031184e8a |
---|---|
7 #include <stdio.h> | 7 #include <stdio.h> |
8 #include <stdlib.h> | 8 #include <stdlib.h> |
9 | 9 |
10 #define CARTRIDGE_WORDS 0x200000 | 10 #define CARTRIDGE_WORDS 0x200000 |
11 #define RAM_WORDS 32 * 1024 | 11 #define RAM_WORDS 32 * 1024 |
12 #define Z80_RAM_BYTES 8 * 1024 | |
12 #define MCLKS_PER_68K 7 | 13 #define MCLKS_PER_68K 7 |
13 //TODO: Figure out the exact value for this | 14 //TODO: Figure out the exact value for this |
14 #define MCLKS_PER_FRAME (MCLKS_LINE*262) | 15 #define MCLKS_PER_FRAME (MCLKS_LINE*262) |
15 #define CYCLE_NEVER 0xFFFFFFFF | 16 #define CYCLE_NEVER 0xFFFFFFFF |
16 | 17 |
17 uint16_t cart[CARTRIDGE_WORDS]; | 18 uint16_t cart[CARTRIDGE_WORDS]; |
18 uint16_t ram[RAM_WORDS]; | 19 uint16_t ram[RAM_WORDS]; |
20 uint8_t z80_ram[Z80_RAM_BYTES]; | |
19 | 21 |
20 io_port gamepad_1; | 22 io_port gamepad_1; |
21 io_port gamepad_2; | 23 io_port gamepad_2; |
22 | 24 |
23 #ifndef MIN | 25 #ifndef MIN |
273 }*/ | 275 }*/ |
274 } | 276 } |
275 | 277 |
276 m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value) | 278 m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value) |
277 { | 279 { |
278 if (location < 0x100) { | 280 if (location < 0x10000) { |
279 switch(location/2) | 281 if (busack_cycle > context->current_cycle) { |
280 { | 282 busack = new_busack; |
281 case 0x1: | 283 busack_cycle = CYCLE_NEVER; |
282 io_data_write(&gamepad_1, context, value); | 284 } |
283 break; | 285 if (!(busack || reset)) { |
284 case 0x2: | 286 location &= 0x7FFF; |
285 io_data_write(&gamepad_2, context, value); | 287 if (location < 0x4000) { |
286 break; | 288 z80_ram[location & 0x1FFF] = value; |
287 case 0x3://PORT C Data | 289 } |
288 break; | 290 } |
289 case 0x4: | 291 } else { |
290 gamepad_1.control = value; | 292 location &= 0x1FFF; |
291 break; | 293 if (location < 0x100) { |
292 case 0x5: | 294 switch(location/2) |
293 gamepad_2.control = value; | 295 { |
294 break; | 296 case 0x1: |
295 } | 297 io_data_write(&gamepad_1, context, value); |
296 } else { | 298 break; |
297 if (location == 0x1100) { | 299 case 0x2: |
298 if (busack_cycle > context->current_cycle) { | 300 io_data_write(&gamepad_2, context, value); |
299 busack = new_busack; | 301 break; |
300 busack_cycle = CYCLE_NEVER; | 302 case 0x3://PORT C Data |
301 } | 303 break; |
302 if (value & 1) { | 304 case 0x4: |
303 busreq = 1; | 305 gamepad_1.control = value; |
304 if(!reset) { | 306 break; |
305 busack_cycle = context->current_cycle + Z80_ACK_DELAY; | 307 case 0x5: |
306 new_busack = 0; | 308 gamepad_2.control = value; |
307 } | 309 break; |
308 } else { | 310 } |
309 busreq = 0; | 311 } else { |
310 busack_cycle = CYCLE_NEVER; | 312 if (location == 0x1100) { |
311 busack = 1; | 313 if (busack_cycle > context->current_cycle) { |
312 } | 314 busack = new_busack; |
313 } else if (location == 0x1200) { | 315 busack_cycle = CYCLE_NEVER; |
314 if (value & 1) { | 316 } |
315 if (reset && busreq) { | 317 if (value & 1) { |
316 new_busack = 0; | 318 busreq = 1; |
317 busack_cycle = context->current_cycle + Z80_ACK_DELAY; | 319 if(!reset) { |
318 } | 320 busack_cycle = context->current_cycle + Z80_ACK_DELAY; |
319 reset = 0; | 321 new_busack = 0; |
320 } else { | 322 } |
321 reset = 1; | 323 } else { |
324 busreq = 0; | |
325 busack_cycle = CYCLE_NEVER; | |
326 busack = 1; | |
327 } | |
328 } else if (location == 0x1200) { | |
329 if (value & 1) { | |
330 if (reset && busreq) { | |
331 new_busack = 0; | |
332 busack_cycle = context->current_cycle + Z80_ACK_DELAY; | |
333 } | |
334 reset = 0; | |
335 } else { | |
336 reset = 1; | |
337 } | |
322 } | 338 } |
323 } | 339 } |
324 } | 340 } |
325 return context; | 341 return context; |
326 } | 342 } |
327 | 343 |
328 m68k_context * io_write_w(uint32_t location, m68k_context * context, uint16_t value) | 344 m68k_context * io_write_w(uint32_t location, m68k_context * context, uint16_t value) |
329 { | 345 { |
330 if (location < 0x100) { | 346 if (location < 0x10000) { |
331 switch(location/2) | 347 if (busack_cycle > context->current_cycle) { |
332 { | 348 busack = new_busack; |
333 case 0x1: | 349 busack_cycle = CYCLE_NEVER; |
334 io_data_write(&gamepad_1, context, value); | 350 } |
335 break; | 351 if (!(busack || reset)) { |
336 case 0x2: | 352 location &= 0x7FFF; |
337 io_data_write(&gamepad_2, context, value); | 353 if (location < 0x4000) { |
338 break; | 354 z80_ram[location & 0x1FFE] = value >> 8; |
339 case 0x3://PORT C Data | 355 } |
340 break; | 356 } |
341 case 0x4: | 357 } else { |
342 gamepad_1.control = value; | 358 location &= 0x1FFF; |
343 break; | 359 if (location < 0x100) { |
344 case 0x5: | 360 switch(location/2) |
345 gamepad_2.control = value; | 361 { |
346 break; | 362 case 0x1: |
347 } | 363 io_data_write(&gamepad_1, context, value); |
348 } else { | 364 break; |
349 //printf("IO Write of %X to %X @ %d\n", value, location, context->current_cycle); | 365 case 0x2: |
350 if (location == 0x1100) { | 366 io_data_write(&gamepad_2, context, value); |
351 if (busack_cycle > context->current_cycle) { | 367 break; |
352 busack = new_busack; | 368 case 0x3://PORT C Data |
353 busack_cycle = CYCLE_NEVER; | 369 break; |
354 } | 370 case 0x4: |
355 if (value & 0x100) { | 371 gamepad_1.control = value; |
356 busreq = 1; | 372 break; |
357 if(!reset) { | 373 case 0x5: |
358 busack_cycle = context->current_cycle + Z80_ACK_DELAY; | 374 gamepad_2.control = value; |
359 new_busack = 0; | 375 break; |
360 } | 376 } |
361 } else { | 377 } else { |
362 busreq = 0; | 378 //printf("IO Write of %X to %X @ %d\n", value, location, context->current_cycle); |
363 busack_cycle = CYCLE_NEVER; | 379 if (location == 0x1100) { |
364 busack = 1; | 380 if (busack_cycle > context->current_cycle) { |
365 } | 381 busack = new_busack; |
366 } else if (location == 0x1200) { | 382 busack_cycle = CYCLE_NEVER; |
367 if (value & 0x100) { | 383 } |
368 if (reset && busreq) { | 384 if (value & 0x100) { |
369 new_busack = 0; | 385 busreq = 1; |
370 busack_cycle = context->current_cycle + Z80_ACK_DELAY; | 386 if(!reset) { |
371 } | 387 busack_cycle = context->current_cycle + Z80_ACK_DELAY; |
372 reset = 0; | 388 new_busack = 0; |
373 } else { | 389 } |
374 reset = 1; | 390 } else { |
391 busreq = 0; | |
392 busack_cycle = CYCLE_NEVER; | |
393 busack = 1; | |
394 } | |
395 } else if (location == 0x1200) { | |
396 if (value & 0x100) { | |
397 if (reset && busreq) { | |
398 new_busack = 0; | |
399 busack_cycle = context->current_cycle + Z80_ACK_DELAY; | |
400 } | |
401 reset = 0; | |
402 } else { | |
403 reset = 1; | |
404 } | |
375 } | 405 } |
376 } | 406 } |
377 } | 407 } |
378 return context; | 408 return context; |
379 } | 409 } |
384 #define NO_DISK 0x20 | 414 #define NO_DISK 0x20 |
385 uint8_t version_reg = NO_DISK | USA; | 415 uint8_t version_reg = NO_DISK | USA; |
386 | 416 |
387 m68k_context * io_read(uint32_t location, m68k_context * context) | 417 m68k_context * io_read(uint32_t location, m68k_context * context) |
388 { | 418 { |
389 if (location < 0x100) { | 419 if (location < 0x10000) { |
390 switch(location/2) | 420 if (busack_cycle > context->current_cycle) { |
391 { | 421 busack = new_busack; |
392 case 0x0: | 422 busack_cycle = CYCLE_NEVER; |
393 //version bits should be 0 for now since we're not emulating TMSS | 423 } |
394 //Not sure about the other bits | 424 if (!(busack || reset)) { |
395 context->value = version_reg; | 425 location &= 0x7FFF; |
396 break; | 426 if (location < 0x4000) { |
397 case 0x1: | 427 context->value = z80_ram[location & 0x1FFF]; |
398 io_data_read(&gamepad_1, context); | 428 } else { |
399 break; | 429 context->value = 0xFF; |
400 case 0x2: | 430 } |
401 io_data_read(&gamepad_2, context); | 431 } else { |
402 break; | 432 context->value = 0xFF; |
403 case 0x3://PORT C Data | 433 } |
404 break; | 434 } else { |
405 case 0x4: | 435 location &= 0x1FFF; |
406 context->value = gamepad_1.control; | 436 if (location < 0x100) { |
407 break; | 437 switch(location/2) |
408 case 0x5: | 438 { |
409 context->value = gamepad_2.control; | 439 case 0x0: |
410 break; | 440 //version bits should be 0 for now since we're not emulating TMSS |
411 } | 441 //Not sure about the other bits |
412 } else { | 442 context->value = version_reg; |
413 if (location == 0x1100) { | 443 break; |
414 if (busack_cycle > context->current_cycle) { | 444 case 0x1: |
415 busack = new_busack; | 445 io_data_read(&gamepad_1, context); |
416 busack_cycle = CYCLE_NEVER; | 446 break; |
417 } | 447 case 0x2: |
418 context->value = reset || busack; | 448 io_data_read(&gamepad_2, context); |
419 //printf("Byte read of BUSREQ returned %d @ %d (reset: %d, busack: %d)\n", context->value, context->current_cycle, reset, busack); | 449 break; |
420 } else if (location == 0x1200) { | 450 case 0x3://PORT C Data |
421 context->value = !reset; | 451 break; |
422 } else { | 452 case 0x4: |
423 printf("Byte read of unknown IO location: %X\n", location); | 453 context->value = gamepad_1.control; |
454 break; | |
455 case 0x5: | |
456 context->value = gamepad_2.control; | |
457 break; | |
458 } | |
459 } else { | |
460 if (location == 0x1100) { | |
461 if (busack_cycle > context->current_cycle) { | |
462 busack = new_busack; | |
463 busack_cycle = CYCLE_NEVER; | |
464 } | |
465 context->value = reset || busack; | |
466 //printf("Byte read of BUSREQ returned %d @ %d (reset: %d, busack: %d)\n", context->value, context->current_cycle, reset, busack); | |
467 } else if (location == 0x1200) { | |
468 context->value = !reset; | |
469 } else { | |
470 printf("Byte read of unknown IO location: %X\n", location); | |
471 } | |
424 } | 472 } |
425 } | 473 } |
426 return context; | 474 return context; |
427 } | 475 } |
428 | 476 |
429 m68k_context * io_read_w(uint32_t location, m68k_context * context) | 477 m68k_context * io_read_w(uint32_t location, m68k_context * context) |
430 { | 478 { |
431 if (location < 0x100) { | 479 if (location < 0x10000) { |
432 switch(location/2) | 480 if (busack_cycle > context->current_cycle) { |
433 { | 481 busack = new_busack; |
434 case 0x0: | 482 busack_cycle = CYCLE_NEVER; |
435 //version bits should be 0 for now since we're not emulating TMSS | 483 } |
436 //Not sure about the other bits | 484 if (!(busack || reset)) { |
437 context->value = 0; | 485 location &= 0x7FFF; |
438 break; | 486 if (location < 0x4000) { |
439 case 0x1: | 487 context->value = z80_ram[location & 0x1FFE]; |
440 io_data_read(&gamepad_1, context); | 488 context->value |= context->value << 8; |
441 break; | 489 } else { |
442 case 0x2: | 490 context->value = 0xFFFF; |
443 io_data_read(&gamepad_2, context); | 491 } |
444 break; | 492 } else { |
445 case 0x3://PORT C Data | 493 context->value = 0xFFFF; |
446 break; | 494 } |
447 case 0x4: | 495 } else { |
448 context->value = gamepad_1.control; | 496 location &= 0x1FFF; |
449 break; | 497 if (location < 0x100) { |
450 case 0x5: | 498 switch(location/2) |
451 context->value = gamepad_2.control; | 499 { |
452 break; | 500 case 0x0: |
453 case 0x6: | 501 //version bits should be 0 for now since we're not emulating TMSS |
454 //PORT C Control | 502 //Not sure about the other bits |
455 context->value = 0; | 503 context->value = 0; |
456 break; | 504 break; |
457 } | 505 case 0x1: |
458 context->value = context->value | (context->value << 8); | 506 io_data_read(&gamepad_1, context); |
459 //printf("Word read to %X returned %d\n", location, context->value); | 507 break; |
460 } else { | 508 case 0x2: |
461 if (location == 0x1100) { | 509 io_data_read(&gamepad_2, context); |
462 if (busack_cycle > context->current_cycle) { | 510 break; |
463 busack = new_busack; | 511 case 0x3://PORT C Data |
464 busack_cycle = CYCLE_NEVER; | 512 break; |
465 } | 513 case 0x4: |
466 context->value = (reset || busack) << 8; | 514 context->value = gamepad_1.control; |
467 //printf("Word read of BUSREQ returned %d\n", context->value); | 515 break; |
468 } else if (location == 0x1200) { | 516 case 0x5: |
469 context->value = (!reset) << 8; | 517 context->value = gamepad_2.control; |
470 } else { | 518 break; |
471 printf("Word read of unknown IO location: %X\n", location); | 519 case 0x6: |
520 //PORT C Control | |
521 context->value = 0; | |
522 break; | |
523 } | |
524 context->value = context->value | (context->value << 8); | |
525 //printf("Word read to %X returned %d\n", location, context->value); | |
526 } else { | |
527 if (location == 0x1100) { | |
528 if (busack_cycle > context->current_cycle) { | |
529 busack = new_busack; | |
530 busack_cycle = CYCLE_NEVER; | |
531 } | |
532 context->value = (reset || busack) << 8; | |
533 //printf("Word read of BUSREQ returned %d\n", context->value); | |
534 } else if (location == 0x1200) { | |
535 context->value = (!reset) << 8; | |
536 } else { | |
537 printf("Word read of unknown IO location: %X\n", location); | |
538 } | |
472 } | 539 } |
473 } | 540 } |
474 return context; | 541 return context; |
475 } | 542 } |
476 | 543 |