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