2 // Megadrive C++ module
9 // This is the 'static' StarScream/MZ80 multitasker
10 // which detects which megadrive is active (by which star_mz80_on() has been called
11 // and forwards to the appropriate misc_read/writebyte/word/z80 function
12 // of the appropriate instance (grrrr - bloody C++)
16 int md::star_mz80_on()
18 #ifdef COMPILE_WITH_STAR
19 s68000SetContext(&cpu
);
25 int md::star_mz80_off()
28 #ifdef COMPILE_WITH_STAR
29 s68000GetContext(&cpu
);
37 unsigned root_readbyte(unsigned a
)
38 { if (which
) return which
->misc_readbyte(a
); else return 0x00; }
39 unsigned root_readword(unsigned a
)
40 { if (which
) return which
->misc_readword(a
); else return 0x0000; }
42 unsigned root_readlong(unsigned a
)
44 return (root_readword(a
)<<16)+root_readword(a
+2);
47 void root_writebyte(unsigned a
,unsigned d
)
48 { if (which
) which
->misc_writebyte(a
,d
); }
49 void root_writeword(unsigned a
,unsigned d
)
50 { if (which
) which
->misc_writeword(a
,d
); }
52 void root_writelong(unsigned a
,unsigned d
)
54 root_writeword(a
,(d
>>16)&0xffff);
55 root_writeword(a
+2,d
&0xffff);
59 #ifdef COMPILE_WITH_MUSA
60 // Okay: a bit for MUSASHI
63 // read/write functions called by the CPU to access memory.
64 // while values used are 32 bits, only the appropriate number
65 // of bits are relevant (i.e. in write_memory_8, only the lower 8 bits
66 // of value should be written to memory).
67 // address will be a 24-bit value.
69 /* Read from anywhere */
70 int m68k_read_memory_8(int address
) { return root_readbyte(address
); }
71 int m68k_read_memory_16(int address
) {
72 return root_readword(address
);
74 int m68k_read_memory_32(int address
) { return root_readlong(address
); }
76 /* Read data immediately following the PC */
77 int m68k_read_immediate_8(int address
) { return root_readbyte(address
); }
78 int m68k_read_immediate_16(int address
) { return root_readword(address
); }
79 int m68k_read_immediate_32(int address
) { return root_readlong(address
); }
81 /* Read an instruction (16-bit word immeditately after PC) */
82 int m68k_read_instruction(int address
) { return root_readword(address
); }
84 /* Write to anywhere */
85 void m68k_write_memory_8(int address
, int value
) { root_writebyte(address
,value
); }
86 void m68k_write_memory_16(int address
, int value
) { root_writeword(address
,value
); }
87 void m68k_write_memory_32(int address
, int value
) { root_writelong(address
,value
); }
91 // The same thing for 68KEM
92 #ifdef COMPILE_WITH_M68KEM
94 int cpu_readmem24(int address
) { return root_readbyte(address
); }
95 int cpu_readmem24_word(int address
) { return root_readword(address
); }
96 int cpu_readmem24_dword(int address
) { return root_readlong(address
); }
98 void cpu_writemem24(int address
, int val
) { root_writebyte(address
, val
); }
99 void cpu_writemem24_word(int address
, int val
) { root_writeword(address
, val
); }
100 void cpu_writemem24_dword(int address
, int val
) { root_writelong(address
, val
); }
102 unsigned char *OP_ROM
, *OP_RAM
;
103 void cpu_setOPbase24(int pc
) {
104 if(!which
) return; // star_mz80_on() wasn't called! :0
105 if (pc
< 0xa00000) // ROM area
107 if (pc
>= 0xe00000) // RAM
108 OP_ROM
= which
->ram
- (pc
& 0xff0000);
113 UINT8
root_z80_read(UINT32 a
,struct MemoryReadByte
*huh
)
116 if (which
) return which
->z80_read(a
); return 0x00;
118 void root_z80_write(UINT32 a
,UINT8 d
,struct MemoryWriteByte
*huh
)
121 if (which
) which
->z80_write(a
,d
);
123 UINT16
root_z80_port_read(UINT16 a
, struct z80PortRead
*huh
)
126 if (which
) return which
->z80_port_read(a
); return 0x0000;
128 void root_z80_port_write(UINT16 a
,UINT8 d
, struct z80PortWrite
*huh
)
131 if (which
) which
->z80_port_write(a
,d
);
135 extern FILE *debug_log
;
139 int mega_dacout
=0,mega_dacen
=0;
142 #ifdef COMPILE_WITH_STAR
148 if (rommax
>0xa00000) rommax
=0xa00000;
149 if (rommax
<0) rommax
=0;
151 // FETCH: Set up 2 or 3 FETCH sections
154 { fetch
[i
].lowaddr
=0x000000; fetch
[i
].highaddr
=rommax
-1; fetch
[i
].offset
=(unsigned)rom
-0x000000; i
++; }
155 fetch
[i
].lowaddr
=0xff0000; fetch
[i
].highaddr
=0xffffff; fetch
[i
].offset
=(unsigned)ram
- 0xff0000; i
++;
157 fetch
[i
].lowaddr
=0xffff0000; fetch
[i
].highaddr
=0xffffffff; fetch
[i
].offset
=(unsigned)ram
-0xffff0000; i
++;
159 fetch
[i
].lowaddr
=0xff000000; fetch
[i
].highaddr
=0xff000000+rommax
-1; fetch
[i
].offset
=(unsigned)rom
-0xff000000; i
++;
160 fetch
[i
].lowaddr
=fetch
[i
].highaddr
=0xffffffff; fetch
[i
].offset
=0; i
++;
163 fprintf (debug_log
,"StarScream memory_map has %d fetch sections\n",i
);
168 // Simple version ***************
169 readbyte
[i
].lowaddr
= readword
[i
].lowaddr
=
170 writebyte
[j
].lowaddr
= writeword
[j
].lowaddr
= 0;
171 readbyte
[i
].highaddr
= readword
[i
].highaddr
=
172 writebyte
[j
].highaddr
= writeword
[j
].highaddr
= 0xffffffff;
174 readbyte
[i
].memorycall
=(void *) root_readbyte
;
175 readword
[i
].memorycall
=(void *) root_readword
;
176 writebyte
[j
].memorycall
=(void *)root_writebyte
;
177 writeword
[j
].memorycall
=(void *)root_writeword
;
179 readbyte
[i
].userdata
= readword
[i
].userdata
=
180 writebyte
[j
].userdata
= writeword
[j
].userdata
= NULL
;
182 // Simple version end ***************
185 // Faster version ***************
186 // IO: Set up 3/4 read sections, and 2/3 write sections
189 // Cartridge save RAM memory
191 readbyte
[i
].lowaddr
= readword
[i
].lowaddr
=
192 writebyte
[j
].lowaddr
= writeword
[j
].lowaddr
= save_start
;
193 readbyte
[i
].highaddr
= readword
[i
].highaddr
=
194 writebyte
[j
].highaddr
= writeword
[j
].highaddr
= save_start
+save_len
-1;
195 readbyte
[i
].memorycall
= (void*)root_readbyte
;
196 readword
[j
].memorycall
= (void*)root_readword
;
197 writebyte
[i
].memorycall
=(void*)root_writebyte
;
198 writeword
[j
].memorycall
=(void*)root_writeword
;
199 readbyte
[i
].userdata
= readword
[i
].userdata
=
200 writebyte
[j
].userdata
= writeword
[j
].userdata
= NULL
;
203 // Cartridge ROM memory (read only)
204 readbyte
[i
].lowaddr
= readword
[i
].lowaddr
= 0x000000;
205 readbyte
[i
].highaddr
= readword
[i
].highaddr
= rommax
-1;
206 readbyte
[i
].memorycall
=readword
[i
].memorycall
=NULL
;
207 readbyte
[i
].userdata
= readword
[i
].userdata
= rom
;
209 // misc memory (e.g. aoo and coo) through root_rw
210 readbyte
[i
].lowaddr
= readword
[i
].lowaddr
=
211 writebyte
[j
].lowaddr
= writeword
[j
].lowaddr
= rommax
;
214 readbyte
[i
].lowaddr
= readword
[i
].lowaddr
=
215 writebyte
[j
].lowaddr
= writeword
[j
].lowaddr
= 0;
217 readbyte
[i
].highaddr
= readword
[i
].highaddr
=
218 writebyte
[j
].highaddr
= writeword
[j
].highaddr
= 0xfeffff;
220 readbyte
[i
].memorycall
=(void *) root_readbyte
;
221 readword
[i
].memorycall
=(void *) root_readword
;
222 writebyte
[j
].memorycall
=(void *)root_writebyte
;
223 writeword
[j
].memorycall
=(void *)root_writeword
;
225 readbyte
[i
].userdata
= readword
[i
].userdata
=
226 writebyte
[j
].userdata
= writeword
[j
].userdata
= NULL
;
229 // scratch RAM memory
230 readbyte
[i
].lowaddr
= readword
[i
].lowaddr
=
231 writebyte
[j
].lowaddr
= writeword
[j
].lowaddr
= 0xff0000;
232 readbyte
[i
].highaddr
= readword
[i
].highaddr
=
233 writebyte
[j
].highaddr
= writeword
[j
].highaddr
= 0xffffff;
234 readbyte
[i
].memorycall
= readword
[i
].memorycall
=
235 writebyte
[j
].memorycall
=writeword
[j
].memorycall
= NULL
;
236 readbyte
[i
].userdata
= readword
[i
].userdata
=
237 writebyte
[j
].userdata
= writeword
[j
].userdata
= ram
;
239 // Faster version end ***************
243 readbyte
[i
].lowaddr
= readword
[i
].lowaddr
=
244 writebyte
[j
].lowaddr
= writeword
[j
].lowaddr
=
245 readbyte
[i
].highaddr
= readword
[i
].highaddr
=
246 writebyte
[j
].highaddr
= writeword
[j
].highaddr
= 0xffffffff;
248 readbyte
[i
].memorycall
= readword
[i
].memorycall
=
249 writebyte
[j
].memorycall
= writeword
[j
].memorycall
=
250 readbyte
[i
].userdata
= readword
[i
].userdata
=
251 writebyte
[j
].userdata
= writeword
[j
].userdata
= NULL
;
255 fprintf (debug_log
,"StarScream memory_map has %d read sections and %d write sections\n",i
,j
);
264 #ifdef COMPILE_WITH_STAR
265 if (cpu_emu
==0) s68000reset();
267 #ifdef COMPILE_WITH_MUSA
268 if (cpu_emu
==1) m68k_pulse_reset(NULL
);
270 #ifdef COMPILE_WITH_M68KEM
271 if (cpu_emu
==2) m68000_reset(NULL
);
273 if (debug_log
) fprintf (debug_log
,"reset()\n");
276 // zero = natural state of select line?
278 z80_bank68k
=z80_online
=z80_extra_cycles
279 =coo_waiting
=coo_cmd
=aoo3_toggle
=aoo5_toggle
=aoo3_six
=aoo5_six
280 =aoo3_six_timeout
=aoo5_six_timeout
282 pad
[0]=pad
[1]=0xf303f; // Untouched pad
284 // Reset FM registers
291 fm_sel
[0] = fm_sel
[1] = fm_tover
[0] = fm_tover
[1] = 0;
294 odo
=odo_line_start
=odo_line_end
=ras
=0;
303 static struct MemoryReadByte mem_read
[]=
305 {0x2000,0xffff,root_z80_read
},
306 {(UINT32
) -1,(UINT32
) -1,NULL
}
308 static struct MemoryWriteByte mem_write
[]=
310 {0x2000,0xffff,root_z80_write
},
311 {(UINT32
) -1,(UINT32
) -1,NULL
}
313 static struct z80PortRead io_read
[] ={
314 {0x00,0x00ff,root_z80_port_read
},
315 {(UINT16
) -1,(UINT16
) -1,NULL
}
317 static struct z80PortWrite io_write
[]={
318 {0x00,0x00ff,root_z80_port_write
},
319 {(UINT16
) -1,(UINT16
) -1,NULL
}
327 // Modify the default context
328 mz80GetContext(&z80
);
332 z80
.z80MemRead
=mem_read
;
333 z80
.z80MemWrite
=mem_write
;
334 z80
.z80IoRead
=io_read
;
335 z80
.z80IoWrite
=io_write
;
337 mz80SetContext(&z80
);
347 mem
=rom
=ram
=z80ram
=saveram
=NULL
;
348 save_start
=save_len
=save_prot
=save_active
=0;
351 fm_sel
[0]=fm_sel
[1]=fm_tover
[0]=fm_tover
[1]=0;
353 memset(&fm_reg
,0,sizeof(fm_reg
));
354 memset(&ras_fm_ticker
,0,sizeof(ras_fm_ticker
));
356 #ifdef COMPILE_WITH_STAR
358 readbyte
=readword
=writebyte
=writeword
=NULL
;
359 memset(&cpu
,0,sizeof(cpu
));
362 memset(&z80
,0,sizeof(z80
));
364 country_ver
=0xff0; layer_sel
= 0xff;
366 memset(romfilename
,0,sizeof(romfilename
));
369 if (!vdp
.okay()) return;
372 // Format of pad is: __SA____ UDLRBC__
374 rom
=mem
=ram
=z80ram
=NULL
;
375 mem
=(unsigned char *)malloc(0x20000);
376 if (mem
==NULL
) return;
377 memset(mem
,0,0x20000);
383 star_mz80_on(); // VERY IMPORTANT - Must call before using stars/mz80!!
385 #ifdef COMPILE_WITH_STAR
386 if (s68000init()!=0) { printf ("s68000init failed!\n"); return; }
389 star_mz80_off(); // VERY IMPORTANT - Must call after using stars/mz80!!
391 cpu_emu
=-1; // Do we have a cpu emu?
392 #ifdef COMPILE_WITH_STAR
393 // Dave: Rich said doing point star stuff is done after s68000init
394 // in Asgard68000, so just in case...
395 fetch
= new STARSCREAM_PROGRAMREGION
[6]; if (!fetch
) return;
396 readbyte
= new STARSCREAM_DATAREGION
[5]; if (!readbyte
) return;
397 readword
= new STARSCREAM_DATAREGION
[5]; if (!readword
) return;
398 writebyte
=new STARSCREAM_DATAREGION
[5]; if (!writebyte
) return;
399 writeword
=new STARSCREAM_DATAREGION
[5]; if (!writeword
) return;
403 cpu
.s_fetch
= cpu
.u_fetch
= fetch
;
404 cpu
.s_readbyte
= cpu
.u_readbyte
= readbyte
;
405 cpu
.s_readword
= cpu
.u_readword
= readword
;
406 cpu
.s_writebyte
= cpu
.u_writebyte
= writebyte
;
407 cpu
.s_writeword
= cpu
.u_writeword
= writeword
;
408 cpu_emu
=0; // zero=starscream, one=musashi, two=68kem
410 #ifdef COMPILE_WITH_MUSA
411 cpu_emu
=1; // zero=starscream, one=musash, two=68kemi
413 #ifdef COMPILE_WITH_M68KEM
414 cpu_emu
=2; // zero=starscream, one=musash, two=68kemi
418 #ifdef COMPILE_WITH_MUSA
419 m68k_pulse_reset(NULL
);
422 #ifdef COMPILE_WITH_M68KEM
428 reset(); // reset megadrive
437 if (rom
!=NULL
) unplug();
440 rom
=mem
=ram
=z80ram
=NULL
;
442 #ifdef COMPILE_WITH_STAR
443 if (fetch
) delete[] fetch
;
444 if (readbyte
) delete[] readbyte
;
445 if (readword
) delete[] readword
;
446 if (writebyte
) delete[] writebyte
;
447 if (writeword
) delete[] writeword
;
454 int byteswap_memory(unsigned char *start
,int len
)
455 { int i
; unsigned char tmp
;
457 { tmp
=start
[i
+0]; start
[i
+0]=start
[i
+1]; start
[i
+1]=tmp
; }
461 int md::plug_in(unsigned char *cart
,int len
)
463 // Plug in the cartridge specified by the uchar *
464 // NB - The megadrive will free() it if unplug() is called, or it exits
465 // So it must be a single piece of malloced data
466 if (cart
==NULL
) return 1; if (len
<=0) return 1;
467 byteswap_memory(cart
,len
); // for starscream
470 // Get saveram start, length (remember byteswapping)
471 // First check magic, if there is saveram
472 if(rom
[0x1b1] == 'R' && rom
[0x1b0] == 'A')
474 save_start
= rom
[0x1b5] << 24 | rom
[0x1b4] << 16 |
475 rom
[0x1b7] << 8 | rom
[0x1b6];
476 save_len
= rom
[0x1b9] << 24 | rom
[0x1b8] << 16 |
477 rom
[0x1bb] << 8 | rom
[0x1ba];
478 // Make sure start is even, end is odd, for alignment
479 // A ROM that I came across had the start and end bytes of
480 // the save ram the same and wouldn't work. Fix this as seen
481 // fit, I know it could probably use some work. [PKH]
482 if(save_start
!= save_len
) {
483 if(save_start
& 1) --save_start
;
484 if(!(save_len
& 1)) ++save_len
;
485 save_len
-= (save_start
- 1);
486 saveram
= (unsigned char*)malloc(save_len
);
487 // If save RAM does not overlap main ROM, set it active by default since
488 // a few games can't manage to properly switch it on/off.
489 if(save_start
>= romlen
)
493 save_start
= save_len
= 0;
499 save_start
= save_len
= 0;
502 #ifdef COMPILE_WITH_STAR
503 memory_map(); // Update memory map to include this cartridge
505 reset(); // Reset megadrive
511 if (rom
==NULL
) return 1; if (romlen
<=0) return 1;
512 free(rom
); free(saveram
); romlen
= save_start
= save_len
= 0;
513 #ifdef COMPILE_WITH_STAR
514 memory_map(); // Update memory map to include no rom
516 memset(romfilename
,0,sizeof(romfilename
));
522 extern "C" int load_rom_into(char *name
,unsigned char *into
);
524 int md::load(char *name
)
526 // Convenience function - calls romload.c functions
527 unsigned char *temp
=NULL
; int len
=0;
528 if (name
==NULL
) return 1;
530 len
=load_rom_into(name
,NULL
);
531 if (len
<=0) return 1;
532 temp
=(unsigned char *)malloc(len
);
533 if (temp
==NULL
) return 1;
534 load_rom_into(name
,temp
);
536 strncpy(romfilename
,name
,255);
537 // Fill the header with ROM info (god this is ugly)
538 memcpy((void*)cart_head
.system_name
, (void*)(temp
+ 0x100), 0x10);
539 memcpy((void*)cart_head
.copyright
, (void*)(temp
+ 0x110), 0x10);
540 memcpy((void*)cart_head
.domestic_name
,(void*)(temp
+ 0x120), 0x30);
541 memcpy((void*)cart_head
.overseas_name
,(void*)(temp
+ 0x150), 0x30);
542 memcpy((void*)cart_head
.product_no
, (void*)(temp
+ 0x180), 0x0e);
543 cart_head
.checksum
= temp
[0x18e]<<8 | temp
[0x18f]; // ugly, but endian-neutral
544 memcpy((void*)cart_head
.control_data
, (void*)(temp
+ 0x190), 0x10);
545 cart_head
.rom_start
= temp
[0x1a0]<<24 | temp
[0x1a1]<<16 | temp
[0x1a2]<<8 | temp
[0x1a3];
546 cart_head
.rom_end
= temp
[0x1a4]<<24 | temp
[0x1a5]<<16 | temp
[0x1a6]<<8 | temp
[0x1a7];
547 cart_head
.ram_start
= temp
[0x1a8]<<24 | temp
[0x1a9]<<16 | temp
[0x1aa]<<8 | temp
[0x1ab];
548 cart_head
.ram_end
= temp
[0x1ac]<<24 | temp
[0x1ad]<<16 | temp
[0x1ae]<<8 | temp
[0x1af];
549 cart_head
.save_magic
= temp
[0x1b0]<<8 | temp
[0x1b1];
550 cart_head
.save_flags
= temp
[0x1b2]<<8 | temp
[0x1b3];
551 cart_head
.save_start
= temp
[0x1b4]<<24 | temp
[0x1b5]<<16 | temp
[0x1b6]<<8 | temp
[0x1b7];
552 cart_head
.save_end
= temp
[0x1b8]<<24 | temp
[0x1b9]<<16 | temp
[0x1ba]<<8 | temp
[0x1bb];
553 memcpy((void*)cart_head
.memo
, (void*)(temp
+ 0x1c8), 0x28);
554 memcpy((void*)cart_head
.countries
, (void*)(temp
+ 0x1f0), 0x10);
555 // Plug it into the memory map
556 plug_in(temp
,len
); // md then deallocates it when it's done
561 int md::change_cpu_emu(int to
)
563 // Note - stars/mz80 isn't run here, so star_mz80_on() not necessary
564 #ifdef COMPILE_WITH_STAR
565 #ifdef COMPILE_WITH_MUSA
566 if (cpu_emu
==0 && to
==1)
569 for (i
=0;i
<8;i
++) m68k_poke_dr(i
,cpu
.dreg
[i
]);
570 for (i
=0;i
<8;i
++) m68k_poke_ar(i
,cpu
.areg
[i
]);
571 m68k_poke_pc(cpu
.pc
);
572 m68k_poke_sr(cpu
.sr
);
574 if (cpu_emu
==1 && to
==0)
577 for (i
=0;i
<8;i
++) cpu
.dreg
[i
]=m68k_peek_dr(i
);
578 for (i
=0;i
<8;i
++) cpu
.areg
[i
]=m68k_peek_ar(i
);
579 cpu
.pc
=m68k_peek_pc();
580 cpu
.sr
=m68k_peek_sr();
592 hand
=fopen("dgz80ram","wb");
594 { fwrite(z80ram
,1,0x10000,hand
); fclose(hand
); }