2 // Megadrive C++ module - misc memory
12 * Read one byte from the memory space.
13 * @param a Address to read
14 * @return byte or 0 if invalid.
16 uint8_t md::z80_read(uint16_t a
)
18 /* 0x0000-0x3fff: Z80 RAM */
20 return z80ram
[(a
& 0x1fff)];
21 /* 0x4000-0x5fff: YM2612 */
22 if (a
<= YM2612_RAM_END
)
24 /* 0x6000-0x6fff: bank register */
25 if (a
<= BANK_RAM_END
)
26 return 0; /* invalid address */
27 /* 0x7000-0x7fff: PSG/VDP */
28 if (a
<= PSGVDP_RAM_END
)
29 return 0; /* invalid address */
30 /* 0x8000-0xffff: M68K bank */
31 return misc_readbyte(z80_bank68k
+ (a
& 0x7fff));
35 * Write one byte to the memory
36 * @param a Address to read
37 * @param d Data (byte) to write.
39 void md::z80_write(uint16_t a
, uint8_t d
)
41 /* 0x0000-0x3fff: Z80 RAM */
42 if (a
<= Z80_RAM_END
) {
43 z80ram
[(a
& 0x1fff)] = d
;
46 /* 0x4000-0x5fff: YM2612 */
47 if (a
<= YM2612_RAM_END
) {
51 /* 0x6000-0x6fff: bank register */
52 if (a
<= BANK_RAM_END
) {
56 return; /* invalid address */
57 tmp
= (z80_bank68k
>> 1);
58 tmp
|= ((d
& 1) << 23);
59 z80_bank68k
= (tmp
& 0xff8000);
62 /* 0x7000-0x7fff: PSG */
63 if (a
<= PSGVDP_RAM_END
) {
68 return; /* invalid address */
70 /* 0x8000-0xffff: M68K bank */
71 misc_writebyte((z80_bank68k
+ (a
& 0x7fff)), d
);
77 * @param a address (ignored)
78 * @return always returns 0xff
80 uint8_t md::z80_port_read(uint16_t a
)
89 * @param a address (ignored)
90 * @param d data (ignored)
92 void md::z80_port_write(uint16_t a
, uint8_t d
)
98 uint8_t md::m68k_ROM_read(uint32_t a
)
101 if ((save_active
) && (save_len
) &&
102 (a
>= save_start
) && ((a
- save_start
) < save_len
))
103 return saveram
[((a
^ 1) - save_start
)];
105 if (ROM_ADDR(a
) < romlen
)
106 return rom
[ROM_ADDR(a
)];
111 uint8_t md::m68k_IO_read(uint32_t a
)
115 if ((!z80_st_busreq
) && (a
< 0xa04000))
117 return z80_read(a
& 0xffff);
125 /* If region hasn't been defined, guess it. */
128 region_info(c
, 0, 0, 0, 0, &c
);
129 /* Remove PAL flag if we're not in PAL mode. */
139 /* extended pad info */
140 if (aoo3_toggle
== 0)
141 return (((pad
[0] >> 8) & 0x30) + 0x00);
142 return ((pad
[0] & 0x30) + 0x40 +
143 ((pad
[0] >> 16) & 0x0f));
145 if (aoo3_toggle
== 0) {
147 return (((pad
[0] >> 8) & 0x30) +
149 return (((pad
[0] >> 8) & 0x30) +
150 0x00 + (pad
[0] & 0x03));
152 return ((pad
[0] & 0x30) + 0x40 + (pad
[0] & 0x0f));
159 /* extended pad info */
160 if (aoo5_toggle
== 0)
161 return (((pad
[1] >> 8) & 0x30) + 0x00);
162 return ((pad
[1] & 0x30) + 0x40 +
163 ((pad
[1] >> 16) & 0x0f));
165 if (aoo5_toggle
== 0) {
167 return (((pad
[1] >> 8) & 0x30) +
169 return (((pad
[1] >> 8) & 0x30) +
170 0x00 + (pad
[1] & 0x03));
172 return ((pad
[1] & 0x30) + 0x40 + (pad
[1] & 0x0f));
190 if ((a
& 0xa1000c) == 0xa1000c)
193 if ((a
& 0xfffffe) == 0xa11000)
196 if ((a
& 0xffff01) == 0xa11100)
197 return (!z80_st_busreq
| ((m68k_read_pc() >> 8) & 0xfe));
198 if ((a
& 0xffff01) == 0xa11101)
199 return (m68k_read_pc() & 0xff);
201 if ((a
& 0xffff01) == 0xa11200)
202 return (m68k_read_pc() >> 8);
203 if ((a
& 0xffff01) == 0xa11201)
204 return (m68k_read_pc() & 0xff);
205 return 0; /* invalid address */
208 uint8_t md::m68k_VDP_read(uint32_t a
)
215 vdp
.cmd_pending
= false;
216 return vdp
.readbyte();
220 vdp
.cmd_pending
= false;
227 return calculate_coo8();
229 return calculate_coo9();
233 return 0; /* invalid address */
237 * Read a byte from the m68Ks ram.
238 * @param a Address to read.
240 uint8_t md::misc_readbyte(uint32_t a
)
244 /* 0x000000-0x7fffff: ROM */
245 if (a
<= M68K_ROM_END
) {
246 return m68k_ROM_read(a
);
249 /* 0x800000-0x80001f: Sega Pico I/O area */
250 if ((pico_enabled
) &&
251 ((a
>= 0x800000) && (a
<= 0x80001f))) {
254 case 1: // Version register
266 case 5: // MSB of X coordinate for pen
267 return pico_pen_coords
[0] >> 8;
268 case 7: // LSB of X coordinate for pen
269 return pico_pen_coords
[0] & 0xff;
270 case 9: // MSB of Y coordinate for pen
271 return pico_pen_coords
[1] >> 8;
272 case 0xB: // LSB of Y coordinate for pen
273 return pico_pen_coords
[1] & 0xff;
276 /* 0x800020-0xafffff: Sega Pico empty area */
277 if ((pico_enabled
) &&
281 /* 0x800000-0x9fffff: empty area */
282 if (a
<= M68K_EMPTY1_END
) {
284 * http://cgfm2.emuviews.com/txt/gen-hw.txt
285 * see section 1 point 3 for what these addresses do.
289 /* 0xa00000-0xafffff: system I/O and control */
290 if (a
<= M68K_IO_END
) {
291 return m68k_IO_read(a
);
293 /* 0xb00000-0xbfffff: empty area */
294 if (a
<= M68K_EMPTY2_END
)
296 /* 0xc00000-0xdfffff: VDP/PSG */
297 if (a
<= M68K_VDP_END
) {
298 return m68k_VDP_read(a
);
300 /* 0xe00000-0xfeffff: invalid addresses, mirror RAM */
301 /* 0xff0000-0xffffff: RAM */
302 return ram
[((a
^ 1) & 0xffff)];
305 void md::m68k_ROM_write(uint32_t a
, uint8_t d
)
308 if ((!save_prot
) && (save_len
) &&
309 (a
>= save_start
) && ((a
- save_start
) < save_len
))
310 saveram
[((a
^ 1) - save_start
)] = d
;
312 /* Allow debugger to write to the ROM. */
313 if ((debug_trap
) && (ROM_ADDR(a
) < romlen
))
314 rom
[ROM_ADDR(a
)] = d
;
318 void md::m68k_IO_write(uint32_t a
, uint8_t d
)
322 if ((!z80_st_busreq
) && (a
< 0xa04000))
324 z80_write((a
& 0xffff), d
);
330 m68k_busreq_request();
332 m68k_busreq_cancel();
339 /* cancel RESET state if nonzero */
342 else if (z80_st_reset
== 0) {
343 if (z80_st_busreq
== 0)
353 /* I/O port access */
356 if ((aoo3_six
>= 0) && ((d
& 0x40) == 0) &&
359 if (aoo3_six
> 0xc00000)
360 aoo3_six
&= ~0x400000;
361 /* keep it circling around a high value */
366 aoo3_six_timeout
= 0;
370 if ((aoo5_six
>= 0) && ((d
& 0x40) == 0) &&
373 if (aoo5_six
> 0xc00000)
374 aoo5_six
&= ~0x400000;
375 /* keep it circling around a high value */
380 aoo5_six_timeout
= 0;
385 /* save RAM status */
388 Bit 0: 0 = ROM active, 1 = SRAM active
389 Bit 1: 0 = writable protect
391 save_active
= (d
& 1);
399 * write a byte to the m68Ks ram.
400 * @param a Address to write.
401 * @param d Date (byte) two write.
403 void md::misc_writebyte(uint32_t a
, uint8_t d
)
407 /* 0x000000-0x7fffff: ROM */
408 if (a
<= M68K_ROM_END
) {
409 m68k_ROM_write(a
, d
);
412 /* 0x800000-0x9fffff: empty area */
413 if (a
<= M68K_EMPTY1_END
)
415 /* 0xa00000-0xafffff: system I/O and control */
416 if (a
<= M68K_IO_END
) {
420 /* 0xb00000-0xbfffff: empty area */
421 if (a
<= M68K_EMPTY2_END
)
423 /* 0xc00000-0xdfffff: VDP/PSG */
424 if (a
< M68K_VDP_END
) {
427 misc_writeword(a
, (d
| (d
<< 8)));
435 /* 0xe00000-0xfeffff: invalid addresses, mirror RAM */
436 /* 0xff0000-0xffffff: RAM */
437 ram
[((a
^ 1) & 0xffff)] = d
;
442 * Read a word from the m68k memory.
443 * There are quirks with word wide reads see section 1.2 of
444 * http://cgfm2.emuviews.com/txt/gen-hw.txt
445 * @param a Address to read
446 * @return word from memory.
448 uint16_t md::misc_readword(uint32_t a
)
454 if ((a
& 0xffff00) == 0xa11100)
455 return ((!z80_st_busreq
<< 8) | (m68k_read_pc() & 0xfeff));
457 if ((a
& 0xffff00) == 0xa11200)
458 return m68k_read_pc();
460 if ((a
>= 0xc00000) && (a
< 0xe00000)) {
465 vdp
.cmd_pending
= false;
466 return vdp
.readword();
471 return (((coo4
& 0xff) << 8) | (coo5
& 0xff));
476 return ((calculate_coo8() << 8) |
477 (calculate_coo9() & 0xff));
480 /* else pass onto readbyte */
481 ret
= (misc_readbyte(a
) << 8);
482 ret
|= misc_readbyte(a
+ 1);
487 * Write a word to m68k memory
488 * @param a Address to write to.
489 * @param d Data to write.
491 void md::misc_writeword(uint32_t a
, uint16_t d
)
495 if ((a
>= 0xa00000) && (a
< 0xa10000)) {
496 if ((!z80_st_busreq
) && (a
< 0xa04000))
498 z80_write((a
& 0xffff), (d
>> 8));
501 /* BUSREQ and RESET */
502 if ((a
== 0xa11100) ||
504 misc_writebyte(a
, (d
>> 8));
508 if ((a
>= 0xc00000) && (a
< 0xe00000)) {
514 vdp
.cmd_pending
= false;
520 /* second half of a command */
521 if (vdp
.cmd_pending
) {
526 if ((d
& 0xc000) == 0x8000) {
527 uint8_t addr
= ((d
>> 8) & 0x1f);
528 vdp
.write_reg(addr
, d
);
531 /* first half of a command */
533 vdp
.cmd_pending
= true;
537 /* else pass onto writebyte */
538 misc_writebyte(a
, (d
>> 8));
539 misc_writebyte((a
+ 1), (d
& 0xff));
544 // read/write functions called by the CPU to access memory.
545 // while values used are 32 bits, only the appropriate number
546 // of bits are relevant (i.e. in write_memory_8, only the lower 8 bits
547 // of value should be written to memory).
548 // address will be a 24-bit value.
550 /* Read from anywhere */
551 extern "C" unsigned int m68k_read_memory_8(unsigned int address
)
553 return md::md_musa
->misc_readbyte(address
);
556 extern "C" unsigned int m68k_read_memory_16(unsigned int address
)
558 return md::md_musa
->misc_readword(address
);
561 extern "C" unsigned int m68k_read_memory_32(unsigned int address
)
563 return ((md::md_musa
->misc_readword(address
) << 16) |
564 (md::md_musa
->misc_readword(address
+ 2) & 0xffff));
567 /* Read data immediately following the PC */
568 extern "C" unsigned int m68k_read_immediate_8(unsigned int address
)
570 return m68k_read_memory_8(address
);
573 extern "C" unsigned int m68k_read_immediate_16(unsigned int address
)
575 return m68k_read_memory_16(address
);
578 extern "C" unsigned int m68k_read_immediate_32(unsigned int address
)
580 return m68k_read_memory_32(address
);
583 /* Read an instruction (16-bit word immeditately after PC) */
584 extern "C" unsigned int m68k_read_instruction(unsigned int address
)
586 return m68k_read_memory_16(address
);
589 /* Write to anywhere */
590 extern "C" void m68k_write_memory_8(unsigned int address
, unsigned int value
)
592 md::md_musa
->misc_writebyte(address
, value
);
595 extern "C" void m68k_write_memory_16(unsigned int address
, unsigned int value
)
597 md::md_musa
->misc_writeword(address
, value
);
600 extern "C" void m68k_write_memory_32(unsigned int address
, unsigned int value
)
602 md::md_musa
->misc_writeword(address
, ((value
>> 16) & 0xffff));
603 md::md_musa
->misc_writeword((address
+ 2), (value
& 0xffff));
610 /* Read from anywhere */
611 extern "C" uint32_t cyclone_read_memory_8(uint32_t address
)
613 return md::md_cyclone
->misc_readbyte(address
);
616 extern "C" uint32_t cyclone_read_memory_16(uint32_t address
)
618 return md::md_cyclone
->misc_readword(address
);
621 extern "C" uint32_t cyclone_read_memory_32(uint32_t address
)
623 return ((md::md_cyclone
->misc_readword(address
) << 16) |
624 (md::md_cyclone
->misc_readword(address
+ 2) & 0xffff));
627 /* Write to anywhere */
628 extern "C" void cyclone_write_memory_8(uint32_t address
, uint8_t value
)
630 md::md_cyclone
->misc_writebyte(address
, value
);
633 extern "C" void cyclone_write_memory_16(uint32_t address
, uint16_t value
)
635 md::md_cyclone
->misc_writeword(address
, value
);
638 extern "C" void cyclone_write_memory_32(uint32_t address
, uint32_t value
)
640 md::md_cyclone
->misc_writeword(address
, ((value
>> 16) & 0xffff));
641 md::md_cyclone
->misc_writeword((address
+ 2), (value
& 0xffff));
644 uintptr_t md::checkpc(uintptr_t pc
)
646 static uint8_t zero
[(M68K_EMPTY1_END
+ 1)];
648 pc
-= cyclonecpu
.membase
; // Get the real program counter.
650 pc
&= 0x00ffffff; // Clip to 24-bit.
651 if ((save_active
) && (save_len
) &&
652 (pc
>= save_start
) && ((pc
- save_start
) < save_len
)) {
653 cyclonecpu
.membase
= (uintptr_t)saveram
;
657 cyclonecpu
.membase
= (uintptr_t)rom
; // Jump to ROM.
658 else if (pc
<= M68K_EMPTY1_END
)
659 cyclonecpu
.membase
= (uintptr_t)zero
; // Scratch area.
660 else if (pc
>= 0xe00000) {
662 cyclonecpu
.membase
= (uintptr_t)ram
; // Jump to RAM.
665 DEBUG(("PC out of bounds: %06x", pc
));
666 // Freeze, avoid crashing the emulator.
667 cyclonecpu
.membase
= (uintptr_t)no_rom
;
670 return (cyclonecpu
.membase
+ pc
); // New program counter.
673 extern "C" uintptr_t cyclone_checkpc(uintptr_t pc
)
675 return md::md_cyclone
->checkpc(pc
);
678 #endif // WITH_CYCLONE
682 extern "C" unsigned star_readbyte(unsigned a
, unsigned d
)
685 return md::md_star
->misc_readbyte(a
);
688 extern "C" unsigned star_readword(unsigned a
, unsigned d
)
691 return md::md_star
->misc_readword(a
);
694 extern "C" unsigned star_writebyte(unsigned a
, unsigned d
)
696 md::md_star
->misc_writebyte(a
, d
);
700 extern "C" unsigned star_writeword(unsigned a
, unsigned d
)
702 md::md_star
->misc_writeword(a
, d
);
711 In case the assembly version of MZ80 is used (WITH_X86_MZ80), prevent
712 GCC from optimizing sibling calls (-foptimize-sibling-calls, enabled
713 by default at -O2 and above). The ASM code doesn't expect this and
718 #define MZ80_NOSIBCALL(t, w) *((volatile t *)&(w))
720 #define MZ80_NOSIBCALL(t, w) (w)
723 extern "C" UINT8
mz80_read(UINT32 a
, struct MemoryReadByte
*unused
)
726 return md::md_mz80
->z80_read(MZ80_NOSIBCALL(UINT32
, a
));
729 extern "C" void mz80_write(UINT32 a
, UINT8 d
, struct MemoryWriteByte
*unused
)
732 md::md_mz80
->z80_write(MZ80_NOSIBCALL(UINT32
, a
), d
);
735 extern "C" UINT16
mz80_ioread(UINT16 a
, struct z80PortRead
*unused
)
738 return md::md_mz80
->z80_port_read(MZ80_NOSIBCALL(UINT16
, a
));
741 extern "C" void mz80_iowrite(UINT16 a
, UINT8 d
, struct z80PortWrite
*unused
)
744 return md::md_mz80
->z80_port_write(MZ80_NOSIBCALL(UINT16
, a
), d
);
751 extern "C" uint8_t cz80_memread(void *ctx
, uint16_t a
)
753 class md
* md
= (class md
*)ctx
;
755 return md
->z80_read(a
);
758 extern "C" void cz80_memwrite(void *ctx
, uint16_t a
, uint8_t d
)
760 class md
* md
= (class md
*)ctx
;
765 extern "C" uint16_t cz80_memread16(void *ctx
, uint16_t a
)
767 class md
* md
= (class md
*)ctx
;
769 return ((uint16_t)md
->z80_read(a
) |
770 ((uint16_t)md
->z80_read(a
+ 1) << 8));
773 extern "C" void cz80_memwrite16(void *ctx
, uint16_t a
, uint16_t d
)
775 class md
* md
= (class md
*)ctx
;
777 md
->z80_write(a
, (uint8_t)d
);
778 md
->z80_write((a
+ 1), (uint8_t)(d
>> 8));
781 extern "C" uint8_t cz80_ioread(void *ctx
, uint16_t a
)
783 class md
* md
= (class md
*)ctx
;
785 return md
->z80_port_read(a
);
788 extern "C" void cz80_iowrite(void *ctx
, uint16_t a
, uint8_t d
)
790 class md
* md
= (class md
*)ctx
;
792 md
->z80_port_write(a
, d
);
799 uintptr_t md::drz80_rebase_pc(uint16_t address
)
801 // PC in memory - rebase PC into memory.
802 drz80
.Z80PC_BASE
= (uintptr_t)z80ram
;
803 return (drz80
.Z80PC_BASE
+ address
);
806 uintptr_t md::drz80_rebase_sp(uint16_t address
)
808 // SP in memory - rebase SP into memory.
809 drz80
.Z80SP_BASE
= (uintptr_t)z80ram
;
810 return (drz80
.Z80SP_BASE
+ address
);
813 uintptr_t drz80_rebaseSP(uint16_t new_sp
)
815 return md::md_drz80
->drz80_rebase_sp(new_sp
);
818 uintptr_t drz80_rebasePC(uint16_t new_pc
)
820 return md::md_drz80
->drz80_rebase_pc(new_pc
);
823 uint8_t drz80_read8(uint16_t a
)
825 return md::md_drz80
->z80_read(a
);
828 uint16_t drz80_read16(uint16_t a
)
830 return ((uint16_t)md::md_drz80
->z80_read(a
) |
831 ((uint16_t)md::md_drz80
->z80_read(a
+ 1) << 8));
834 void drz80_write8(uint8_t d
, uint16_t a
)
836 md::md_drz80
->z80_write(a
, d
);
839 void drz80_write16(uint16_t d
, uint16_t a
)
841 md::md_drz80
->z80_write(a
, (uint8_t)d
);
842 md::md_drz80
->z80_write((a
+ 1), (uint8_t)(d
>> 8));
845 uint8_t drz80_in(uint16_t p
)
851 void drz80_out(uint16_t p
, uint8_t d
)