| 1 | #include "pico_int.h" |
| 2 | #include "sound/sn76496.h" |
| 3 | |
| 4 | #define Z80_MEM_SHIFT 13 |
| 5 | |
| 6 | unsigned long z80_read_map [0x10000 >> Z80_MEM_SHIFT]; |
| 7 | unsigned long z80_write_map[0x10000 >> Z80_MEM_SHIFT]; |
| 8 | |
| 9 | void MEMH_FUNC z80_map_set(unsigned long *map, int start_addr, int end_addr, |
| 10 | void *func_or_mh, int is_func) |
| 11 | { |
| 12 | unsigned long addr = (unsigned long)func_or_mh; |
| 13 | int mask = (1 << Z80_MEM_SHIFT) - 1; |
| 14 | int i; |
| 15 | |
| 16 | if ((start_addr & mask) != 0 || (end_addr & mask) != mask) |
| 17 | elprintf(EL_STATUS|EL_ANOMALY, "z80_map_set: tried to map bad range: %04x-%04x", |
| 18 | start_addr, end_addr); |
| 19 | |
| 20 | if (addr & 1) { |
| 21 | elprintf(EL_STATUS|EL_ANOMALY, "z80_map_set: ptr is not aligned: %08lx", addr); |
| 22 | return; |
| 23 | } |
| 24 | |
| 25 | for (i = start_addr >> Z80_MEM_SHIFT; i <= end_addr >> Z80_MEM_SHIFT; i++) |
| 26 | if (is_func) |
| 27 | map[i] = (addr >> 1) | (1 << (sizeof(addr) * 8 - 1)); |
| 28 | else |
| 29 | map[i] = (addr - (i << Z80_MEM_SHIFT)) >> 1; |
| 30 | } |
| 31 | |
| 32 | #ifdef _USE_MZ80 |
| 33 | |
| 34 | // memhandlers for mz80 core |
| 35 | unsigned char mz80_read(UINT32 a, struct MemoryReadByte *w) { return z80_read(a); } |
| 36 | void mz80_write(UINT32 a, UINT8 d, struct MemoryWriteByte *w) { z80_write(d, a); } |
| 37 | |
| 38 | // structures for mz80 core |
| 39 | static struct MemoryReadByte mz80_mem_read[]= |
| 40 | { |
| 41 | {0x0000,0xffff,mz80_read}, |
| 42 | {(UINT32) -1,(UINT32) -1,NULL} |
| 43 | }; |
| 44 | static struct MemoryWriteByte mz80_mem_write[]= |
| 45 | { |
| 46 | {0x0000,0xffff,mz80_write}, |
| 47 | {(UINT32) -1,(UINT32) -1,NULL} |
| 48 | }; |
| 49 | static struct z80PortRead mz80_io_read[] ={ |
| 50 | {(UINT16) -1,(UINT16) -1,NULL} |
| 51 | }; |
| 52 | static struct z80PortWrite mz80_io_write[]={ |
| 53 | {(UINT16) -1,(UINT16) -1,NULL} |
| 54 | }; |
| 55 | |
| 56 | int mz80_run(int cycles) |
| 57 | { |
| 58 | int ticks_pre = mz80GetElapsedTicks(0); |
| 59 | mz80exec(cycles); |
| 60 | return mz80GetElapsedTicks(0) - ticks_pre; |
| 61 | } |
| 62 | |
| 63 | #endif |
| 64 | |
| 65 | #ifdef _USE_DRZ80 |
| 66 | |
| 67 | struct DrZ80 drZ80; |
| 68 | |
| 69 | static unsigned int DrZ80_rebasePC(unsigned short a) |
| 70 | { |
| 71 | drZ80.Z80PC_BASE = (unsigned int) Pico.zram; |
| 72 | return drZ80.Z80PC_BASE + a; |
| 73 | } |
| 74 | |
| 75 | static unsigned int DrZ80_rebaseSP(unsigned short a) |
| 76 | { |
| 77 | drZ80.Z80SP_BASE = (unsigned int) Pico.zram; |
| 78 | return drZ80.Z80SP_BASE + a; |
| 79 | } |
| 80 | #endif |
| 81 | |
| 82 | |
| 83 | PICO_INTERNAL void z80_init(void) |
| 84 | { |
| 85 | #ifdef _USE_MZ80 |
| 86 | struct mz80context z80; |
| 87 | |
| 88 | // z80 |
| 89 | mz80init(); |
| 90 | // Modify the default context |
| 91 | mz80GetContext(&z80); |
| 92 | |
| 93 | // point mz80 stuff |
| 94 | z80.z80Base=Pico.zram; |
| 95 | z80.z80MemRead=mz80_mem_read; |
| 96 | z80.z80MemWrite=mz80_mem_write; |
| 97 | z80.z80IoRead=mz80_io_read; |
| 98 | z80.z80IoWrite=mz80_io_write; |
| 99 | |
| 100 | mz80SetContext(&z80); |
| 101 | #endif |
| 102 | #ifdef _USE_DRZ80 |
| 103 | memset(&drZ80, 0, sizeof(drZ80)); |
| 104 | drZ80.z80_rebasePC=DrZ80_rebasePC; |
| 105 | drZ80.z80_rebaseSP=DrZ80_rebaseSP; |
| 106 | drZ80.z80_read8 =(void *)z80_read_map; |
| 107 | drZ80.z80_read16 =NULL; |
| 108 | drZ80.z80_write8 =(void *)z80_write_map; |
| 109 | drZ80.z80_write16 =NULL; |
| 110 | drZ80.z80_irq_callback=NULL; |
| 111 | #endif |
| 112 | #ifdef _USE_CZ80 |
| 113 | memset(&CZ80, 0, sizeof(CZ80)); |
| 114 | Cz80_Init(&CZ80); |
| 115 | Cz80_Set_ReadB(&CZ80, NULL); // unused (hacked in) |
| 116 | Cz80_Set_WriteB(&CZ80, NULL); |
| 117 | #endif |
| 118 | } |
| 119 | |
| 120 | PICO_INTERNAL void z80_reset(void) |
| 121 | { |
| 122 | #ifdef _USE_MZ80 |
| 123 | mz80reset(); |
| 124 | #endif |
| 125 | #ifdef _USE_DRZ80 |
| 126 | memset(&drZ80, 0, 0x54); |
| 127 | drZ80.Z80F = (1<<2); // set ZFlag |
| 128 | drZ80.Z80F2 = (1<<2); // set ZFlag |
| 129 | drZ80.Z80IX = 0xFFFF << 16; |
| 130 | drZ80.Z80IY = 0xFFFF << 16; |
| 131 | drZ80.Z80IM = 0; // 1? |
| 132 | drZ80.z80irqvector = 0xff0000; // RST 38h |
| 133 | drZ80.Z80PC = drZ80.z80_rebasePC(0); |
| 134 | drZ80.Z80SP = drZ80.z80_rebaseSP(0x2000); // 0xf000 ? |
| 135 | #endif |
| 136 | #ifdef _USE_CZ80 |
| 137 | Cz80_Reset(&CZ80); |
| 138 | Cz80_Set_Reg(&CZ80, CZ80_IX, 0xffff); |
| 139 | Cz80_Set_Reg(&CZ80, CZ80_IY, 0xffff); |
| 140 | Cz80_Set_Reg(&CZ80, CZ80_SP, 0x2000); |
| 141 | #endif |
| 142 | Pico.m.z80_fakeval = 0; // for faking when Z80 is disabled |
| 143 | } |
| 144 | |
| 145 | PICO_INTERNAL void z80_pack(unsigned char *data) |
| 146 | { |
| 147 | #if defined(_USE_MZ80) |
| 148 | struct mz80context mz80; |
| 149 | *(int *)data = 0x00005A6D; // "mZ" |
| 150 | mz80GetContext(&mz80); |
| 151 | memcpy(data+4, &mz80.z80clockticks, sizeof(mz80)-5*4); // don't save base&memhandlers |
| 152 | #elif defined(_USE_DRZ80) |
| 153 | *(int *)data = 0x015A7244; // "DrZ" v1 |
| 154 | drZ80.Z80PC = drZ80.z80_rebasePC(drZ80.Z80PC-drZ80.Z80PC_BASE); |
| 155 | drZ80.Z80SP = drZ80.z80_rebaseSP(drZ80.Z80SP-drZ80.Z80SP_BASE); |
| 156 | memcpy(data+4, &drZ80, 0x54); |
| 157 | #elif defined(_USE_CZ80) |
| 158 | *(int *)data = 0x00007a43; // "Cz" |
| 159 | *(int *)(data+4) = Cz80_Get_Reg(&CZ80, CZ80_PC); |
| 160 | memcpy(data+8, &CZ80, (INT32)&CZ80.BasePC - (INT32)&CZ80); |
| 161 | #endif |
| 162 | } |
| 163 | |
| 164 | PICO_INTERNAL void z80_unpack(unsigned char *data) |
| 165 | { |
| 166 | #if defined(_USE_MZ80) |
| 167 | if (*(int *)data == 0x00005A6D) { // "mZ" save? |
| 168 | struct mz80context mz80; |
| 169 | mz80GetContext(&mz80); |
| 170 | memcpy(&mz80.z80clockticks, data+4, sizeof(mz80)-5*4); |
| 171 | mz80SetContext(&mz80); |
| 172 | } else { |
| 173 | z80_reset(); |
| 174 | z80_int(); |
| 175 | } |
| 176 | #elif defined(_USE_DRZ80) |
| 177 | if (*(int *)data == 0x015A7244) { // "DrZ" v1 save? |
| 178 | memcpy(&drZ80, data+4, 0x54); |
| 179 | // update bases |
| 180 | drZ80.Z80PC = drZ80.z80_rebasePC(drZ80.Z80PC-drZ80.Z80PC_BASE); |
| 181 | drZ80.Z80SP = drZ80.z80_rebaseSP(drZ80.Z80SP-drZ80.Z80SP_BASE); |
| 182 | } else { |
| 183 | z80_reset(); |
| 184 | drZ80.Z80IM = 1; |
| 185 | z80_int(); // try to goto int handler, maybe we won't execute trash there? |
| 186 | } |
| 187 | #elif defined(_USE_CZ80) |
| 188 | if (*(int *)data == 0x00007a43) { // "Cz" save? |
| 189 | memcpy(&CZ80, data+8, (INT32)&CZ80.BasePC - (INT32)&CZ80); |
| 190 | Cz80_Set_Reg(&CZ80, CZ80_PC, *(int *)(data+4)); |
| 191 | } else { |
| 192 | z80_reset(); |
| 193 | z80_int(); |
| 194 | } |
| 195 | #endif |
| 196 | } |
| 197 | |
| 198 | PICO_INTERNAL void z80_exit(void) |
| 199 | { |
| 200 | #if defined(_USE_MZ80) |
| 201 | mz80shutdown(); |
| 202 | #endif |
| 203 | } |
| 204 | |
| 205 | PICO_INTERNAL void z80_debug(char *dstr) |
| 206 | { |
| 207 | #if defined(_USE_DRZ80) |
| 208 | sprintf(dstr, "Z80 state: PC: %04x SP: %04x\n", drZ80.Z80PC-drZ80.Z80PC_BASE, drZ80.Z80SP-drZ80.Z80SP_BASE); |
| 209 | #elif defined(_USE_CZ80) |
| 210 | sprintf(dstr, "Z80 state: PC: %04x SP: %04x\n", CZ80.PC - CZ80.BasePC, CZ80.SP.W); |
| 211 | #endif |
| 212 | } |