|
|
1.1 root 1: /*****************************************************************************/
2: /* Generator - Sega Genesis emulation - (c) James Ponder 1997-1998 */
3: /*****************************************************************************/
4: /* */
5: /* z80.c */
6: /* */
7: /*****************************************************************************/
8:
9: #include <stdlib.h>
10: #include <stdio.h>
11: #include <string.h>
12:
13: #include "generator.h"
14: #include "cpuz80.h"
15: #include "cpu68k.h"
16: #include "memz80.h"
17: #include "ui.h"
18:
19: #define BIG_ENDIAN
20:
21: #include "z80/mz80.h"
22: #include "z80/cmz80.h"
23:
24: UINT8 cpuz80_read_actual(UINT32 addr, struct MemoryReadByte *me);
25: void cpuz80_write_actual(UINT32 addr, UINT8 data, struct MemoryWriteByte *me);
26: UINT16 cpuz80_ioread_actual(UINT16 addr, struct z80PortRead *me);
27: void cpuz80_iowrite_actual(UINT16 addr, UINT8 data, struct z80PortWrite *me);
28:
29: UINT8 cpuz80c_read_actual(UINT32 addr, struct MemoryReadByte *me);
30: void cpuz80c_write_actual(UINT32 addr, UINT8 data, struct MemoryWriteByte *me);
31: UINT16 cpuz80c_ioread_actual(UINT16 addr, struct z80PortRead *me);
32: void cpuz80c_iowrite_actual(UINT16 addr, UINT8 data, struct z80PortWrite *me);
33:
34: /*** variables externed ***/
35:
36: uint8 *cpuz80_ram = NULL;
37: uint32 cpuz80_bank = 0;
38: unsigned int cpuz80_active = 0;
39:
40: /*** global variables ***/
41:
42: static unsigned int cpuz80_lastsync = 0;
43: static unsigned int cpuz80_resetting = 0;
44: static CONTEXTMZ80 cpuz80_z80;
45: static CONTEXTCMZ80 cpuz80c_z80;
46:
47: struct {
48: uint32 addr;
49: uint8 data;
50: } reads[256];
51:
52: uint32 readpointer_head = 0;
53: uint32 readpointer_tail = 0;
54:
55: struct {
56: uint32 addr;
57: uint8 data;
58: } writes[256];
59:
60: uint32 writepointer_head = 0;
61: uint32 writepointer_tail = 0;
62:
63: static struct MemoryReadByte cpuz80_read[] = {
64: { 0x0000, 0xFFFF, cpuz80_read_actual, NULL },
65: { -1, -1, NULL, NULL }
66: };
67:
68: static struct MemoryWriteByte cpuz80_write[] = {
69: { 0x0000, 0xFFFF, cpuz80_write_actual, NULL },
70: { -1, -1, NULL, NULL }
71: };
72:
73: static struct z80PortRead cpuz80_ioread[] = {
74: { 0x0000, 0x00FF, cpuz80_ioread_actual, NULL },
75: { -1, -1, NULL, NULL }
76: };
77:
78: static struct z80PortWrite cpuz80_iowrite[] = {
79: { 0x0000, 0x00FF, cpuz80_iowrite_actual, NULL },
80: { -1, -1, NULL, NULL }
81: };
82:
83:
84:
85: static struct MemoryReadByte cpuz80c_read[] = {
86: { 0x0000, 0xFFFF, cpuz80c_read_actual, NULL },
87: { -1, -1, NULL, NULL }
88: };
89:
90: static struct MemoryWriteByte cpuz80c_write[] = {
91: { 0x0000, 0xFFFF, cpuz80c_write_actual, NULL },
92: { -1, -1, NULL, NULL }
93: };
94:
95: static struct z80PortRead cpuz80c_ioread[] = {
96: { 0x0000, 0x00FF, cpuz80c_ioread_actual, NULL },
97: { -1, -1, NULL, NULL }
98: };
99:
100: static struct z80PortWrite cpuz80c_iowrite[] = {
101: { 0x0000, 0x00FF, cpuz80c_iowrite_actual, NULL },
102: { -1, -1, NULL, NULL }
103: };
104:
105:
106: UINT8 cpuz80_read_actual(UINT32 addr, struct MemoryReadByte *me)
107: {
108: uint8 data;
109: (void)me;
110: if (((readpointer_head+1)%256) == readpointer_tail)
111: ui_err("read overrun during REAL read to %08X (p=%d)",
112: addr, readpointer_head);
113: data = memz80_fetchbyte((uint32)addr);
114: LOG_CRITICAL(("REAL read to %08X = %02X (p=%d)", addr, data,
115: readpointer_head));
116: reads[readpointer_head].addr = addr;
117: reads[readpointer_head].data = data;
118: if (++readpointer_head >= 256)
119: readpointer_head = 0;
120: return data;
121: }
122:
123: void cpuz80_write_actual(UINT32 addr, UINT8 data, struct MemoryWriteByte *me)
124: {
125: (void)me;
126: LOG_CRITICAL(("REAL write to %08X of %02X (p=%d)", addr, data,
127: writepointer_head));
128: if (((writepointer_head+1)%256) == writepointer_tail)
129: ui_err("write overrun");
130: writes[writepointer_head].addr = addr;
131: writes[writepointer_head].data = data;
132: if (++writepointer_head >= 256)
133: writepointer_head = 0;
134: memz80_storebyte((uint32)addr, (uint8)data);
135: }
136:
137: UINT16 cpuz80_ioread_actual(UINT16 addr, struct z80PortRead *me)
138: {
139: (void)me;
140: return cpuz80_portread((uint16)addr);
141: }
142:
143: void cpuz80_iowrite_actual(UINT16 addr, UINT8 data, struct z80PortWrite *me)
144: {
145: (void)me;
146: cpuz80_portwrite((uint16)addr, (uint8)data);
147: }
148:
149:
150:
151:
152: UINT8 cpuz80c_read_actual(UINT32 addr, struct MemoryReadByte *me)
153: {
154: uint8 data;
155: (void)me;
156: if (readpointer_tail == readpointer_head)
157: ui_err("read underrun");
158: if (reads[readpointer_tail].addr != addr)
159: ui_err("read address mismatch");
160: data = reads[readpointer_tail].data;
161: LOG_CRITICAL(("FAKE read to %08X = %02X", addr, data));
162: readpointer_tail = (readpointer_tail+1) % 256;
163: return data;
164: }
165:
166: void cpuz80c_write_actual(UINT32 addr, UINT8 data, struct MemoryWriteByte *me)
167: {
168: (void)me;
169: LOG_CRITICAL(("FAKE write to %08X of %02X (p=%d)", addr, data,
170: writepointer_tail));
171: if (writepointer_tail == writepointer_head) {
172: LOG_CRITICAL(("write underrun"));
173: return;
174: }
175: if (writes[writepointer_tail].addr != addr &&
176: writes[writepointer_tail].data != data)
177: ui_err("write address AND data mismatch");
178: if (writes[writepointer_tail].addr != addr)
179: ui_err("write address mismatch");
180: if (writes[writepointer_tail].data != data)
181: ui_err("write data mismatch");
182: writepointer_tail = (writepointer_tail+1) % 256;
183: }
184:
185: UINT16 cpuz80c_ioread_actual(UINT16 addr, struct z80PortRead *me)
186: {
187: (void)me;
188: ui_err("ioread");
189: return 0;
190: }
191:
192: void cpuz80c_iowrite_actual(UINT16 addr, UINT8 data, struct z80PortWrite *me)
193: {
194: (void)me;
195: ui_err("iowrite");
196: }
197:
198:
199:
200: /*** cpuz80_init - initialise this sub-unit ***/
201:
202: int cpuz80_init(void)
203: {
204: cmz80init();
205: cpuz80_reset();
206: return 0;
207: }
208:
209: /*** cpuz80_reset - reset z80 sub-unit ***/
210:
211: void cpuz80_reset(void)
212: {
213: if (!cpuz80_ram) {
214: if ((cpuz80_ram = malloc(LEN_SRAM)) == NULL) {
215: fprintf(stderr, "Out of memory\n");
216: exit(1);
217: }
218: }
219: memset(cpuz80_ram, 0, LEN_SRAM);
220: cpuz80_resetcpu();
221: cpuz80_bank = 0;
222: cpuz80_active = 0;
223: cpuz80_lastsync = 0;
224: cpuz80_resetting = 0;
225: /* mz80GetContext(&cpuz80_z80); */
226: memset(&cpuz80_z80, 0, sizeof(cpuz80_z80));
227: cpuz80_z80.z80Base = cpuz80_ram;
228: cpuz80_z80.z80MemRead = cpuz80_read;
229: cpuz80_z80.z80MemWrite = cpuz80_write;
230: cpuz80_z80.z80IoRead = cpuz80_ioread;
231: cpuz80_z80.z80IoWrite = cpuz80_iowrite;
232: mz80SetContext(&cpuz80_z80);
233: mz80reset();
234: ;
235: memset(&cpuz80c_z80, 0, sizeof(cpuz80c_z80));
236: cpuz80c_z80.z80Base = cpuz80_ram;
237: cpuz80c_z80.z80MemRead = cpuz80c_read;
238: cpuz80c_z80.z80MemWrite = cpuz80c_write;
239: cpuz80c_z80.z80IoRead = cpuz80c_ioread;
240: cpuz80c_z80.z80IoWrite = cpuz80c_iowrite;
241: cmz80SetContext(&cpuz80c_z80);
242: cmz80reset();
243: }
244:
245: /*** cpuz80_resetcpu - reset z80 cpu ***/
246:
247: void cpuz80_resetcpu(void)
248: {
249: mz80reset();
250: cmz80reset();
251: cpuz80_resetting = 1; /* suspends execution */
252: }
253:
254: /*** cpuz80_unresetcpu - unreset z80 cpu ***/
255:
256: void cpuz80_unresetcpu(void)
257: {
258: cpuz80_resetting = 0; /* un-suspends execution */
259: }
260:
261: /*** cpuz80_bankwrite - data is being written to latch ***/
262:
263: void cpuz80_bankwrite(uint8 data)
264: {
265: cpuz80_bank = (((cpuz80_bank >> 1) | ((data & 1) <<23)) & 0xff8000);
266: /*
267: if (gen_debug)
268: printf("BANK WRITE: %d --> %08X\n", data, cpuz80_bank);
269: */
270: }
271:
272: /*** cpuz80_stop - stop the processor ***/
273:
274: void cpuz80_stop(void)
275: {
276: cpuz80_sync();
277: cpuz80_active = 0;
278: }
279:
280: /*** cpuz80_start - start the processor ***/
281:
282: void cpuz80_start(void)
283: {
284: cpuz80_sync();
285: cpuz80_active = 1;
286: }
287:
288: /*** cpuz80_endfield - reset counters ***/
289:
290: void cpuz80_endfield(void)
291: {
292: cpuz80_lastsync = 0;
293: }
294:
295: /*** cpuz80_sync - synchronise ***/
296:
297: void cpuz80_sync(void)
298: {
299: int cpu68k_wanted = cpu68k_clocks - cpuz80_lastsync;
300: int wanted = (cpu68k_wanted<0?0:cpu68k_wanted)*7/16;
301: int achieved, achieved_c;
302: uint32 oldpc;
303:
304: if (cpuz80_active && !cpuz80_resetting) {
305: /* ui_log(LOG_USER, "executing %d z80 clocks @ %X", wanted,
306: cpuz80_z80.z80pc); */
307: printf("context: s=%08X c=%08X\n", &cpuz80_z80, &cpuz80c_z80);
308: printf("pc invalid: %08X %08X\n", &cpuz80_z80.z80pc, &cpuz80c_z80.z80pc);
309: mz80GetContext(&cpuz80_z80);
310: cmz80GetContext(&cpuz80c_z80);
311: printf("pc start: %08X %08X\n", cpuz80_z80.z80pc, cpuz80c_z80.z80pc);
312: printf("opcodes: %02x(%02x) %02x(%02x)\n", cpuz80_ram[cpuz80_z80.z80pc],
313: cpuz80_ram[cpuz80_z80.z80pc+1],
314: cpuz80_ram[cpuz80c_z80.z80pc],
315: cpuz80_ram[cpuz80c_z80.z80pc+1]);
316: if (cpuz80_z80.z80pc != cpuz80c_z80.z80pc) {
317: ui_err("sPC = %08X / cPC = %08X mismatch on entry",
318: cpuz80_z80.z80pc, cpuz80c_z80.z80pc);
319: }
320: printf("Pending ints: s = %X c = %X\n",
321: cpuz80_z80.z80intPending, cpuz80c_z80.z80intPending);
322: printf("DE on entry: s=%X c=%X\n", cpuz80_z80.z80de.de,
323: cpuz80c_z80.z80de.de);
324: oldpc = cpuz80_z80.z80pc;
325: printf("Attempting to execute %d clocks...\n", wanted);
326: mz80exec(wanted); /* wanted */
327: cmz80exec(wanted);
328: achieved = mz80GetElapsedTicks(1);
329: achieved_c = cmz80GetElapsedTicks(1);
330: mz80GetContext(&cpuz80_z80);
331: cmz80GetContext(&cpuz80c_z80);
332: LOG_CRITICAL(("achieved s=%d c=%d", achieved, achieved_c));
333: printf("pc end: %08X %08X\n", cpuz80_z80.z80pc, cpuz80c_z80.z80pc);
334: printf("Exit pending ints: s = %X c = %X\n",
335: cpuz80_z80.z80intPending, cpuz80c_z80.z80intPending);
336: if (cpuz80_z80.z80af.af != cpuz80c_z80.z80af.af)
337: ui_err("AF differs: s=%X c=%X", cpuz80_z80.z80af.af,
338: cpuz80c_z80.z80af.af);
339: if (cpuz80_z80.z80bc.bc != cpuz80c_z80.z80bc.bc)
340: ui_err("BC differs: s=%X c=%X", cpuz80_z80.z80bc.bc,
341: cpuz80c_z80.z80bc.bc);
342: if (cpuz80_z80.z80de.de != cpuz80c_z80.z80de.de)
343: ui_err("DE differs: s=%X c=%X", cpuz80_z80.z80de.de,
344: cpuz80c_z80.z80de.de);
345: if (cpuz80_z80.z80hl.hl != cpuz80c_z80.z80hl.hl)
346: ui_err("HL differs: s=%X c=%X", cpuz80_z80.z80hl.hl,
347: cpuz80c_z80.z80hl.hl);
348: if (cpuz80_z80.z80ix.ix != cpuz80c_z80.z80ix.ix)
349: ui_err("IX differs: s=%X c=%X", cpuz80_z80.z80ix.ix,
350: cpuz80c_z80.z80ix.ix);
351: if (cpuz80_z80.z80iy.iy != cpuz80c_z80.z80iy.iy)
352: ui_err("IY differs: s=%X c=%X", cpuz80_z80.z80iy.iy,
353: cpuz80c_z80.z80iy.iy);
354: if (cpuz80_z80.z80pc != cpuz80c_z80.z80pc) {
355: ui_err("sPC = %08X / cPC = %08X mismatch on exit",
356: cpuz80_z80.z80pc, cpuz80c_z80.z80pc);
357: }
358: if (cpuz80_z80.z80intPending != cpuz80c_z80.z80intPending) {
359: /*
360: ui_err("sIntPending = %X / cIntPending = %X\n",
361: cpuz80_z80.z80intPending, cpuz80c_z80.z80intPending);
362: */
363: }
364: if (achieved != achieved_c) {
365: LOG_CRITICAL(("oldpc=%08X newpc=%08X", oldpc, cpuz80_z80.z80pc));
366: ui_err("achieved clocks mismatch: s=%d c=%d", achieved, achieved_c);
367: }
368: /* this if/else statement below, I'm not entirely sure this is a good
369: idea, perhaps just doing cpuz80_lastsync = cpu68k_clocks; always is
370: better? hmm. */
371: if (achieved > wanted) {
372: cpuz80_lastsync = cpu68k_clocks;
373: } else {
374: cpuz80_lastsync = cpuz80_lastsync + achieved*16/7;
375: }
376: } else {
377: cpuz80_lastsync = cpu68k_clocks;
378: }
379: }
380:
381: /*** cpuz80_interrupt - cause an interrupt on the z80 */
382:
383: void cpuz80_interrupt(void)
384: {
385: if (!cpuz80_resetting) {
386: LOG_CRITICAL(("interrupt!!!!!!!!!!!!!"));
387: mz80int(0);
388: cmz80int(0);
389: }
390: }
391:
392: /*** cpuz80_portread - port read from z80 */
393:
394: uint8 cpuz80_portread(uint8 port)
395: {
396: LOG_VERBOSE(("[Z80] Port read to %X", port));
397: return 0;
398: }
399:
400: /*** cpuz80_portwrite - z80 write to port */
401:
402: void cpuz80_portwrite(uint8 port, uint8 value)
403: {
404: LOG_VERBOSE(("[Z80] Port write to %X of %X", port, value));
405: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.