1 // DGen/SDL v1.29+
2 // Megadrive C++ module - misc memory
3 
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <stdint.h>
7 #include <assert.h>
8 #include "md.h"
9 #include "mem.h"
10 
11 /**
12  * Read one byte from the memory space.
13  * @param a Address to read
14  * @return byte or 0 if invalid.
15  */
z80_read(uint16_t a)16 uint8_t md::z80_read(uint16_t a)
17 {
18 	/* 0x0000-0x3fff: Z80 RAM */
19 	if (a <= Z80_RAM_END)
20 		return z80ram[(a & 0x1fff)];
21 	/* 0x4000-0x5fff: YM2612 */
22 	if (a <= YM2612_RAM_END)
23 		return myfm_read(a);
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));
32 }
33 
34 /**
35  * Write one byte to the memory
36  * @param a Address to read
37  * @param d Data (byte) to write.
38  */
z80_write(uint16_t a,uint8_t d)39 void md::z80_write(uint16_t a, uint8_t d)
40 {
41 	/* 0x0000-0x3fff: Z80 RAM */
42 	if (a <= Z80_RAM_END) {
43 		z80ram[(a & 0x1fff)] = d;
44 		return;
45 	}
46 	/* 0x4000-0x5fff: YM2612 */
47 	if (a <= YM2612_RAM_END) {
48 		myfm_write(a, d, 1);
49 		return;
50 	}
51 	/* 0x6000-0x6fff: bank register */
52 	if (a <= BANK_RAM_END) {
53 		uint32_t tmp;
54 
55 		if (a > 0x60ff)
56 			return; /* invalid address */
57 		tmp = (z80_bank68k >> 1);
58 		tmp |= ((d & 1) << 23);
59 		z80_bank68k = (tmp & 0xff8000);
60 		return;
61 	}
62 	/* 0x7000-0x7fff: PSG */
63 	if (a <= PSGVDP_RAM_END) {
64 		if (a == 0x7f11) {
65 			mysn_write(d);
66 			return;
67 		}
68 		return; /* invalid address */
69 	}
70 	/* 0x8000-0xffff: M68K bank */
71 	misc_writebyte((z80_bank68k + (a & 0x7fff)), d);
72 }
73 
74 /**
75  * Port read to Z80.
76  * This is a NOP
77  * @param a address (ignored)
78  * @return always returns 0xff
79  */
z80_port_read(uint16_t a)80 uint8_t md::z80_port_read(uint16_t a)
81 {
82 	(void)a;
83 	return 0xff;
84 }
85 
86 /**
87  * Port write to z80
88  * This is a Nop
89  * @param a address (ignored)
90  * @param d data (ignored)
91  */
z80_port_write(uint16_t a,uint8_t d)92 void md::z80_port_write(uint16_t a, uint8_t d)
93 {
94 	(void)a;
95 	(void)d;
96 }
97 
m68k_ROM_read(uint32_t a)98 uint8_t md::m68k_ROM_read(uint32_t a)
99 {
100 	/* save RAM */
101 	if ((save_active) && (save_len) &&
102 	    (a >= save_start) && ((a - save_start) < save_len))
103 		return saveram[((a ^ 1) - save_start)];
104 	/* ROM */
105 	if (ROM_ADDR(a) < romlen)
106 		return rom[ROM_ADDR(a)];
107 	/* empty area */
108 	return 0;
109 }
110 
m68k_IO_read(uint32_t a)111 uint8_t md::m68k_IO_read(uint32_t a)
112 {
113 	/* Z80 */
114 	if (a < 0xa10000) {
115 		if ((!z80_st_busreq) && (a < 0xa04000))
116 			return 0;
117 		return z80_read(a & 0xffff);
118 	}
119 	/* version */
120 	if (a == 0xa10000)
121 		return 0;
122 	if (a == 0xa10001) {
123 		uint8_t c = region;
124 
125 		/* If region hasn't been defined, guess it. */
126 		if (c == '\0')
127 			c = region_guess();
128 		region_info(c, 0, 0, 0, 0, &c);
129 		/* Remove PAL flag if we're not in PAL mode. */
130 		if (!pal)
131 			c &= ~0x40;
132 		return c;
133 	}
134 	/* data 1 (pad 0) */
135 	if (a == 0xa10002)
136 		return 0;
137 	if (a == 0xa10003) {
138 		if (aoo3_six == 3) {
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));
144 		}
145 		if (aoo3_toggle == 0) {
146 			if (aoo3_six == 4)
147 				return (((pad[0] >> 8) & 0x30) +
148 					0x00 + 0x0f);
149 			return (((pad[0] >> 8) & 0x30) +
150 				0x00 + (pad[0] & 0x03));
151 		}
152 		return ((pad[0] & 0x30) + 0x40 + (pad[0] & 0x0f));
153 	}
154 	/* data 2 (pad 1) */
155 	if (a == 0xa10004)
156 		return 0;
157 	if (a == 0xa10005) {
158 		if (aoo5_six == 3) {
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));
164 		}
165 		if (aoo5_toggle == 0) {
166 			if (aoo5_six == 4)
167 				return (((pad[1] >> 8) & 0x30) +
168 					0x00 + 0x0f);
169 			return (((pad[1] >> 8) & 0x30) +
170 				0x00 + (pad[1] & 0x03));
171 		}
172 		return ((pad[1] & 0x30) + 0x40 + (pad[1] & 0x0f));
173 	}
174 	/* data 3 (exp) */
175 	if (a == 0xa10006)
176 		return 0;
177 	if (a == 0xa10007)
178 		return 0xff;
179 	/* ctrl 1 */
180 	if (a == 0xa10008)
181 		return 0;
182 	if (a == 0xa10009)
183 		return pad_com[0];
184 	/* ctrl 2 */
185 	if (a == 0xa1000a)
186 		return 0;
187 	if (a == 0xa1000b)
188 		return pad_com[1];
189 	/* ctrl 3 */
190 	if ((a & 0xa1000c) == 0xa1000c)
191 		return 0;
192 	/* memory mode */
193 	if ((a & 0xfffffe) == 0xa11000)
194 		return 0xff;
195 	/* Z80 BUSREQ */
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);
200 	/* Z80 RESET */
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 */
206 }
207 
m68k_VDP_read(uint32_t a)208 uint8_t md::m68k_VDP_read(uint32_t a)
209 {
210 	a &= 0xe700ff;
211 	/* data */
212 	if (a < 0xc00004) {
213 		if (a & 0x01)
214 			return 0;
215 		vdp.cmd_pending = false;
216 		return vdp.readbyte();
217 	}
218 	/* control */
219 	if (a < 0xc00008) {
220 		vdp.cmd_pending = false;
221 		if ((a & 0x01) == 0)
222 			return coo4;
223 		return coo5;
224 	}
225 	/* HV counters */
226 	if (a == 0xc00008)
227 		return calculate_coo8();
228 	if (a == 0xc00009)
229 		return calculate_coo9();
230 	/* PSG */
231 	if (a == 0xc00011)
232 		return (0);
233 	return 0; /* invalid address */
234 }
235 
236 /**
237  * Read a byte from the m68Ks ram.
238  * @param a Address to read.
239  */
misc_readbyte(uint32_t a)240 uint8_t md::misc_readbyte(uint32_t a)
241 {
242 	/* clip to 24-bit */
243 	a &= 0x00ffffff;
244 	/* 0x000000-0x7fffff: ROM */
245 	if (a <= M68K_ROM_END) {
246 		return m68k_ROM_read(a);
247 	}
248 #ifdef WITH_PICO
249 	/* 0x800000-0x80001f: Sega Pico I/O area */
250 	if ((pico_enabled) &&
251 	    ((a >= 0x800000) && (a <= 0x80001f))) {
252 		a &= 0x1f;
253 		switch(a) {
254 		case 1: // Version register
255 			switch (region) {
256 			case 'J': // Japan
257 				return 0;
258 			case 'E': // Europe
259 				return 32;
260 			case 'U': // USA
261 				return 64;
262 			}
263 			return 0;
264 		case 3: // Pico pad
265 			return pad[0];
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;
274 		}
275 	}
276 	/* 0x800020-0xafffff: Sega Pico empty area */
277 	if ((pico_enabled) &&
278 	    (a <= M68K_IO_END))
279 		return 0;
280 #endif
281 	/* 0x800000-0x9fffff: empty area */
282 	if (a <= M68K_EMPTY1_END) {
283 		/*
284 		 * http://cgfm2.emuviews.com/txt/gen-hw.txt
285 		 * see section 1 point 3 for what these addresses do.
286 		 */
287 		return 0;
288 	}
289 	/* 0xa00000-0xafffff: system I/O and control */
290 	if (a <= M68K_IO_END) {
291 		return m68k_IO_read(a);
292 	}
293 	/* 0xb00000-0xbfffff: empty area */
294 	if (a <= M68K_EMPTY2_END)
295 		return 0;
296 	/* 0xc00000-0xdfffff: VDP/PSG */
297 	if (a <= M68K_VDP_END) {
298 		return m68k_VDP_read(a);
299 	}
300 	/* 0xe00000-0xfeffff: invalid addresses, mirror RAM */
301 	/* 0xff0000-0xffffff: RAM */
302 	return ram[((a ^ 1) & 0xffff)];
303 }
304 
m68k_ROM_write(uint32_t a,uint8_t d)305 void md::m68k_ROM_write(uint32_t a, uint8_t d)
306 {
307 	/* save RAM */
308 	if ((!save_prot) && (save_len) &&
309 	    (a >= save_start) && ((a - save_start) < save_len))
310 		saveram[((a ^ 1) - save_start)] = d;
311 #ifdef WITH_DEBUGGER
312 	/* Allow debugger to write to the ROM. */
313 	if ((debug_trap) && (ROM_ADDR(a) < romlen))
314 		rom[ROM_ADDR(a)] = d;
315 #endif
316 }
317 
m68k_IO_write(uint32_t a,uint8_t d)318 void md::m68k_IO_write(uint32_t a, uint8_t d)
319 {
320 	/* Z80 */
321 	if (a < 0xa10000) {
322 		if ((!z80_st_busreq) && (a < 0xa04000))
323 			return;
324 		z80_write((a & 0xffff), d);
325 		return;
326 	}
327 	if (a == 0xa11100) {
328 		/* Z80 BUSREQ */
329 		if (d & 0x01)
330 			m68k_busreq_request();
331 		else
332 			m68k_busreq_cancel();
333 		return;
334 	}
335 	if (a == 0xa11101)
336 		return;
337 	/* Z80 RESET */
338 	if (a == 0xa11200) {
339 		/* cancel RESET state if nonzero */
340 		if (d)
341 			z80_st_reset = 0;
342 		else if (z80_st_reset == 0) {
343 			if (z80_st_busreq == 0)
344 				z80_sync(0);
345 			z80_st_reset = 1;
346 			z80_reset();
347 			fm_reset();
348 		}
349 		return;
350 	}
351 	if (a == 0xa11201)
352 		return;
353 	/* I/O port access */
354 	if (a < 0xa1000d) {
355 		if (a == 0xa10003) {
356 			if ((aoo3_six >= 0) && ((d & 0x40) == 0) &&
357 			    (aoo3_toggle))
358 				++aoo3_six;
359 			if (aoo3_six > 0xc00000)
360 				aoo3_six &= ~0x400000;
361 			/* keep it circling around a high value */
362 			if (d & 0x40)
363 				aoo3_toggle = 1;
364 			else
365 				aoo3_toggle = 0;
366 			aoo3_six_timeout = 0;
367 			return;
368 		}
369 		if (a == 0xa10005) {
370 			if ((aoo5_six >= 0) && ((d & 0x40) == 0) &&
371 			    (aoo5_toggle))
372 				++aoo5_six;
373 			if (aoo5_six > 0xc00000)
374 				aoo5_six &= ~0x400000;
375 			/* keep it circling around a high value */
376 			if (d & 0x40)
377 				aoo5_toggle = 1;
378 			else
379 				aoo5_toggle = 0;
380 			aoo5_six_timeout = 0;
381 			return;
382 		}
383 		return;
384 	}
385 	/* save RAM status */
386 	if (a == 0xa130f1) {
387 		/*
388 		  Bit 0: 0 = ROM active, 1 = SRAM active
389 		  Bit 1: 0 = writable protect
390 		*/
391 		save_active = (d & 1);
392 		save_prot = (d & 2);
393 		return;
394 	}
395 	return;
396 }
397 
398 /**
399  * write a byte to the m68Ks ram.
400  * @param a Address to write.
401  * @param d Date (byte) two write.
402  */
misc_writebyte(uint32_t a,uint8_t d)403 void md::misc_writebyte(uint32_t a, uint8_t d)
404 {
405 	/* clip to 24-bit */
406 	a &= 0x00ffffff;
407 	/* 0x000000-0x7fffff: ROM */
408 	if (a <= M68K_ROM_END) {
409 		m68k_ROM_write(a, d);
410 		return;
411 	}
412 	/* 0x800000-0x9fffff: empty area */
413 	if (a <= M68K_EMPTY1_END)
414 		return;
415 	/* 0xa00000-0xafffff: system I/O and control */
416 	if (a <= M68K_IO_END) {
417 		m68k_IO_write(a, d);
418 		return;
419 	}
420 	/* 0xb00000-0xbfffff: empty area */
421 	if (a <= M68K_EMPTY2_END)
422 		return;
423 	/* 0xc00000-0xdfffff: VDP/PSG */
424 	if (a < M68K_VDP_END) {
425 		a &= 0xe700ff;
426 		if (a < 0xc00008) {
427 			misc_writeword(a, (d | (d << 8)));
428 			return;
429 		}
430 		/* PSG */
431 		if (a == 0xc00011)
432 			mysn_write(d);
433 		return;
434 	}
435 	/* 0xe00000-0xfeffff: invalid addresses, mirror RAM */
436 	/* 0xff0000-0xffffff: RAM */
437 	ram[((a ^ 1) & 0xffff)] = d;
438 }
439 
440 
441 /**
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.
447  */
misc_readword(uint32_t a)448 uint16_t md::misc_readword(uint32_t a)
449 {
450 	uint16_t ret;
451 
452 	a &= 0x00ffffff;
453 	/* BUSREQ */
454 	if ((a & 0xffff00) == 0xa11100)
455 		return ((!z80_st_busreq << 8) | (m68k_read_pc() & 0xfeff));
456 	/* RESET */
457 	if ((a & 0xffff00) == 0xa11200)
458 		return m68k_read_pc();
459 	/* VDP */
460 	if ((a >= 0xc00000) && (a < 0xe00000)) {
461 		a &= 0xe700ff;
462 		if (a < 0xc00004) {
463 			if (a & 0x01)
464 				return 0;
465 			vdp.cmd_pending = false;
466 			return vdp.readword();
467 		}
468 		if (a < 0xc00008) {
469 			if (a & 0x01)
470 				return 0;
471 			return (((coo4 & 0xff) << 8) | (coo5 & 0xff));
472 		}
473 		if (a == 0xc00008) {
474 			if (a & 0x01)
475 				return 0;
476 			return ((calculate_coo8() << 8) |
477 				(calculate_coo9() & 0xff));
478 		}
479 	}
480 	/* else pass onto readbyte */
481 	ret = (misc_readbyte(a) << 8);
482 	ret |= misc_readbyte(a + 1);
483 	return ret;
484 }
485 
486 /**
487  * Write a word to m68k memory
488  * @param a Address to write to.
489  * @param d Data to write.
490  */
misc_writeword(uint32_t a,uint16_t d)491 void md::misc_writeword(uint32_t a, uint16_t d)
492 {
493 	a &= 0x00ffffff;
494 	/* Z80 */
495 	if ((a >= 0xa00000) && (a < 0xa10000)) {
496 		if ((!z80_st_busreq) && (a < 0xa04000))
497 			return;
498 		z80_write((a & 0xffff), (d >> 8));
499 		return;
500 	}
501 	/* BUSREQ and RESET */
502 	if ((a == 0xa11100) ||
503 	    (a == 0xa11200)) {
504 		misc_writebyte(a, (d >> 8));
505 		return;
506 	}
507 	/* VDP */
508 	if ((a >= 0xc00000) && (a < 0xe00000)) {
509 		a &= 0xe700ff;
510 		if (a < 0xc00004) {
511 			if (a & 0x01)
512 				return;
513 			vdp.writeword(d);
514 			vdp.cmd_pending = false;
515 			return;
516 		}
517 		if (a < 0xc00008) {
518 			if (a & 0x01)
519 				return;
520 			/* second half of a command */
521 			if (vdp.cmd_pending) {
522 				vdp.command(d);
523 				return;
524 			}
525 			/* register write */
526 			if ((d & 0xc000) == 0x8000) {
527 				uint8_t addr = ((d >> 8) & 0x1f);
528 				vdp.write_reg(addr, d);
529 				return;
530 			}
531 			/* first half of a command */
532 			vdp.command(d);
533 			vdp.cmd_pending = true;
534 			return;
535 		}
536 	}
537 	/* else pass onto writebyte */
538 	misc_writebyte(a, (d >> 8));
539 	misc_writebyte((a + 1), (d & 0xff));
540 }
541 
542 #ifdef WITH_MUSA
543 
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.
549 
550 /* Read from anywhere */
m68k_read_memory_8(unsigned int address)551 extern "C" unsigned int m68k_read_memory_8(unsigned int address)
552 {
553 	return md::md_musa->misc_readbyte(address);
554 }
555 
m68k_read_memory_16(unsigned int address)556 extern "C" unsigned int m68k_read_memory_16(unsigned int address)
557 {
558 	return md::md_musa->misc_readword(address);
559 }
560 
m68k_read_memory_32(unsigned int address)561 extern "C" unsigned int m68k_read_memory_32(unsigned int address)
562 {
563 	return ((md::md_musa->misc_readword(address) << 16) |
564 		(md::md_musa->misc_readword(address + 2) & 0xffff));
565 }
566 
567 /* Read data immediately following the PC */
m68k_read_immediate_8(unsigned int address)568 extern "C" unsigned int m68k_read_immediate_8(unsigned int address)
569 {
570 	return m68k_read_memory_8(address);
571 }
572 
m68k_read_immediate_16(unsigned int address)573 extern "C" unsigned int m68k_read_immediate_16(unsigned int address)
574 {
575 	return m68k_read_memory_16(address);
576 }
577 
m68k_read_immediate_32(unsigned int address)578 extern "C" unsigned int m68k_read_immediate_32(unsigned int address)
579 {
580 	return m68k_read_memory_32(address);
581 }
582 
583 /* Read an instruction (16-bit word immeditately after PC) */
m68k_read_instruction(unsigned int address)584 extern "C" unsigned int m68k_read_instruction(unsigned int address)
585 {
586 	return m68k_read_memory_16(address);
587 }
588 
589 /* Write to anywhere */
m68k_write_memory_8(unsigned int address,unsigned int value)590 extern "C" void m68k_write_memory_8(unsigned int address, unsigned int value)
591 {
592 	md::md_musa->misc_writebyte(address, value);
593 }
594 
m68k_write_memory_16(unsigned int address,unsigned int value)595 extern "C" void m68k_write_memory_16(unsigned int address, unsigned int value)
596 {
597 	md::md_musa->misc_writeword(address, value);
598 }
599 
m68k_write_memory_32(unsigned int address,unsigned int value)600 extern "C" void m68k_write_memory_32(unsigned int address, unsigned int value)
601 {
602 	md::md_musa->misc_writeword(address, ((value >> 16) & 0xffff));
603 	md::md_musa->misc_writeword((address + 2), (value & 0xffff));
604 }
605 
606 #endif // WITH_MUSA
607 
608 #ifdef WITH_CYCLONE
609 
610 /* Read from anywhere */
cyclone_read_memory_8(uint32_t address)611 extern "C" uint32_t cyclone_read_memory_8(uint32_t address)
612 {
613 	return md::md_cyclone->misc_readbyte(address);
614 }
615 
cyclone_read_memory_16(uint32_t address)616 extern "C" uint32_t cyclone_read_memory_16(uint32_t address)
617 {
618 	return md::md_cyclone->misc_readword(address);
619 }
620 
cyclone_read_memory_32(uint32_t address)621 extern "C" uint32_t cyclone_read_memory_32(uint32_t address)
622 {
623 	return ((md::md_cyclone->misc_readword(address) << 16) |
624 		(md::md_cyclone->misc_readword(address + 2) & 0xffff));
625 }
626 
627 /* Write to anywhere */
cyclone_write_memory_8(uint32_t address,uint8_t value)628 extern "C" void cyclone_write_memory_8(uint32_t address, uint8_t value)
629 {
630 	md::md_cyclone->misc_writebyte(address, value);
631 }
632 
cyclone_write_memory_16(uint32_t address,uint16_t value)633 extern "C" void cyclone_write_memory_16(uint32_t address, uint16_t value)
634 {
635 	md::md_cyclone->misc_writeword(address, value);
636 }
637 
cyclone_write_memory_32(uint32_t address,uint32_t value)638 extern "C" void cyclone_write_memory_32(uint32_t address, uint32_t value)
639 {
640 	md::md_cyclone->misc_writeword(address, ((value >> 16) & 0xffff));
641 	md::md_cyclone->misc_writeword((address + 2), (value & 0xffff));
642 }
643 
checkpc(uintptr_t pc)644 uintptr_t md::checkpc(uintptr_t pc)
645 {
646 	static uint8_t zero[(M68K_EMPTY1_END + 1)];
647 
648 	pc -= cyclonecpu.membase; // Get the real program counter.
649 
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;
654 		pc -= save_start;
655 	}
656 	if (pc <= romlen)
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) {
661 		pc &= 0xffff;
662 		cyclonecpu.membase = (uintptr_t)ram; // Jump to RAM.
663 	}
664 	else {
665 		DEBUG(("PC out of bounds: %06x", pc));
666 		// Freeze, avoid crashing the emulator.
667 		cyclonecpu.membase = (uintptr_t)no_rom;
668 		pc = 0;
669 	}
670 	return (cyclonecpu.membase + pc); // New program counter.
671 }
672 
cyclone_checkpc(uintptr_t pc)673 extern "C" uintptr_t cyclone_checkpc(uintptr_t pc)
674 {
675 	return md::md_cyclone->checkpc(pc);
676 }
677 
678 #endif // WITH_CYCLONE
679 
680 #ifdef WITH_STAR
681 
star_readbyte(unsigned a,unsigned d)682 extern "C" unsigned star_readbyte(unsigned a, unsigned d)
683 {
684 	(void)d;
685 	return md::md_star->misc_readbyte(a);
686 }
687 
star_readword(unsigned a,unsigned d)688 extern "C" unsigned star_readword(unsigned a, unsigned d)
689 {
690 	(void)d;
691 	return md::md_star->misc_readword(a);
692 }
693 
star_writebyte(unsigned a,unsigned d)694 extern "C" unsigned star_writebyte(unsigned a, unsigned d)
695 {
696 	md::md_star->misc_writebyte(a, d);
697 	return 0;
698 }
699 
star_writeword(unsigned a,unsigned d)700 extern "C" unsigned star_writeword(unsigned a, unsigned d)
701 {
702 	md::md_star->misc_writeword(a, d);
703 	return 0;
704 }
705 
706 #endif // WITH_STAR
707 
708 #ifdef WITH_MZ80
709 
710 /*
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
714   crashes otherwise.
715 */
716 
717 #ifdef WITH_X86_MZ80
718 #define MZ80_NOSIBCALL(t, w) *((volatile t *)&(w))
719 #else
720 #define MZ80_NOSIBCALL(t, w) (w)
721 #endif
722 
mz80_read(UINT32 a,struct MemoryReadByte * unused)723 extern "C" UINT8 mz80_read(UINT32 a, struct MemoryReadByte *unused)
724 {
725 	(void)unused;
726 	return md::md_mz80->z80_read(MZ80_NOSIBCALL(UINT32, a));
727 }
728 
mz80_write(UINT32 a,UINT8 d,struct MemoryWriteByte * unused)729 extern "C" void mz80_write(UINT32 a, UINT8 d, struct MemoryWriteByte *unused)
730 {
731 	(void)unused;
732 	md::md_mz80->z80_write(MZ80_NOSIBCALL(UINT32, a), d);
733 }
734 
mz80_ioread(UINT16 a,struct z80PortRead * unused)735 extern "C" UINT16 mz80_ioread(UINT16 a, struct z80PortRead *unused)
736 {
737 	(void)unused;
738 	return md::md_mz80->z80_port_read(MZ80_NOSIBCALL(UINT16, a));
739 }
740 
mz80_iowrite(UINT16 a,UINT8 d,struct z80PortWrite * unused)741 extern "C" void mz80_iowrite(UINT16 a, UINT8 d, struct z80PortWrite *unused)
742 {
743 	(void)unused;
744 	return md::md_mz80->z80_port_write(MZ80_NOSIBCALL(UINT16, a), d);
745 }
746 
747 #endif // WITH_MZ80
748 
749 #ifdef WITH_CZ80
750 
cz80_memread(void * ctx,uint16_t a)751 extern "C" uint8_t cz80_memread(void *ctx, uint16_t a)
752 {
753 	class md* md = (class md*)ctx;
754 
755 	return md->z80_read(a);
756 }
757 
cz80_memwrite(void * ctx,uint16_t a,uint8_t d)758 extern "C" void cz80_memwrite(void *ctx, uint16_t a, uint8_t d)
759 {
760 	class md* md = (class md*)ctx;
761 
762 	md->z80_write(a, d);
763 }
764 
cz80_memread16(void * ctx,uint16_t a)765 extern "C" uint16_t cz80_memread16(void *ctx, uint16_t a)
766 {
767 	class md* md = (class md*)ctx;
768 
769 	return ((uint16_t)md->z80_read(a) |
770 		((uint16_t)md->z80_read(a + 1) << 8));
771 }
772 
cz80_memwrite16(void * ctx,uint16_t a,uint16_t d)773 extern "C" void cz80_memwrite16(void *ctx, uint16_t a, uint16_t d)
774 {
775 	class md* md = (class md*)ctx;
776 
777 	md->z80_write(a, (uint8_t)d);
778 	md->z80_write((a + 1), (uint8_t)(d >> 8));
779 }
780 
cz80_ioread(void * ctx,uint16_t a)781 extern "C" uint8_t cz80_ioread(void *ctx, uint16_t a)
782 {
783 	class md* md = (class md*)ctx;
784 
785 	return md->z80_port_read(a);
786 }
787 
cz80_iowrite(void * ctx,uint16_t a,uint8_t d)788 extern "C" void cz80_iowrite(void *ctx, uint16_t a, uint8_t d)
789 {
790 	class md* md = (class md*)ctx;
791 
792 	md->z80_port_write(a, d);
793 }
794 
795 #endif // WITH_CZ80
796 
797 #ifdef WITH_DRZ80
798 
drz80_rebase_pc(uint16_t address)799 uintptr_t md::drz80_rebase_pc(uint16_t address)
800 {
801 	// PC in memory - rebase PC into memory.
802 	drz80.Z80PC_BASE = (uintptr_t)z80ram;
803 	return (drz80.Z80PC_BASE + address);
804 }
805 
drz80_rebase_sp(uint16_t address)806 uintptr_t md::drz80_rebase_sp(uint16_t address)
807 {
808 	// SP in memory - rebase SP into memory.
809 	drz80.Z80SP_BASE = (uintptr_t)z80ram;
810 	return (drz80.Z80SP_BASE + address);
811 }
812 
drz80_rebaseSP(uint16_t new_sp)813 uintptr_t drz80_rebaseSP(uint16_t new_sp)
814 {
815 	return md::md_drz80->drz80_rebase_sp(new_sp);
816 }
817 
drz80_rebasePC(uint16_t new_pc)818 uintptr_t drz80_rebasePC(uint16_t new_pc)
819 {
820 	return md::md_drz80->drz80_rebase_pc(new_pc);
821 }
822 
drz80_read8(uint16_t a)823 uint8_t drz80_read8(uint16_t a)
824 {
825 	return md::md_drz80->z80_read(a);
826 }
827 
drz80_read16(uint16_t a)828 uint16_t drz80_read16(uint16_t a)
829 {
830 	return ((uint16_t)md::md_drz80->z80_read(a) |
831 		((uint16_t)md::md_drz80->z80_read(a + 1) << 8));
832 }
833 
drz80_write8(uint8_t d,uint16_t a)834 void drz80_write8(uint8_t d, uint16_t a)
835 {
836 	md::md_drz80->z80_write(a, d);
837 }
838 
drz80_write16(uint16_t d,uint16_t a)839 void drz80_write16(uint16_t d, uint16_t a)
840 {
841 	md::md_drz80->z80_write(a, (uint8_t)d);
842 	md::md_drz80->z80_write((a + 1), (uint8_t)(d >> 8));
843 }
844 
drz80_in(uint16_t p)845 uint8_t drz80_in(uint16_t p)
846 {
847 	(void)p;
848 	return 0xff;
849 }
850 
drz80_out(uint16_t p,uint8_t d)851 void drz80_out(uint16_t p, uint8_t d)
852 {
853 	(void)p;
854 	(void)d;
855 }
856 
857 #endif // WITH_DRZ80
858