1 #include "burnint.h"
2 #include "m6809_intf.h"
3 #include <stddef.h>
4
5 #define MAX_CPU 8
6
7 INT32 nM6809Count = 0;
8 static INT32 nActiveCPU = 0;
9
10 static M6809Ext *m6809CPUContext = NULL;
11
12 cpu_core_config M6809Config =
13 {
14 "M6809",
15 M6809Open,
16 M6809Close,
17 M6809CheatRead,
18 M6809WriteRom,
19 M6809GetActive,
20 M6809TotalCycles,
21 M6809NewFrame,
22 M6809Idle,
23 M6809SetIRQLine,
24 M6809Run,
25 M6809RunEnd,
26 M6809Reset,
27 0x10000,
28 0
29 };
30
M6809ReadByteDummyHandler(UINT16)31 static UINT8 M6809ReadByteDummyHandler(UINT16)
32 {
33 return 0;
34 }
35
M6809WriteByteDummyHandler(UINT16,UINT8)36 static void M6809WriteByteDummyHandler(UINT16, UINT8)
37 {
38 }
39
M6809ReadOpDummyHandler(UINT16)40 static UINT8 M6809ReadOpDummyHandler(UINT16)
41 {
42 return 0;
43 }
44
M6809ReadOpArgDummyHandler(UINT16)45 static UINT8 M6809ReadOpArgDummyHandler(UINT16)
46 {
47 return 0;
48 }
49
50 // ## M6809CPUPush() / M6809CPUPop() ## internal helpers for sending signals to other m6809's
51 struct m6809pstack {
52 INT32 nHostCPU;
53 INT32 nPushedCPU;
54 };
55 #define MAX_PSTACK 10
56
57 static m6809pstack pstack[MAX_PSTACK];
58 static INT32 pstacknum = 0;
59
M6809CPUPush(INT32 nCPU)60 void M6809CPUPush(INT32 nCPU)
61 {
62 m6809pstack *p = &pstack[pstacknum++];
63
64 if (pstacknum + 1 >= MAX_PSTACK) {
65 bprintf(0, _T("M6809CPUPush(): out of stack! Possible infinite recursion? Crash pending..\n"));
66 }
67
68 p->nPushedCPU = nCPU;
69
70 p->nHostCPU = M6809GetActive();
71
72 if (p->nHostCPU != p->nPushedCPU) {
73 if (p->nHostCPU != -1) M6809Close();
74 M6809Open(p->nPushedCPU);
75 }
76 }
77
M6809CPUPop()78 void M6809CPUPop()
79 {
80 m6809pstack *p = &pstack[--pstacknum];
81
82 if (p->nHostCPU != p->nPushedCPU) {
83 M6809Close();
84 if (p->nHostCPU != -1) M6809Open(p->nHostCPU);
85 }
86 }
87
M6809Reset()88 void M6809Reset()
89 {
90 #if defined FBNEO_DEBUG
91 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809Reset called without init\n"));
92 if (nActiveCPU == -1) bprintf(PRINT_ERROR, _T("M6809Reset called when no CPU open\n"));
93 #endif
94
95 m6809_reset();
96 }
97
M6809Reset(INT32 nCPU)98 void M6809Reset(INT32 nCPU)
99 {
100 #if defined FBNEO_DEBUG
101 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809Reset called without init\n"));
102 #endif
103
104 M6809CPUPush(nCPU);
105
106 M6809Reset();
107
108 M6809CPUPop();
109 }
110
M6809GetPC()111 UINT16 M6809GetPC()
112 {
113 #if defined FBNEO_DEBUG
114 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809GetPC called without init\n"));
115 if (nActiveCPU == -1) bprintf(PRINT_ERROR, _T("M6809GetPC called when no CPU open\n"));
116 #endif
117
118 return m6809_get_pc();
119 }
120
M6809GetPrevPC()121 UINT16 M6809GetPrevPC()
122 {
123 #if defined FBNEO_DEBUG
124 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809GetPrevPC called without init\n"));
125 if (nActiveCPU == -1) bprintf(PRINT_ERROR, _T("M6809GetPrevPC called when no CPU open\n"));
126 #endif
127
128 return m6809_get_prev_pc();
129 }
130
M6809NewFrame()131 void M6809NewFrame()
132 {
133 #if defined FBNEO_DEBUG
134 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809NewFrame called without init\n"));
135 #endif
136
137 for (INT32 i = 0; i < nM6809Count+1; i++) {
138 m6809CPUContext[i].nCyclesTotal = 0;
139 }
140 }
141
M6809TotalCycles()142 INT32 M6809TotalCycles()
143 {
144 #if defined FBNEO_DEBUG
145 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809TotalCycles called without init\n"));
146 if (nActiveCPU == -1) bprintf(PRINT_ERROR, _T("M6809TotalCycles called when no CPU open\n"));
147 #endif
148
149 if (nActiveCPU == -1) return 0; // prevent crash
150
151 return m6809CPUContext[nActiveCPU].nCyclesTotal + m6809_get_segmentcycles();
152 }
153
M6809TotalCycles(INT32 nCPU)154 INT32 M6809TotalCycles(INT32 nCPU)
155 {
156 #if defined FBNEO_DEBUG
157 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809TotalCycles called without init\n"));
158 #endif
159
160 M6809CPUPush(nCPU);
161
162 INT32 nRet = M6809TotalCycles();
163
164 M6809CPUPop();
165
166 return nRet;
167 }
168
M6809Idle(INT32 cycles)169 INT32 M6809Idle(INT32 cycles)
170 {
171 #if defined FBNEO_DEBUG
172 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809Idle called without init\n"));
173 if (nActiveCPU == -1) bprintf(PRINT_ERROR, _T("M6809Idle called when no CPU open\n"));
174 #endif
175
176 m6809CPUContext[nActiveCPU].nCyclesTotal += cycles;
177
178 return cycles;
179 }
180
M6809Idle(INT32 nCPU,INT32 nCycles)181 INT32 M6809Idle(INT32 nCPU, INT32 nCycles)
182 {
183 #if defined FBNEO_DEBUG
184 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809Idle called without init\n"));
185 #endif
186
187 M6809CPUPush(nCPU);
188
189 INT32 nRet = M6809Idle(nCycles);
190
191 M6809CPUPop();
192
193 return nRet;
194 }
195
M6809CheatRead(UINT32 a)196 UINT8 M6809CheatRead(UINT32 a)
197 {
198 return M6809ReadByte(a);
199 }
200
M6809Init(INT32 cpu)201 INT32 M6809Init(INT32 cpu)
202 {
203 DebugCPU_M6809Initted = 1;
204
205 nActiveCPU = -1;
206 nM6809Count = cpu;
207
208 #if defined FBNEO_DEBUG
209 if (cpu >= MAX_CPU-1) bprintf (0, _T("M6809Init called with greater than maximum (%d) cpu number (%d)\n"), MAX_CPU-1, cpu);
210 #endif
211
212 if (m6809CPUContext == NULL) {
213 m6809CPUContext = (M6809Ext*)malloc(MAX_CPU * sizeof(M6809Ext));
214
215 if (m6809CPUContext == NULL) {
216 #if defined FBNEO_DEBUG
217 if (cpu >= MAX_CPU-1) bprintf (0, _T("M6809Init failed to initialize context!\n"));
218 #endif
219 return 1;
220 }
221
222 memset(m6809CPUContext, 0, MAX_CPU * sizeof(M6809Ext));
223
224 for (INT32 i = 0; i < MAX_CPU; i++) {
225 m6809CPUContext[i].ReadByte = M6809ReadByteDummyHandler;
226 m6809CPUContext[i].WriteByte = M6809WriteByteDummyHandler;
227 m6809CPUContext[i].ReadOp = M6809ReadOpDummyHandler;
228 m6809CPUContext[i].ReadOpArg = M6809ReadOpArgDummyHandler;
229 m6809CPUContext[i].nCyclesTotal = 0;
230
231 for (INT32 j = 0; j < (0x0100 * 3); j++) {
232 m6809CPUContext[i].pMemMap[j] = NULL;
233 }
234 }
235
236 m6809_init(NULL);
237 }
238
239 m6809CPUContext[cpu].ReadByte = M6809ReadByteDummyHandler;
240 m6809CPUContext[cpu].WriteByte = M6809WriteByteDummyHandler;
241 m6809CPUContext[cpu].ReadOp = M6809ReadOpDummyHandler;
242 m6809CPUContext[cpu].ReadOpArg = M6809ReadOpArgDummyHandler;
243
244 CpuCheatRegister(cpu, &M6809Config);
245
246 return 0;
247 }
248
M6809Exit()249 void M6809Exit()
250 {
251 #if defined FBNEO_DEBUG
252 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809Exit called without init\n"));
253 #endif
254
255 nM6809Count = 0;
256
257 if (m6809CPUContext) {
258 free(m6809CPUContext);
259 m6809CPUContext = NULL;
260 }
261
262 DebugCPU_M6809Initted = 0;
263 }
264
M6809Open(INT32 num)265 void M6809Open(INT32 num)
266 {
267 #if defined FBNEO_DEBUG
268 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809Open called without init\n"));
269 if (num > nM6809Count) bprintf(PRINT_ERROR, _T("M6809Open called with invalid index %x\n"), num);
270 if (nActiveCPU != -1) bprintf(PRINT_ERROR, _T("M6809Open called when CPU already open with index %x\n"), num);
271 #endif
272
273 nActiveCPU = num;
274
275 m6809_set_context(&m6809CPUContext[nActiveCPU].reg);
276 }
277
M6809Close()278 void M6809Close()
279 {
280 #if defined FBNEO_DEBUG
281 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809Close called without init\n"));
282 if (nActiveCPU == -1) bprintf(PRINT_ERROR, _T("M6809Close called when no CPU open\n"));
283 #endif
284
285 m6809_get_context(&m6809CPUContext[nActiveCPU].reg);
286
287 nActiveCPU = -1;
288 }
289
M6809GetActive()290 INT32 M6809GetActive()
291 {
292 #if defined FBNEO_DEBUG
293 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809GetActive called without init\n"));
294 //if (nActiveCPU == -1) bprintf(PRINT_ERROR, _T("M6809GetActive called when no CPU open\n"));
295 #endif
296
297 return nActiveCPU;
298 }
299
M6809SetIRQLine(INT32 vector,INT32 status)300 void M6809SetIRQLine(INT32 vector, INT32 status)
301 {
302 #if defined FBNEO_DEBUG
303 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809SetIRQLine called without init\n"));
304 if (nActiveCPU == -1) bprintf(PRINT_ERROR, _T("M6809SetIRQLine called when no CPU open\n"));
305 #endif
306
307 if (status == CPU_IRQSTATUS_NONE) {
308 m6809_set_irq_line(vector, 0);
309 }
310
311 if (status == CPU_IRQSTATUS_ACK) {
312 m6809_set_irq_line(vector, 1);
313 }
314
315 if (status == CPU_IRQSTATUS_HOLD) {
316 m6809_set_irq_line(vector, 2);
317 }
318
319 if (status == CPU_IRQSTATUS_AUTO) {
320 m6809_set_irq_line(vector, 1);
321 m6809_execute(0);
322 m6809_set_irq_line(vector, 0);
323 m6809_execute(0);
324 }
325 }
326
M6809SetIRQLine(INT32 nCPU,const INT32 line,const INT32 status)327 void M6809SetIRQLine(INT32 nCPU, const INT32 line, const INT32 status)
328 {
329 #if defined FBNEO_DEBUG
330 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809SetIRQLine called without init\n"));
331 #endif
332
333 M6809CPUPush(nCPU);
334
335 M6809SetIRQLine(line, status);
336
337 M6809CPUPop();
338 }
339
M6809Run(INT32 cycles)340 INT32 M6809Run(INT32 cycles)
341 {
342 #if defined FBNEO_DEBUG
343 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809Run called without init\n"));
344 if (nActiveCPU == -1) bprintf(PRINT_ERROR, _T("M6809Run called when no CPU open\n"));
345 #endif
346
347 cycles = m6809_execute(cycles);
348
349 m6809CPUContext[nActiveCPU].nCyclesTotal += cycles;
350
351 return cycles;
352 }
353
M6809Run(INT32 nCPU,INT32 nCycles)354 INT32 M6809Run(INT32 nCPU, INT32 nCycles)
355 {
356 #if defined FBNEO_DEBUG
357 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809Run called without init\n"));
358 #endif
359
360 M6809CPUPush(nCPU);
361
362 INT32 nRet = M6809Run(nCycles);
363
364 M6809CPUPop();
365
366 return nRet;
367 }
368
M6809RunEnd()369 void M6809RunEnd()
370 {
371 #if defined FBNEO_DEBUG
372 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809RunEnd called without init\n"));
373 if (nActiveCPU == -1) bprintf(PRINT_ERROR, _T("M6809RunEnd called when no CPU open\n"));
374 #endif
375
376 m6809_end_timeslice();
377 }
378
M6809MapMemory(UINT8 * pMemory,UINT16 nStart,UINT16 nEnd,INT32 nType)379 INT32 M6809MapMemory(UINT8* pMemory, UINT16 nStart, UINT16 nEnd, INT32 nType)
380 {
381 #if defined FBNEO_DEBUG
382 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809MapMemory called without init\n"));
383 if (nActiveCPU == -1) bprintf(PRINT_ERROR, _T("M6809MapMemory called when no CPU open\n"));
384 #endif
385
386 UINT8 cStart = (nStart >> 8);
387 UINT8 **pMemMap = m6809CPUContext[nActiveCPU].pMemMap;
388
389 for (UINT16 i = cStart; i <= (nEnd >> 8); i++) {
390 if (nType & MAP_READ) {
391 pMemMap[0 + i] = pMemory + ((i - cStart) << 8);
392 }
393 if (nType & MAP_WRITE) {
394 pMemMap[0x100 + i] = pMemory + ((i - cStart) << 8);
395 }
396 if (nType & MAP_FETCH) {
397 pMemMap[0x200 + i] = pMemory + ((i - cStart) << 8);
398 }
399 }
400 return 0;
401
402 }
403
M6809UnmapMemory(UINT16 nStart,UINT16 nEnd,INT32 nType)404 INT32 M6809UnmapMemory(UINT16 nStart, UINT16 nEnd, INT32 nType)
405 {
406 #if defined FBNEO_DEBUG
407 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809UnmapMemory called without init\n"));
408 if (nActiveCPU == -1) bprintf(PRINT_ERROR, _T("M6809UnmapMemory called when no CPU open\n"));
409 #endif
410
411 UINT8 cStart = (nStart >> 8);
412 UINT8 **pMemMap = m6809CPUContext[nActiveCPU].pMemMap;
413
414 for (UINT16 i = cStart; i <= (nEnd >> 8); i++) {
415 if (nType & MAP_READ) {
416 pMemMap[0 + i] = NULL;
417 }
418 if (nType & MAP_WRITE) {
419 pMemMap[0x100 + i] = NULL;
420 }
421 if (nType & MAP_FETCH) {
422 pMemMap[0x200 + i] = NULL;
423 }
424 }
425 return 0;
426
427 }
428
M6809SetReadHandler(UINT8 (* pHandler)(UINT16))429 void M6809SetReadHandler(UINT8 (*pHandler)(UINT16))
430 {
431 #if defined FBNEO_DEBUG
432 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809SetReadHandler called without init\n"));
433 if (nActiveCPU == -1) bprintf(PRINT_ERROR, _T("M6809SetReadHandler called when no CPU open\n"));
434 #endif
435
436 m6809CPUContext[nActiveCPU].ReadByte = pHandler;
437 }
438
M6809SetWriteHandler(void (* pHandler)(UINT16,UINT8))439 void M6809SetWriteHandler(void (*pHandler)(UINT16, UINT8))
440 {
441 #if defined FBNEO_DEBUG
442 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809SetWriteHandler called without init\n"));
443 if (nActiveCPU == -1) bprintf(PRINT_ERROR, _T("M6809SetWriteHandler called when no CPU open\n"));
444 #endif
445
446 m6809CPUContext[nActiveCPU].WriteByte = pHandler;
447 }
448
M6809SetReadOpHandler(UINT8 (* pHandler)(UINT16))449 void M6809SetReadOpHandler(UINT8 (*pHandler)(UINT16))
450 {
451 #if defined FBNEO_DEBUG
452 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809SetReadOpHandler called without init\n"));
453 if (nActiveCPU == -1) bprintf(PRINT_ERROR, _T("M6809SetReadOpHandler called when no CPU open\n"));
454 #endif
455
456 m6809CPUContext[nActiveCPU].ReadOp = pHandler;
457 }
458
M6809SetReadOpArgHandler(UINT8 (* pHandler)(UINT16))459 void M6809SetReadOpArgHandler(UINT8 (*pHandler)(UINT16))
460 {
461 #if defined FBNEO_DEBUG
462 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809SetReadOpArgHandler called without init\n"));
463 if (nActiveCPU == -1) bprintf(PRINT_ERROR, _T("M6809SetReadOpArgHandler called when no CPU open\n"));
464 #endif
465
466 m6809CPUContext[nActiveCPU].ReadOpArg = pHandler;
467 }
468
M6809ReadByte(UINT16 Address)469 UINT8 M6809ReadByte(UINT16 Address)
470 {
471 // check mem map
472 UINT8 * pr = m6809CPUContext[nActiveCPU].pMemMap[0x000 | (Address >> 8)];
473 if (pr != NULL) {
474 return pr[Address & 0xff];
475 }
476
477 // check handler
478 if (m6809CPUContext[nActiveCPU].ReadByte != NULL) {
479 return m6809CPUContext[nActiveCPU].ReadByte(Address);
480 }
481
482 return 0;
483 }
484
M6809WriteByte(UINT16 Address,UINT8 Data)485 void M6809WriteByte(UINT16 Address, UINT8 Data)
486 {
487 // check mem map
488 UINT8 * pr = m6809CPUContext[nActiveCPU].pMemMap[0x100 | (Address >> 8)];
489 if (pr != NULL) {
490 pr[Address & 0xff] = Data;
491 return;
492 }
493
494 // check handler
495 if (m6809CPUContext[nActiveCPU].WriteByte != NULL) {
496 m6809CPUContext[nActiveCPU].WriteByte(Address, Data);
497 return;
498 }
499 }
500
M6809ReadOp(UINT16 Address)501 UINT8 M6809ReadOp(UINT16 Address)
502 {
503 // check mem map
504 UINT8 * pr = m6809CPUContext[nActiveCPU].pMemMap[0x200 | (Address >> 8)];
505 if (pr != NULL) {
506 return pr[Address & 0xff];
507 }
508
509 // check handler
510 if (m6809CPUContext[nActiveCPU].ReadOp != NULL) {
511 return m6809CPUContext[nActiveCPU].ReadOp(Address);
512 }
513
514 return 0;
515 }
516
M6809ReadOpArg(UINT16 Address)517 UINT8 M6809ReadOpArg(UINT16 Address)
518 {
519 // check mem map
520 UINT8 * pr = m6809CPUContext[nActiveCPU].pMemMap[0x000 | (Address >> 8)];
521 if (pr != NULL) {
522 return pr[Address & 0xff];
523 }
524
525 // check handler
526 if (m6809CPUContext[nActiveCPU].ReadOpArg != NULL) {
527 return m6809CPUContext[nActiveCPU].ReadOpArg(Address);
528 }
529
530 return 0;
531 }
532
M6809WriteRom(UINT32 Address,UINT8 Data)533 void M6809WriteRom(UINT32 Address, UINT8 Data)
534 {
535 #if defined FBNEO_DEBUG
536 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809WriteRom called without init\n"));
537 if (nActiveCPU == -1) bprintf(PRINT_ERROR, _T("M6809WriteRom called when no CPU open\n"));
538 #endif
539 Address &= 0xffff;
540
541 UINT8 * pr = m6809CPUContext[nActiveCPU].pMemMap[0x000 | (Address >> 8)];
542 UINT8 * pw = m6809CPUContext[nActiveCPU].pMemMap[0x100 | (Address >> 8)];
543 UINT8 * pf = m6809CPUContext[nActiveCPU].pMemMap[0x200 | (Address >> 8)];
544
545 if (pr != NULL) {
546 pr[Address & 0xff] = Data;
547 }
548
549 if (pw != NULL) {
550 pw[Address & 0xff] = Data;
551 }
552
553 if (pf != NULL) {
554 pf[Address & 0xff] = Data;
555 }
556
557 // check handler
558 if (m6809CPUContext[nActiveCPU].WriteByte != NULL) {
559 m6809CPUContext[nActiveCPU].WriteByte(Address, Data);
560 return;
561 }
562 }
563
M6809Scan(INT32 nAction)564 INT32 M6809Scan(INT32 nAction)
565 {
566 #if defined FBNEO_DEBUG
567 if (!DebugCPU_M6809Initted) bprintf(PRINT_ERROR, _T("M6809Scan called without init\n"));
568 #endif
569
570 struct BurnArea ba;
571
572 if ((nAction & ACB_DRIVER_DATA) == 0) {
573 return 1;
574 }
575
576 for (INT32 i = 0; i < nM6809Count+1; i++) {
577
578 M6809Ext *ptr = &m6809CPUContext[i];
579
580 char szName[] = "M6809 #n";
581 szName[7] = '0' + i;
582
583 memset(&ba, 0, sizeof(ba));
584 ba.Data = &m6809CPUContext[i].reg;
585 ba.nLen = STRUCT_SIZE_HELPER(m6809_Regs, nmi_state);
586 ba.szName = szName;
587 BurnAcb(&ba);
588
589 SCAN_VAR(ptr->nCyclesTotal);
590 }
591
592 return 0;
593 }
594