Import Debian changes 1.23-12
[debian-dgen.git] / md.cpp
blob13b60c55cb7e963255aa3411639cf4c8afb189f5
1 // DGen/SDL v1.17+
2 // Megadrive C++ module
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include "md.h"
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++)
14 static md* which=0;
16 int md::star_mz80_on()
18 #ifdef COMPILE_WITH_STAR
19 s68000SetContext(&cpu);
20 #endif
21 mz80SetContext(&z80);
22 which=this;
23 return 0;
25 int md::star_mz80_off()
27 which=0;
28 #ifdef COMPILE_WITH_STAR
29 s68000GetContext(&cpu);
30 #endif
31 mz80GetContext(&z80);
32 return 0;
35 extern "C"
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
61 extern "C"
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); }
89 #endif
91 // The same thing for 68KEM
92 #ifdef COMPILE_WITH_M68KEM
93 extern "C" {
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
106 OP_ROM = which->rom;
107 if (pc >= 0xe00000) // RAM
108 OP_ROM = which->ram - (pc & 0xff0000);
111 #endif
113 UINT8 root_z80_read(UINT32 a,struct MemoryReadByte *huh)
115 (void)(huh);
116 if (which) return which->z80_read(a); return 0x00;
118 void root_z80_write(UINT32 a,UINT8 d,struct MemoryWriteByte *huh)
120 (void)(huh);
121 if (which) which->z80_write(a,d);
123 UINT16 root_z80_port_read(UINT16 a, struct z80PortRead *huh)
125 (void)(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)
130 (void)(huh);
131 if (which) which->z80_port_write(a,d);
135 extern FILE *debug_log;
137 extern "C"
139 int mega_dacout=0,mega_dacen=0;
142 #ifdef COMPILE_WITH_STAR
143 int md::memory_map()
145 int i=0,j=0;
146 int rommax=romlen;
148 if (rommax>0xa00000) rommax=0xa00000;
149 if (rommax<0) rommax=0;
151 // FETCH: Set up 2 or 3 FETCH sections
152 i=0;
153 if (rommax>0)
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++;
156 // Testing
157 fetch[i].lowaddr=0xffff0000; fetch[i].highaddr=0xffffffff; fetch[i].offset=(unsigned)ram-0xffff0000; i++;
158 // Testing 2
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++;
162 if (debug_log!=NULL)
163 fprintf (debug_log,"StarScream memory_map has %d fetch sections\n",i);
165 i=0; j=0;
167 #if 0
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;
181 i++; j++;
182 // Simple version end ***************
184 #else
185 // Faster version ***************
186 // IO: Set up 3/4 read sections, and 2/3 write sections
187 if (rommax>0)
189 // Cartridge save RAM memory
190 if(save_len) {
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;
201 i++; j++;
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;
208 i++;
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;
213 else
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;
227 i++; j++;
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;
238 i++; j++;
239 // Faster version end ***************
240 #endif
242 // The 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;
252 i++; j++;
254 if (debug_log!=NULL)
255 fprintf (debug_log,"StarScream memory_map has %d read sections and %d write sections\n",i,j);
257 return 0;
259 #endif
261 int md::reset()
263 star_mz80_on();
264 #ifdef COMPILE_WITH_STAR
265 if (cpu_emu==0) s68000reset();
266 #endif
267 #ifdef COMPILE_WITH_MUSA
268 if (cpu_emu==1) m68k_pulse_reset(NULL);
269 #endif
270 #ifdef COMPILE_WITH_M68KEM
271 if (cpu_emu==2) m68000_reset(NULL);
272 #endif
273 if (debug_log) fprintf (debug_log,"reset()\n");
274 mz80reset();
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
281 =coo4=coo5=pause=0;
282 pad[0]=pad[1]=0xf303f; // Untouched pad
284 // Reset FM registers
286 int s, r;
287 for(s=0;s<2;s++)
288 for(r=0;r<0x100;r++)
289 fm_reg[s][r]=0;
291 fm_sel[0] = fm_sel[1] = fm_tover[0] = fm_tover[1] = 0;
292 dac_init();
294 odo=odo_line_start=odo_line_end=ras=0;
295 //odo_frame_max=0;
296 hint_countdown=0;
297 z80_int_pending=0;
299 star_mz80_off();
300 return 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}
322 int md::z80_init()
324 // Set up the z80
325 star_mz80_on();
326 mz80reset();
327 // Modify the default context
328 mz80GetContext(&z80);
330 // point mz80 stuff
331 z80.z80Base=z80ram;
332 z80.z80MemRead=mem_read;
333 z80.z80MemWrite=mem_write;
334 z80.z80IoRead=io_read;
335 z80.z80IoWrite=io_write;
337 mz80SetContext(&z80);
338 mz80reset();
339 star_mz80_off();
340 return 0;
344 md::md()
346 romlen=0;
347 mem=rom=ram=z80ram=saveram=NULL;
348 save_start=save_len=save_prot=save_active=0;
350 pal = frame = 0;
351 fm_sel[0]=fm_sel[1]=fm_tover[0]=fm_tover[1]=0;
352 snd_mute=0;
353 memset(&fm_reg,0,sizeof(fm_reg));
354 memset(&ras_fm_ticker,0,sizeof(ras_fm_ticker));
356 #ifdef COMPILE_WITH_STAR
357 fetch=NULL;
358 readbyte=readword=writebyte=writeword=NULL;
359 memset(&cpu,0,sizeof(cpu));
360 #endif
362 memset(&z80,0,sizeof(z80));
363 romfilename[0]=0;
364 country_ver=0xff0; layer_sel = 0xff;
366 memset(romfilename,0,sizeof(romfilename));
368 ok=0;
369 if (!vdp.okay()) return;
370 vdp.belongs=this;
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);
378 ram= mem+0x00000;
379 z80ram=mem+0x10000;
381 romlen=0;
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; }
387 #endif
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;
400 memory_map();
402 // point star stuff
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
409 #else
410 #ifdef COMPILE_WITH_MUSA
411 cpu_emu=1; // zero=starscream, one=musash, two=68kemi
412 #endif
413 #ifdef COMPILE_WITH_M68KEM
414 cpu_emu=2; // zero=starscream, one=musash, two=68kemi
415 #endif
416 #endif
418 #ifdef COMPILE_WITH_MUSA
419 m68k_pulse_reset(NULL);
420 #endif
422 #ifdef COMPILE_WITH_M68KEM
423 m68000_reset(NULL);
424 #endif
426 z80_init();
428 reset(); // reset megadrive
430 ok=1;
434 md::~md()
436 romfilename[0]=0;
437 if (rom!=NULL) unplug();
439 free(mem);
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;
448 #endif
450 ok=0;
453 // Byteswaps memory
454 int byteswap_memory(unsigned char *start,int len)
455 { int i; unsigned char tmp;
456 for (i=0;i<len;i+=2)
457 { tmp=start[i+0]; start[i+0]=start[i+1]; start[i+1]=tmp; }
458 return 0;
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
468 romlen=len;
469 rom=cart;
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)
490 save_active = 1;
492 else {
493 save_start = save_len = 0;
494 saveram = NULL;
497 else
499 save_start = save_len = 0;
500 saveram = NULL;
502 #ifdef COMPILE_WITH_STAR
503 memory_map(); // Update memory map to include this cartridge
504 #endif
505 reset(); // Reset megadrive
506 return 0;
509 int md::unplug()
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
515 #endif
516 memset(romfilename,0,sizeof(romfilename));
517 reset();
519 return 0;
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);
535 // Register name
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
558 return 0;
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)
568 int i;
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)
576 int i;
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();
582 #endif
583 #endif
585 cpu_emu=to;
586 return 0;
589 int md::z80dump()
591 FILE *hand;
592 hand=fopen("dgz80ram","wb");
593 if (hand!=NULL)
594 { fwrite(z80ram,1,0x10000,hand); fclose(hand); }
595 return 0;