From: notaz Date: Tue, 19 Dec 2006 20:53:21 +0000 (+0000) Subject: initial import X-Git-Tag: v1.85~777 X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cc68a136aa179a5f32fe40208371eb9c2b0aadae;p=picodrive.git initial import git-svn-id: file:///home/notaz/opt/svn/PicoDrive@2 be3aeb3a-fb24-0410-a615-afba39da0efa --- diff --git a/Pico/Area.c b/Pico/Area.c new file mode 100644 index 00000000..1faea1fc --- /dev/null +++ b/Pico/Area.c @@ -0,0 +1,189 @@ +// This is part of Pico Library + +// (c) Copyright 2004 Dave, All rights reserved. +// (c) Copyright 2006 notaz, All rights reserved. +// Free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + + +#include "PicoInt.h" + +// ym2612 +#include "sound/ym2612.h" + +// sn76496 +extern int *sn76496_regs; + + +struct PicoArea { void *data; int len; char *name; }; + +// strange observation on Symbian OS 9.1, m600 organizer fw r3a06: +// taking an address of fread or fwrite causes "application could't be started" error +// on startup randomly depending on binary layout of executable file. + +arearw *areaRead = (arearw *) 0; // fread; // read and write function pointers for +arearw *areaWrite = (arearw *) 0; // fwrite; // gzip save state ability + + +// Scan one variable and callback +static int ScanVar(void *data,int len,char *name,void *PmovFile,int PmovAction) +{ + int ret = 0; + if ((PmovAction&3)==1) ret = areaWrite(data,1,len,PmovFile); + if ((PmovAction&3)==2) ret = areaRead (data,1,len,PmovFile); + return (ret != len); +} + +#define SCAN_VAR(x,y) ScanVar(&x,sizeof(x),y,PmovFile,PmovAction); +#define SCANP(x) ScanVar(&Pico.x,sizeof(Pico.x),#x,PmovFile,PmovAction); + +// Pack the cpu into a common format: +static int PackCpu(unsigned char *cpu) +{ + unsigned int pc=0; + +#ifdef EMU_A68K + memcpy(cpu,M68000_regs.d,0x40); + pc=M68000_regs.pc; + *(unsigned char *)(cpu+0x44)=(unsigned char)M68000_regs.ccr; + *(unsigned char *)(cpu+0x45)=(unsigned char)M68000_regs.srh; + *(unsigned int *)(cpu+0x48)=M68000_regs.isp; +#endif + +#ifdef EMU_C68K + memcpy(cpu,PicoCpu.d,0x40); + pc=PicoCpu.pc-PicoCpu.membase; + *(unsigned int *)(cpu+0x44)=CycloneGetSr(&PicoCpu); + *(unsigned int *)(cpu+0x48)=PicoCpu.osp; +#endif + +#ifdef EMU_M68K + memcpy(cpu,m68ki_cpu.dar,0x40); + pc=m68ki_cpu.pc; + *(unsigned int *)(cpu+0x44)=m68k_get_reg(NULL, M68K_REG_SR); + *(unsigned int *)(cpu+0x48)=m68ki_cpu.sp[0]; +#endif + + *(unsigned int *)(cpu+0x40)=pc; + return 0; +} + +static int UnpackCpu(unsigned char *cpu) +{ + unsigned int pc=0; + + pc=*(unsigned int *)(cpu+0x40); + +#ifdef EMU_A68K + memcpy(M68000_regs.d,cpu,0x40); + M68000_regs.pc=pc; + M68000_regs.ccr=*(unsigned char *)(cpu+0x44); + M68000_regs.srh=*(unsigned char *)(cpu+0x45); + M68000_regs.isp=*(unsigned int *)(cpu+0x48); +#endif + +#ifdef EMU_C68K + CycloneSetSr(&PicoCpu, *(unsigned int *)(cpu+0x44)); + PicoCpu.osp=*(unsigned int *)(cpu+0x48); + memcpy(PicoCpu.d,cpu,0x40); + PicoCpu.membase=0; + PicoCpu.pc =PicoCpu.checkpc(pc); // Base pc +#endif + +#ifdef EMU_M68K + memcpy(m68ki_cpu.dar,cpu,0x40); + m68ki_cpu.pc=pc; + m68k_set_reg(M68K_REG_SR, *(unsigned int *)(cpu+0x44)); + m68ki_cpu.sp[0]=*(unsigned int *)(cpu+0x48); +#endif + return 0; +} + +// Scan the contents of the virtual machine's memory for saving or loading +static int PicoAreaScan(int PmovAction,unsigned int ver, void *PmovFile) +{ + void *ym2612_regs; + unsigned char cpu[0x60]; + unsigned char cpu_z80[0x60]; + int ret; + + memset(&cpu,0,sizeof(cpu)); + memset(&cpu_z80,0,sizeof(cpu_z80)); + + ym2612_regs = YM2612GetRegs(); + + if (PmovAction&4) + { + Pico.m.scanline=0; + + // Scan all the memory areas: + SCANP(ram) SCANP(vram) SCANP(zram) SCANP(cram) SCANP(vsram) + + // Pack, scan and unpack the cpu data: + if((PmovAction&3)==1) PackCpu(cpu); + //SekInit(); // notaz: do we really have to do this here? + //PicoMemInit(); + SCAN_VAR(cpu,"cpu") + if((PmovAction&3)==2) UnpackCpu(cpu); + + SCAN_VAR(Pico.m ,"misc") + SCAN_VAR(Pico.video,"video") + + + if(ver == 0x0030) { // zram was being saved incorrectly in 0x0030 (byteswaped?) + Byteswap(Pico.zram, 0x2000); + return 0; // do not try to load sound stuff + } + + //SCAN_VAR(Pico.s ,"sound") + // notaz: save/load z80, YM2612, sn76496 states instead of Pico.s (which is unused anyway) + if(PicoOpt&7) { + if((PmovAction&3)==1) z80_pack(cpu_z80); + ret = SCAN_VAR(cpu_z80,"cpu_z80") + // do not unpack if we fail to load z80 state + if((PmovAction&3)==2) { + if(ret) z80_reset(); + else z80_unpack(cpu_z80); + } + } + if(PicoOpt&3) + ScanVar(sn76496_regs,28*4,"SN76496state", PmovFile, PmovAction); // regs and other stuff + if(PicoOpt&1) { + ScanVar(ym2612_regs, 0x200+4, "YM2612state", PmovFile, PmovAction); // regs + addr line + if((PmovAction&3)==2) YM2612PicoStateLoad(); // reload YM2612 state from it's regs + } + } + + return 0; +} + +// --------------------------------------------------------------------------- +// Helper code to save/load to a file handle + +// Save or load the state from PmovFile: +int PmovState(int PmovAction, void *PmovFile) +{ + int minimum=0; + unsigned char head[32]; + + memset(head,0,sizeof(head)); + + // Find out minimal compatible version: + //PicoAreaScan(PmovAction&0xc,&minimum); + minimum = 0x0021; + + memcpy(head,"Pico",4); + *(unsigned int *)(head+0x8)=PicoVer; + *(unsigned int *)(head+0xc)=minimum; + + // Scan header: + if (PmovAction&1) areaWrite(head,1,sizeof(head),PmovFile); + if (PmovAction&2) areaRead (head,1,sizeof(head),PmovFile); + + // Scan memory areas: + PicoAreaScan(PmovAction, *(unsigned int *)(head+0x8), PmovFile); + + return 0; +} + diff --git a/Pico/Cart.c b/Pico/Cart.c new file mode 100644 index 00000000..18461a2c --- /dev/null +++ b/Pico/Cart.c @@ -0,0 +1,197 @@ +// This is part of Pico Library + +// (c) Copyright 2004 Dave, All rights reserved. +// (c) Copyright 2006 notaz, All rights reserved. +// Free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + + +#include "PicoInt.h" + +void Byteswap(unsigned char *data,int len) +{ + int i=0; + + if (len<2) return; // Too short + + do + { + unsigned short *pd=(unsigned short *)(data+i); + int value=*pd; // Get 2 bytes + + value=(value<<8)|(value>>8); // Byteswap it + *pd=(unsigned short)value; // Put 2b ytes + i+=2; + } + while (i+2<=len); +} + +// Interleve a 16k block and byteswap +static int InterleveBlock(unsigned char *dest,unsigned char *src) +{ + int i=0; + for (i=0;i<0x2000;i++) dest[(i<<1) ]=src[ i]; // Odd + for (i=0;i<0x2000;i++) dest[(i<<1)+1]=src[0x2000+i]; // Even + return 0; +} + +// Decode a SMD file +static int DecodeSmd(unsigned char *data,int len) +{ + unsigned char *temp=NULL; + int i=0; + + temp=(unsigned char *)malloc(0x4000); + if (temp==NULL) return 1; + memset(temp,0,0x4000); + + // Interleve each 16k block and shift down by 0x200: + for (i=0; i+0x4200<=len; i+=0x4000) + { + InterleveBlock(temp,data+0x200+i); // Interleve 16k to temporary buffer + memcpy(data+i,temp,0x4000); // Copy back in + } + + free(temp); + return 0; +} + +static unsigned char *PicoCartAlloc(int filesize) +{ + int alloc_size; + unsigned char *rom; + + if (PicoMCD & 1) { + dprintf("sizeof(mcd_state): %i", sizeof(mcd_state)); + if (filesize > 0x20000) return NULL; // invalid BIOS + rom=(unsigned char *)malloc(sizeof(mcd_state)); + if (rom) memset(rom, 0, sizeof(mcd_state)); + return rom; + } + + alloc_size=filesize+0x7ffff; + if((filesize&0x3fff)==0x200) alloc_size-=0x200; + alloc_size&=~0x7ffff; // use alloc size of multiples of 512K, so that memhandlers could be set up more efficiently + if((filesize&0x3fff)==0x200) alloc_size+=0x200; + else if(alloc_size-filesize < 4) alloc_size+=4; // padding for out-of-bound exec protection + //dprintf("alloc_size: %x\n", alloc_size); + + // Allocate space for the rom plus padding + rom=(unsigned char *)malloc(alloc_size); + if(rom) memset(rom+alloc_size-0x80000,0,0x80000); + return rom; +} + +int PicoCartLoad(FILE *f,unsigned char **prom,unsigned int *psize) +{ + unsigned char *rom=NULL; int size; + if (f==NULL) return 1; + + fseek(f,0,SEEK_END); size=ftell(f); fseek(f,0,SEEK_SET); + if (size <= 0) return 1; + if (PicoMCD & 1) { + if (size > 0x20000) return 1; // invalid BIOS + size = 0xe0000; + } else { + size=(size+3)&~3; // Round up to a multiple of 4 + } + + // Allocate space for the rom plus padding + rom=PicoCartAlloc(size); + if (rom==NULL) return 1; // { fclose(f); return 1; } + + fread(rom,1,size,f); // Load up the rom + // fclose(f); // this is confusing. From now on, caller should close it, because it opened this. + + // Check for SMD: + if ((size&0x3fff)==0x200) { DecodeSmd(rom,size); size-=0x200; } // Decode and byteswap SMD + else Byteswap(rom,size); // Just byteswap + + if (prom) *prom=rom; + if (psize) *psize=size; + + return 0; +} + +// Insert/remove a cartridge: +int PicoCartInsert(unsigned char *rom,unsigned int romsize) +{ + // notaz: add a 68k "jump one op back" opcode to the end of ROM. + // This will hang the emu, but will prevent nasty crashes. + // note: 4 bytes are padded to every ROM + if(rom != NULL) + *(unsigned long *)(rom+romsize) = 0xFFFE4EFA; // 4EFA FFFE byteswapped + + SRam.resize=1; + Pico.rom=rom; + Pico.romsize=romsize; + + return PicoReset(1); +} + +int PicoUnloadCart(unsigned char* romdata) +{ + free(romdata); + return 0; +} + + +#ifdef _UNZIP_SUPPORT + +// notaz +#include "../unzip/unzip.h" + +// nearly same as PicoCartLoad, but works with zipfiles +int CartLoadZip(const char *fname, unsigned char **prom, unsigned int *psize) +{ + unsigned char *rom=0; + struct zipent* zipentry; + int size; + ZIP *zipfile = openzip(fname); + + if(!zipfile) return 1; + + // find first bin or smd + while((zipentry = readzip(zipfile)) != 0) + { + char *ext; + if(strlen(zipentry->name) < 5) continue; + ext = zipentry->name+strlen(zipentry->name)-4; + + if(!strcasecmp(ext, ".bin") || !strcasecmp(ext, ".smd") || !strcasecmp(ext, ".gen")) break; + } + + if(!zipentry) { + closezip(zipfile); + return 4; // no roms + } + + size = zipentry->uncompressed_size; + + size=(size+3)&~3; // Round up to a multiple of 4 + + // Allocate space for the rom plus padding + rom=PicoCartAlloc(size); + if (rom==NULL) { closezip(zipfile); return 2; } + + if(readuncompresszip(zipfile, zipentry, (char *)rom) != 0) { + free(rom); + rom = 0; + closezip(zipfile); + return 5; // unzip failed + } + + closezip(zipfile); + + // Check for SMD: + if ((size&0x3fff)==0x200) { DecodeSmd(rom,size); size-=0x200; } // Decode and byteswap SMD + else Byteswap(rom,size); // Just byteswap + + if (prom) *prom=rom; + if (psize) *psize=size; + + return 0; +} + +#endif diff --git a/Pico/Draw.c b/Pico/Draw.c new file mode 100644 index 00000000..2eed289f --- /dev/null +++ b/Pico/Draw.c @@ -0,0 +1,1291 @@ +// This is part of Pico Library + +// (c) Copyright 2004 Dave, All rights reserved. +// (c) Copyright 2006 notaz, All rights reserved. +// Free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + + +#include "PicoInt.h" +#ifndef __GNUC__ +#pragma warning (disable:4706) // Disable assignment within conditional +#endif + +int (*PicoScan)(unsigned int num, void *data)=NULL; + +unsigned short DefOutBuff[320*2]; +unsigned char HighCol[8+320+8]; +static int HighCacheA[41+1]; // caches for high layers +static int HighCacheB[41+1]; +static int HighCacheS[80+1]; // and sprites +static int HighPreSpr[80*2+1]; // slightly preprocessed sprites +char HighSprZ[320+8+8]; // Z-buffer for accurate sprites and shadow/hilight mode + // (if bit 7 == 0, sh caused by tile; if bit 6 == 0 pixel must be shadowed, else hilighted, if bit5 == 1) +// lsb->msb: moved sprites, all window tiles don't use same priority, accurate sprites (copied from PicoOpt), interlace +// dirty sprites, sonic mode +int rendstatus; +void *DrawLineDest=DefOutBuff; // pointer to dest buffer where to draw this line to +int Scanline=0; // Scanline + +static int SpriteBlocks; +//unsigned short ppt[] = { 0x0f11, 0x0ff1, 0x01f1, 0x011f, 0x01ff, 0x0f1f, 0x0f0e, 0x0e7c }; + +struct TileStrip +{ + int nametab; // Position in VRAM of name table (for this tile line) + int line; // Line number in pixels 0x000-0x3ff within the virtual tilemap + int hscroll; // Horizontal scroll value in pixels for the line + int xmask; // X-Mask (0x1f - 0x7f) for horizontal wraparound in the tilemap + int *hc; // cache for high tile codes and their positions + int cells; // cells (tiles) to draw (32 col mode doesn't need to update whole 320) +}; + +// stuff available in asm: +#ifdef _ASM_DRAW_C +void DrawWindow(int tstart, int tend, int prio, int sh); +void BackFill(int reg7, int sh); +void DrawSprite(int *sprite, int **hc, int sh); +void DrawTilesFromCache(int *hc, int sh); +void DrawSpritesFromCache(int *hc, int sh); +void DrawLayer(int plane, int *hcache, int maxcells, int sh); +void FinalizeLineBGR444(int sh); +void FinalizeLineRGB555(int sh); +void blockcpy_or(void *dst, void *src, size_t n, int pat); +#else +// utility +void blockcpy_or(void *dst, void *src, size_t n, int pat) +{ + unsigned char *pd = dst, *ps = src; + for (; n; n--) + *pd++ = (unsigned char) (*ps++ | pat); +} +#endif + + +static int TileNorm(int sx,int addr,int pal) +{ + unsigned char *pd = HighCol+sx; + unsigned int pack=0; unsigned int t=0; + + pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + if (pack) + { + t=pack&0x0000f000; if (t) pd[0]=(unsigned char)(pal|(t>>12)); + t=pack&0x00000f00; if (t) pd[1]=(unsigned char)(pal|(t>> 8)); + t=pack&0x000000f0; if (t) pd[2]=(unsigned char)(pal|(t>> 4)); + t=pack&0x0000000f; if (t) pd[3]=(unsigned char)(pal|(t )); + t=pack&0xf0000000; if (t) pd[4]=(unsigned char)(pal|(t>>28)); + t=pack&0x0f000000; if (t) pd[5]=(unsigned char)(pal|(t>>24)); + t=pack&0x00f00000; if (t) pd[6]=(unsigned char)(pal|(t>>20)); + t=pack&0x000f0000; if (t) pd[7]=(unsigned char)(pal|(t>>16)); + return 0; + } + + return 1; // Tile blank +} + +static int TileFlip(int sx,int addr,int pal) +{ + unsigned char *pd = HighCol+sx; + unsigned int pack=0; unsigned int t=0; + + pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + if (pack) + { + t=pack&0x000f0000; if (t) pd[0]=(unsigned char)(pal|(t>>16)); + t=pack&0x00f00000; if (t) pd[1]=(unsigned char)(pal|(t>>20)); + t=pack&0x0f000000; if (t) pd[2]=(unsigned char)(pal|(t>>24)); + t=pack&0xf0000000; if (t) pd[3]=(unsigned char)(pal|(t>>28)); + t=pack&0x0000000f; if (t) pd[4]=(unsigned char)(pal|(t )); + t=pack&0x000000f0; if (t) pd[5]=(unsigned char)(pal|(t>> 4)); + t=pack&0x00000f00; if (t) pd[6]=(unsigned char)(pal|(t>> 8)); + t=pack&0x0000f000; if (t) pd[7]=(unsigned char)(pal|(t>>12)); + return 0; + } + return 1; // Tile blank +} + + +// tile renderers for hacky operator sprite support +#define sh_pix(x) \ + if(!t); \ + else if(t==0xe) pd[x]=(unsigned char)((pd[x]&0x3f)|0x80); /* hilight */ \ + else if(t==0xf) pd[x]=(unsigned char)((pd[x]&0x3f)|0xc0); /* shadow */ \ + else pd[x]=(unsigned char)(pal|t) + +#ifndef _ASM_DRAW_C +static int TileNormSH(int sx,int addr,int pal) +{ + unsigned int pack=0; unsigned int t=0; + unsigned char *pd = HighCol+sx; + + pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + if (pack) + { + t=(pack&0x0000f000)>>12; sh_pix(0); + t=(pack&0x00000f00)>> 8; sh_pix(1); + t=(pack&0x000000f0)>> 4; sh_pix(2); + t=(pack&0x0000000f) ; sh_pix(3); + t=(pack&0xf0000000)>>28; sh_pix(4); + t=(pack&0x0f000000)>>24; sh_pix(5); + t=(pack&0x00f00000)>>20; sh_pix(6); + t=(pack&0x000f0000)>>16; sh_pix(7); + return 0; + } + + return 1; // Tile blank +} + +static int TileFlipSH(int sx,int addr,int pal) +{ + unsigned int pack=0; unsigned int t=0; + unsigned char *pd = HighCol+sx; + + pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + if (pack) + { + t=(pack&0x000f0000)>>16; sh_pix(0); + t=(pack&0x00f00000)>>20; sh_pix(1); + t=(pack&0x0f000000)>>24; sh_pix(2); + t=(pack&0xf0000000)>>28; sh_pix(3); + t=(pack&0x0000000f) ; sh_pix(4); + t=(pack&0x000000f0)>> 4; sh_pix(5); + t=(pack&0x00000f00)>> 8; sh_pix(6); + t=(pack&0x0000f000)>>12; sh_pix(7); + return 0; + } + return 1; // Tile blank +} +#endif + +static int TileNormZ(int sx,int addr,int pal,int zval) +{ + unsigned int pack=0; unsigned int t=0; + unsigned char *pd = HighCol+sx; + char *zb = HighSprZ+sx; + int collision = 0, zb_s; + + pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + if (pack) + { + t=pack&0x0000f000; if(t) { zb_s=zb[0]; if(zb_s) collision=1; if(zval>zb_s) { pd[0]=(unsigned char)(pal|(t>>12)); zb[0]=(char)zval; } } + t=pack&0x00000f00; if(t) { zb_s=zb[1]; if(zb_s) collision=1; if(zval>zb_s) { pd[1]=(unsigned char)(pal|(t>> 8)); zb[1]=(char)zval; } } + t=pack&0x000000f0; if(t) { zb_s=zb[2]; if(zb_s) collision=1; if(zval>zb_s) { pd[2]=(unsigned char)(pal|(t>> 4)); zb[2]=(char)zval; } } + t=pack&0x0000000f; if(t) { zb_s=zb[3]; if(zb_s) collision=1; if(zval>zb_s) { pd[3]=(unsigned char)(pal|(t )); zb[3]=(char)zval; } } + t=pack&0xf0000000; if(t) { zb_s=zb[4]; if(zb_s) collision=1; if(zval>zb_s) { pd[4]=(unsigned char)(pal|(t>>28)); zb[4]=(char)zval; } } + t=pack&0x0f000000; if(t) { zb_s=zb[5]; if(zb_s) collision=1; if(zval>zb_s) { pd[5]=(unsigned char)(pal|(t>>24)); zb[5]=(char)zval; } } + t=pack&0x00f00000; if(t) { zb_s=zb[6]; if(zb_s) collision=1; if(zval>zb_s) { pd[6]=(unsigned char)(pal|(t>>20)); zb[6]=(char)zval; } } + t=pack&0x000f0000; if(t) { zb_s=zb[7]; if(zb_s) collision=1; if(zval>zb_s) { pd[7]=(unsigned char)(pal|(t>>16)); zb[7]=(char)zval; } } + if(collision) Pico.video.status|=0x20; + return 0; + } + + return 1; // Tile blank +} + +static int TileFlipZ(int sx,int addr,int pal,int zval) +{ + unsigned int pack=0; unsigned int t=0; + unsigned char *pd = HighCol+sx; + char *zb = HighSprZ+sx; + int collision = 0, zb_s; + + pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + if (pack) + { + t=pack&0x000f0000; if(t) { zb_s=zb[0]&0x1f; if(zb_s) collision=1; if(zval>zb_s) { pd[0]=(unsigned char)(pal|(t>>16)); zb[0]=(char)zval; } } + t=pack&0x00f00000; if(t) { zb_s=zb[1]&0x1f; if(zb_s) collision=1; if(zval>zb_s) { pd[1]=(unsigned char)(pal|(t>>20)); zb[1]=(char)zval; } } + t=pack&0x0f000000; if(t) { zb_s=zb[2]&0x1f; if(zb_s) collision=1; if(zval>zb_s) { pd[2]=(unsigned char)(pal|(t>>24)); zb[2]=(char)zval; } } + t=pack&0xf0000000; if(t) { zb_s=zb[3]&0x1f; if(zb_s) collision=1; if(zval>zb_s) { pd[3]=(unsigned char)(pal|(t>>28)); zb[3]=(char)zval; } } + t=pack&0x0000000f; if(t) { zb_s=zb[4]&0x1f; if(zb_s) collision=1; if(zval>zb_s) { pd[4]=(unsigned char)(pal|(t )); zb[4]=(char)zval; } } + t=pack&0x000000f0; if(t) { zb_s=zb[5]&0x1f; if(zb_s) collision=1; if(zval>zb_s) { pd[5]=(unsigned char)(pal|(t>> 4)); zb[5]=(char)zval; } } + t=pack&0x00000f00; if(t) { zb_s=zb[6]&0x1f; if(zb_s) collision=1; if(zval>zb_s) { pd[6]=(unsigned char)(pal|(t>> 8)); zb[6]=(char)zval; } } + t=pack&0x0000f000; if(t) { zb_s=zb[7]&0x1f; if(zb_s) collision=1; if(zval>zb_s) { pd[7]=(unsigned char)(pal|(t>>12)); zb[7]=(char)zval; } } + if(collision) Pico.video.status|=0x20; + return 0; + } + return 1; // Tile blank +} + + +#define sh_pixZ(x) \ + if(t) { \ + if(zb[x]) collision=1; \ + if(zval>zb[x]) { \ + if (t==0xe) { pd[x]=(unsigned char)((pd[x]&0x3f)|0x80); /* hilight */ } \ + else if(t==0xf) { pd[x]=(unsigned char)((pd[x]&0x3f)|0xc0); /* shadow */ } \ + else { zb[x]=(char)zval; pd[x]=(unsigned char)(pal|t); } \ + } \ + } + +static int TileNormZSH(int sx,int addr,int pal,int zval) +{ + unsigned int pack=0; unsigned int t=0; + unsigned char *pd = HighCol+sx; + char *zb = HighSprZ+sx; + int collision = 0; + + pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + if (pack) + { + t=(pack&0x0000f000)>>12; sh_pixZ(0); + t=(pack&0x00000f00)>> 8; sh_pixZ(1); + t=(pack&0x000000f0)>> 4; sh_pixZ(2); + t=(pack&0x0000000f) ; sh_pixZ(3); + t=(pack&0xf0000000)>>28; sh_pixZ(4); + t=(pack&0x0f000000)>>24; sh_pixZ(5); + t=(pack&0x00f00000)>>20; sh_pixZ(6); + t=(pack&0x000f0000)>>16; sh_pixZ(7); + if(collision) Pico.video.status|=0x20; + return 0; + } + + return 1; // Tile blank +} + +static int TileFlipZSH(int sx,int addr,int pal,int zval) +{ + unsigned int pack=0; unsigned int t=0; + unsigned char *pd = HighCol+sx; + char *zb = HighSprZ+sx; + int collision = 0; + + pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + if (pack) + { + t=(pack&0x000f0000)>>16; sh_pixZ(0); + t=(pack&0x00f00000)>>20; sh_pixZ(1); + t=(pack&0x0f000000)>>24; sh_pixZ(2); + t=(pack&0xf0000000)>>28; sh_pixZ(3); + t=(pack&0x0000000f) ; sh_pixZ(4); + t=(pack&0x000000f0)>> 4; sh_pixZ(5); + t=(pack&0x00000f00)>> 8; sh_pixZ(6); + t=(pack&0x0000f000)>>12; sh_pixZ(7); + if(collision) Pico.video.status|=0x20; + return 0; + } + return 1; // Tile blank +} + +// -------------------------------------------- + +#ifndef _ASM_DRAW_C +static void DrawStrip(struct TileStrip *ts, int sh) +{ + int tilex=0,dx=0,ty=0,code=0,addr=0,cells; + int oldcode=-1,blank=-1; // The tile we know is blank + int pal=0; + + // Draw tiles across screen: + tilex=(-ts->hscroll)>>3; + ty=(ts->line&7)<<1; // Y-Offset into tile + dx=((ts->hscroll-1)&7)+1; + cells = ts->cells; + if(dx != 8) cells++; // have hscroll, need to draw 1 cell more + + for (; cells; dx+=8,tilex++,cells--) + { + int zero=0; + + code=Pico.vram[ts->nametab+(tilex&ts->xmask)]; + if (code==blank) continue; + if (code>>15) { // high priority tile + int cval = code | (dx<<16) | (ty<<25); + if(code&0x1000) cval^=7<<26; + *ts->hc++ = cval; // cache it + continue; + } + + if (code!=oldcode) { + oldcode = code; + // Get tile address/2: + addr=(code&0x7ff)<<4; + addr+=ty; + if (code&0x1000) addr^=0xe; // Y-flip + +// pal=Pico.cram+((code>>9)&0x30); + pal=((code>>9)&0x30)|(sh<<6); + } + + if (code&0x0800) zero=TileFlip(dx,addr,pal); + else zero=TileNorm(dx,addr,pal); + + if (zero) blank=code; // We know this tile is blank now + } + + // terminate the cache list + *ts->hc = 0; +} +#endif + +// this is messy +#ifndef _ASM_DRAW_C +static +#endif +void DrawStripVSRam(struct TileStrip *ts, int plane) +{ + int tilex=0,dx=0,ty=0,code=0,addr=0,cell=0,nametabadd=0; + int oldcode=-1,blank=-1; // The tile we know is blank + int pal=0,scan=Scanline; + + // Draw tiles across screen: + tilex=(-ts->hscroll)>>3; + dx=((ts->hscroll-1)&7)+1; + if(dx != 8) { + int vscroll, line; + cell--; // have hscroll, start with negative cell + // also calculate intial VS stuff + vscroll=Pico.vsram[plane]; + + // Find the line in the name table + line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask .. + nametabadd=(line>>3)<<(ts->line>>24); // .. and shift[width] + ty=(line&7)<<1; // Y-Offset into tile + } + + for (; cell < ts->cells; dx+=8,tilex++,cell++) + { + int zero=0; + + if((cell&1)==0) { + int line,vscroll; + vscroll=Pico.vsram[plane+(cell&~1)]; + + // Find the line in the name table + line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask .. + nametabadd=(line>>3)<<(ts->line>>24); // .. and shift[width] + ty=(line&7)<<1; // Y-Offset into tile + } + + code=Pico.vram[ts->nametab+nametabadd+(tilex&ts->xmask)]; + if (code==blank) continue; + if (code>>15) { // high priority tile + int cval = code | (dx<<16) | (ty<<25); + if(code&0x1000) cval^=7<<26; + *ts->hc++ = cval; // cache it + continue; + } + + if (code!=oldcode) { + oldcode = code; + // Get tile address/2: + addr=(code&0x7ff)<<4; + if (code&0x1000) addr+=14-ty; else addr+=ty; // Y-flip + +// pal=Pico.cram+((code>>9)&0x30); + pal=((code>>9)&0x30); + } + + if (code&0x0800) zero=TileFlip(dx,addr,pal); + else zero=TileNorm(dx,addr,pal); + + if (zero) blank=code; // We know this tile is blank now + } + + // terminate the cache list + *ts->hc = 0; +} + +#ifndef _ASM_DRAW_C +static +#endif +void DrawStripInterlace(struct TileStrip *ts) +{ + int tilex=0,dx=0,ty=0,code=0,addr=0,cells; + int oldcode=-1,blank=-1; // The tile we know is blank + int pal=0; + + // Draw tiles across screen: + tilex=(-ts->hscroll)>>3; + ty=(ts->line&15)<<1; // Y-Offset into tile + dx=((ts->hscroll-1)&7)+1; + cells = ts->cells; + if(dx != 8) cells++; // have hscroll, need to draw 1 cell more + + for (; cells; dx+=8,tilex++,cells--) + { + int zero=0; + + code=Pico.vram[ts->nametab+(tilex&ts->xmask)]; + if (code==blank) continue; + if (code>>15) { // high priority tile + int cval = (code&0xfc00) | (dx<<16) | (ty<<25); + cval|=(code&0x3ff)<<1; + if(code&0x1000) cval^=0xf<<26; + *ts->hc++ = cval; // cache it + continue; + } + + if (code!=oldcode) { + oldcode = code; + // Get tile address/2: + addr=(code&0x7ff)<<5; + if (code&0x1000) addr+=30-ty; else addr+=ty; // Y-flip + +// pal=Pico.cram+((code>>9)&0x30); + pal=((code>>9)&0x30); + } + + if (code&0x0800) zero=TileFlip(dx,addr,pal); + else zero=TileNorm(dx,addr,pal); + + if (zero) blank=code; // We know this tile is blank now + } + + // terminate the cache list + *ts->hc = 0; +} + +// -------------------------------------------- + +#ifndef _ASM_DRAW_C +static void DrawLayer(int plane, int *hcache, int maxcells, int sh) +{ + struct PicoVideo *pvid=&Pico.video; + const char shift[4]={5,6,5,7}; // 32,64 or 128 sized tilemaps (2 is invalid) + struct TileStrip ts; + int width, height, ymask; + int vscroll, htab; + + ts.hc=hcache; + ts.cells=maxcells; + + // Work out the TileStrip to draw + + // Work out the name table size: 32 64 or 128 tiles (0-3) + width=pvid->reg[16]; + height=(width>>4)&3; width&=3; + + ts.xmask=(1<1) ymask =0x0ff; + + // Find name table: + if (plane==0) ts.nametab=(pvid->reg[2]&0x38)<< 9; // A + else ts.nametab=(pvid->reg[4]&0x07)<<12; // B + + htab=pvid->reg[13]<<9; // Horizontal scroll table address + if ( pvid->reg[11]&2) htab+=Scanline<<1; // Offset by line + if ((pvid->reg[11]&1)==0) htab&=~0xf; // Offset by tile + htab+=plane; // A or B + + // Get horizontal scroll value, will be masked later + ts.hscroll=Pico.vram[htab&0x7fff]; + + if((pvid->reg[12]&6) == 6) { + // interlace mode 2 + vscroll=Pico.vsram[plane]; // Get vertical scroll value + + // Find the line in the name table + ts.line=(vscroll+(Scanline<<1))&((ymask<<1)|1); + ts.nametab+=(ts.line>>4)<reg[11]&4) { + // shit, we have 2-cell column based vscroll + // luckily this doesn't happen too often + ts.line=ymask|(shift[width]<<24); // save some stuff instead of line + DrawStripVSRam(&ts, plane); + } else { + vscroll=Pico.vsram[plane]; // Get vertical scroll value + + // Find the line in the name table + ts.line=(vscroll+Scanline)&ymask; + ts.nametab+=(ts.line>>3)<reg[12]&1) + { + nametab=(pvid->reg[3]&0x3c)<<9; // 40-cell mode + nametab+=(Scanline>>3)<<6; + } + else + { + nametab=(pvid->reg[3]&0x3e)<<9; // 32-cell mode + nametab+=(Scanline>>3)<<5; + } + + tilex=tstart<<1; + tend<<=1; + + ty=(Scanline&7)<<1; // Y-Offset into tile + + if(!(rendstatus&2)) { + // check the first tile code + code=Pico.vram[nametab+tilex]; + // if the whole window uses same priority (what is often the case), we may be able to skip this field + if((code>>15) != prio) return; + } + + // Draw tiles across screen: + for (; tilex < tend; tilex++) + { + int addr=0,zero=0; + int pal; + + code=Pico.vram[nametab+tilex]; + if(code==blank) continue; + if((code>>15) != prio) { + rendstatus|=2; + continue; + } + + pal=((code>>9)&0x30); + + if(sh) { + int tmp, *zb = (int *)(HighCol+8+(tilex<<3)); + if(prio) { + tmp = *zb; + if(!(tmp&0x00000080)) tmp&=~0x000000c0; if(!(tmp&0x00008000)) tmp&=~0x0000c000; + if(!(tmp&0x00800000)) tmp&=~0x00c00000; if(!(tmp&0x80000000)) tmp&=~0xc0000000; + *zb++=tmp; tmp = *zb; + if(!(tmp&0x00000080)) tmp&=~0x000000c0; if(!(tmp&0x00008000)) tmp&=~0x0000c000; + if(!(tmp&0x00800000)) tmp&=~0x00c00000; if(!(tmp&0x80000000)) tmp&=~0xc0000000; + *zb++=tmp; + } else { + pal |= 0x40; + } + } + + // Get tile address/2: + addr=(code&0x7ff)<<4; + if (code&0x1000) addr+=14-ty; else addr+=ty; // Y-flip + + if (code&0x0800) zero=TileFlip(8+(tilex<<3),addr,pal); + else zero=TileNorm(8+(tilex<<3),addr,pal); + + if (zero) blank=code; // We know this tile is blank now + } + + // terminate the cache list + //*hcache = 0; +} + +// -------------------------------------------- + +static void DrawTilesFromCache(int *hc, int sh) +{ + int code, addr, zero, dx; + int pal; + short blank=-1; // The tile we know is blank + + // *ts->hc++ = code | (dx<<16) | (ty<<25); // cache it + + while((code=*hc++)) { + if(!sh && (short)code == blank) continue; + + // Get tile address/2: + addr=(code&0x7ff)<<4; + addr+=(unsigned int)code>>25; // y offset into tile + dx=(code>>16)&0x1ff; + if(sh) { + unsigned char *zb = HighCol+dx; + if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++; + if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++; + if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++; + if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++; + } + + pal=((code>>9)&0x30); + + if (code&0x0800) zero=TileFlip(dx,addr,pal); + else zero=TileNorm(dx,addr,pal); + + if(zero) blank=(short)code; + } +} + +// -------------------------------------------- + +// Index + 0 : hhhhvvvv ab--hhvv yyyyyyyy yyyyyyyy // a: offscreen h, b: offs. v, h: horiz. size +// Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8 + +static void DrawSprite(int *sprite, int **hc, int sh) +{ + int width=0,height=0; + int row=0,code=0; + int pal; + int tile=0,delta=0; + int sx, sy; + int (*fTileFunc)(int sx,int addr,int pal); + + // parse the sprite data + sy=sprite[0]; + code=sprite[1]; + sx=code>>16; // X + width=sy>>28; + height=(sy>>24)&7; // Width and height in tiles + sy=(sy<<16)>>16; // Y + + row=Scanline-sy; // Row of the sprite we are on + + if (code&0x1000) row=(height<<3)-1-row; // Flip Y + + tile=code&0x7ff; // Tile number + tile+=row>>3; // Tile number increases going down + delta=height; // Delta to increase tile by going right + if (code&0x0800) { tile+=delta*(width-1); delta=-delta; } // Flip X + + tile<<=4; tile+=(row&7)<<1; // Tile address + + if(code&0x8000) { // high priority - cache it + *(*hc)++ = (tile<<16)|((code&0x0800)<<5)|((sx<<6)&0x0000ffc0)|((code>>9)&0x30)|((sprite[0]>>16)&0xf); + } else { + delta<<=4; // Delta of address + pal=((code>>9)&0x30)|(sh<<6); + + if(sh && (code&0x6000) == 0x6000) { + if(code&0x0800) fTileFunc=TileFlipSH; + else fTileFunc=TileNormSH; + } else { + if(code&0x0800) fTileFunc=TileFlip; + else fTileFunc=TileNorm; + } + + for (; width; width--,sx+=8,tile+=delta) + { + if(sx<=0) continue; + if(sx>=328) break; // Offscreen + + tile&=0x7fff; // Clip tile address + fTileFunc(sx,tile,pal); + } + } +} +#endif + + +// Index + 0 : hhhhvvvv s---hhvv yyyyyyyy yyyyyyyy // s: skip flag, h: horiz. size +// Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8 + +static void DrawSpriteZ(int pack, int pack2, int shpri, int sprio) +{ + int width=0,height=0; + int row=0; + int pal; + int tile=0,delta=0; + int sx, sy; + int (*fTileFunc)(int sx,int addr,int pal,int zval); + + // parse the sprite data + sx=pack2>>16; // X + sy=(pack <<16)>>16; // Y + width=pack>>28; + height=(pack>>24)&7; // Width and height in tiles + + row=Scanline-sy; // Row of the sprite we are on + + if (pack2&0x1000) row=(height<<3)-1-row; // Flip Y + + tile=pack2&0x7ff; // Tile number + tile+=row>>3; // Tile number increases going down + delta=height; // Delta to increase tile by going right + if (pack2&0x0800) { tile+=delta*(width-1); delta=-delta; } // Flip X + + tile<<=4; tile+=(row&7)<<1; // Tile address + delta<<=4; // Delta of address + pal=((pack2>>9)&0x30); + if((shpri&1)&&!(shpri&2)) pal|=0x40; + + shpri&=1; + if((pack2&0x6000) != 0x6000) shpri = 0; + shpri |= (pack2&0x0800)>>10; + switch(shpri) { + default: + case 0: fTileFunc=TileNormZ; break; + case 1: fTileFunc=TileNormZSH; break; + case 2: fTileFunc=TileFlipZ; break; + case 3: fTileFunc=TileFlipZSH; break; + } + + for (; width; width--,sx+=8,tile+=delta) + { + if(sx<=0) continue; + if(sx>=328) break; // Offscreen + + tile&=0x7fff; // Clip tile address + fTileFunc(sx,tile,pal,sprio); + } +} + +static void DrawSpriteInterlace(unsigned int *sprite) +{ + int width=0,height=0; + int row=0,code=0; + int pal; + int tile=0,delta=0; + int sx, sy; + + // parse the sprite data + sy=sprite[0]; + height=sy>>24; + sy=(sy&0x3ff)-0x100; // Y + width=(height>>2)&3; height&=3; + width++; height++; // Width and height in tiles + + row=(Scanline<<1)-sy; // Row of the sprite we are on + + code=sprite[1]; + sx=((code>>16)&0x1ff)-0x78; // X + + if (code&0x1000) row^=(16<>4; // Tile number increases going down + delta=height; // Delta to increase tile by going right + if (code&0x0800) { tile+=delta*(width-1); delta=-delta; } // Flip X + + tile<<=5; tile+=(row&15)<<1; // Tile address + + delta<<=5; // Delta of address + pal=((code>>9)&0x30); // Get palette pointer + + for (; width; width--,sx+=8,tile+=delta) + { + if(sx<=0) continue; + if(sx>=328) break; // Offscreen + + tile&=0x7fff; // Clip tile address + if (code&0x0800) TileFlip(sx,tile,pal); + else TileNorm(sx,tile,pal); + } +} + + +static void DrawAllSpritesInterlace(int pri, int maxwidth) +{ + struct PicoVideo *pvid=&Pico.video; + int i,u,table,link=0,sline=Scanline<<1; + unsigned int *sprites[80]; // Sprite index + + table=pvid->reg[5]&0x7f; + if (pvid->reg[12]&1) table&=0x7e; // Lowest bit 0 in 40-cell mode + table<<=8; // Get sprite table address/2 + + for (i=u=0; u < 80 && i < 21; u++) + { + unsigned int *sprite; + int code, sx, sy, height; + + sprite=(unsigned int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite + + // get sprite info + code = sprite[0]; + sx = sprite[1]; + if(((sx>>15)&1) != pri) goto nextsprite; // wrong priority sprite + + // check if it is on this line + sy = (code&0x3ff)-0x100; + height = (((code>>24)&3)+1)<<4; + if(sline < sy || sline >= sy+height) goto nextsprite; // no + + // check if sprite is not hidden offscreen + sx = (sx>>16)&0x1ff; + sx -= 0x78; // Get X coordinate + 8 + if(sx <= -8*3 || sx >= maxwidth) goto nextsprite; + + // sprite is good, save it's pointer + sprites[i++]=sprite; + + nextsprite: + // Find next sprite + link=(code>>16)&0x7f; + if(!link) break; // End of sprites + } + + // Go through sprites backwards: + for (i-- ;i>=0; i--) + DrawSpriteInterlace(sprites[i]); +} + + +#ifndef _ASM_DRAW_C +static void DrawSpritesFromCache(int *hc, int sh) +{ + int code, tile, sx, delta, width; + int pal; + int (*fTileFunc)(int sx,int addr,int pal); + + // *(*hc)++ = (tile<<16)|((code&0x0800)<<5)|((sx<<6)&0x0000ffc0)|((code>>9)&0x30)|((sprite[0]>>24)&0xf); + + while((code=*hc++)) { + pal=(code&0x30); + delta=code&0xf; + width=delta>>2; delta&=3; + width++; delta++; // Width and height in tiles + if (code&0x10000) delta=-delta; // Flip X + delta<<=4; + tile=((unsigned int)code>>17)<<1; + sx=(code<<16)>>22; // sx can be negative (start offscreen), so sign extend + + if(sh && pal == 0x30) { // + if(code&0x10000) fTileFunc=TileFlipSH; + else fTileFunc=TileNormSH; + } else { + if(code&0x10000) fTileFunc=TileFlip; + else fTileFunc=TileNorm; + } + + for (; width; width--,sx+=8,tile+=delta) + { + if(sx<=0) continue; + if(sx>=328) break; // Offscreen + + tile&=0x7fff; // Clip tile address + fTileFunc(sx,tile,pal); + } + } +} +#endif + + +// Index + 0 : ----hhvv -lllllll -------y yyyyyyyy +// Index + 4 : -------x xxxxxxxx pccvhnnn nnnnnnnn +// v +// Index + 0 : hhhhvvvv ab--hhvv yyyyyyyy yyyyyyyy // a: offscreen h, b: offs. v, h: horiz. size +// Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8 + +static void PrepareSprites(int full) +{ + struct PicoVideo *pvid=&Pico.video; + int u=0,link=0,sblocks=0; + int table=0; + int *pd = HighPreSpr; + + table=pvid->reg[5]&0x7f; + if (pvid->reg[12]&1) table&=0x7e; // Lowest bit 0 in 40-cell mode + table<<=8; // Get sprite table address/2 + + if (!full) + { + int pack; + // updates: tilecode, sx + for (u=0; u < 80 && (pack = *pd); u++, pd+=2) + { + unsigned int *sprite; + int code, code2, sx, sy, skip=0; + + sprite=(unsigned int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite + + // parse sprite info + code = sprite[0]; + code2 = sprite[1]; + code2 &= ~0xfe000000; + code2 -= 0x00780000; // Get X coordinate + 8 in upper 16 bits + sx = code2>>16; + + if((sx <= 8-((pack>>28)<<3) && sx >= -0x76) || sx >= 328) skip=1<<23; + else if ((sy = (pack<<16)>>16) < 240 && sy > -32) { + int sbl = (2<<(pack>>28))-1; + sblocks |= sbl<<(sy>>3); + } + + *pd = (pack&~(1<<23))|skip; + *(pd+1) = code2; + + // Find next sprite + link=(code>>16)&0x7f; + if(!link) break; // End of sprites + } + SpriteBlocks |= sblocks; + } + else + { + for (; u < 80; u++) + { + unsigned int *sprite; + int code, code2, sx, sy, hv, height, width, skip=0, sx_min; + + sprite=(unsigned int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite + + // parse sprite info + code = sprite[0]; + sy = (code&0x1ff)-0x80; + hv = (code>>24)&0xf; + height = (hv&3)+1; + + if(sy > 240 || sy + (height<<3) <= 0) skip|=1<<22; + + width = (hv>>2)+1; + code2 = sprite[1]; + sx = (code2>>16)&0x1ff; + sx -= 0x78; // Get X coordinate + 8 + sx_min = 8-(width<<3); + + if((sx <= sx_min && sx >= -0x76) || sx >= 328) skip|=1<<23; + else if (sx > sx_min && !skip) { + int sbl = (2<>3; + if(shi < 0) shi=0; // negative sy + sblocks |= sbl<>16)&0x7f; + if(!link) break; // End of sprites + } + SpriteBlocks = sblocks; + *pd = 0; // terminate + } +} + +static void DrawAllSprites(int *hcache, int maxwidth, int prio, int sh) +{ + int i,u,n; + int sx1seen=0; // sprite with x coord 1 or 0 seen + int ntiles = 0; // tile counter for sprite limit emulation + int *sprites[40]; // Sprites to draw in fast mode + int *ps, pack, rs = rendstatus, scan=Scanline; + + if(rs&8) { + DrawAllSpritesInterlace(prio, maxwidth); + return; + } + if(rs&0x11) { + //dprintf("PrepareSprites(%i) [%i]", (rs>>4)&1, scan); + PrepareSprites(rs&0x10); + rendstatus=rs&~0x11; + } + if (!(SpriteBlocks & (1<<(scan>>3)))) return; + + if(((rs&4)||sh)&&prio==0) + memset(HighSprZ, 0, 328); + if(!(rs&4)&&prio) { + if(hcache[0]) DrawSpritesFromCache(hcache, sh); + return; + } + + ps = HighPreSpr; + + // Index + 0 : hhhhvvvv ab--hhvv yyyyyyyy yyyyyyyy // a: offscreen h, b: offs. v, h: horiz. size + // Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8 + + for(i=u=n=0; (pack = *ps) && n < 20; ps+=2, u++) + { + int sx, sy, row, pack2; + + if(pack & 0x00400000) continue; + + // get sprite info + pack2 = *(ps+1); + sx = pack2>>16; + sy = (pack <<16)>>16; + row = scan-sy; + + //dprintf("x: %i y: %i %ix%i", sx, sy, (pack>>28)<<3, (pack>>21)&0x38); + + if(sx == -0x77) sx1seen|=1; // for masking mode 2 + + // check if it is on this line + if(row < 0 || row >= ((pack>>21)&0x38)) continue; // no + n++; // number of sprites on this line (both visible and hidden, max is 20) [broken] + + // sprite limit + ntiles += pack>>28; + if(ntiles > 40) break; + + if(pack & 0x00800000) continue; + + // masking sprite? + if(sx == -0x78) { + if(!(sx1seen&1) || sx1seen==3) { + break; // this sprite is not drawn and remaining sprites are masked + } + if((sx1seen>>8) == 0) sx1seen=(i+1)<<8; + continue; + } + else if(sx == -0x77) { + // masking mode2 (Outrun, Galaxy Force II, Shadow of the beast) + if(sx1seen>>8) { i=(sx1seen>>8)-1; break; } // seen both 0 and 1 + sx1seen |= 2; + continue; + } + + // accurate sprites + //dprintf("P:%i",((sx>>15)&1)); + if(rs&4) { + // might need to skip this sprite + if((pack2&0x8000) ^ (prio<<15)) continue; + DrawSpriteZ(pack,pack2,sh|(prio<<1),(char)(0x1f-n)); + continue; + } + + // sprite is good, save it's pointer + sprites[i++]=ps; + } + + // Go through sprites backwards: + if(!(rs&4)) { + for (i--; i>=0; i--) + DrawSprite(sprites[i],&hcache,sh); + + // terminate cache list + *hcache = 0; + } +} + + +// -------------------------------------------- + +#ifndef _ASM_DRAW_C +static void BackFill(int reg7, int sh) +{ + unsigned int back=0; + unsigned int *pd=NULL,*end=NULL; + + // Start with a blank scanline (background colour): + back=reg7&0x3f; + back|=sh<<6; + back|=back<<8; + back|=back<<16; + + pd= (unsigned int *)(HighCol+8); + end=(unsigned int *)(HighCol+8+320); + + do { pd[0]=pd[1]=pd[2]=pd[3]=back; pd+=4; } while (pd= 0; i--) + pal[0x40|i] = pal[0xc0|i] = (unsigned short)((pal[i]>>1)&0x0777); + // hilighted pixels + for(i = 0x3f; i >= 0; i--) { + t=pal[i]&0xeee;t+=0x444;if(t&0x10)t|=0xe;if(t&0x100)t|=0xe0;if(t&0x1000)t|=0xe00;t&=0xeee; + pal[0x80|i]=(unsigned short)t; + } + Pico.m.dirtyPal = 0; + } + } + + for(i = 0; i < len; i++) + pd[i] = pal[ps[i]]; +} + + +static void FinalizeLineRGB555(int sh) +{ + unsigned short *pd=DrawLineDest; + unsigned char *ps=HighCol+8; + unsigned short *pal=HighPal; + int len, i, t, dirtyPal = Pico.m.dirtyPal; + + if(dirtyPal) { + unsigned short *ppal=Pico.cram; + for(i = 0x3f; i >= 0; i--) + pal[i] = (unsigned short) (((ppal[i]&0x00f)<<12)|((ppal[i]&0x0f0)<<3)|((ppal[i]&0xf00)>>7)); + Pico.m.dirtyPal = 0; + } + + if (Pico.video.reg[12]&1) { + len = 320; + } else { + if(!(PicoOpt&0x100)) pd+=32; + len = 256; + } + + if(sh) { + if(dirtyPal) { + // shadowed pixels + for(i = 0x3f; i >= 0; i--) + pal[0x40|i] = pal[0xc0|i] = (unsigned short)((pal[i]>>1)&0x738e); + // hilighted pixels + for(i = 0x3f; i >= 0; i--) { + t=pal[i]&0xe71c;t+=0x4208;if(t&0x20)t|=0x1c;if(t&0x800)t|=0x700;if(t&0x10000)t|=0xe000;t&=0xe71c; + pal[0x80|i]=(unsigned short)t; + } + } + } + + for(i = 0; i < len; i++) + pd[i] = pal[ps[i]]; +} +#endif + +static void FinalizeLine8bit(int sh) +{ + unsigned char *pd=DrawLineDest; + int len, rs = rendstatus; + static int dirty_count; + + if (!sh && Pico.m.dirtyPal == 1 && Scanline < 222) { + // a hack for mid-frame palette changes + if (!(rs & 0x20)) + dirty_count = 1; + else dirty_count++; + rs |= 0x20; + rendstatus = rs; + if (dirty_count == 3) { + blockcpy(HighPal, Pico.cram, 0x40*2); + } else if (dirty_count == 11) { + blockcpy(HighPal+0x40, Pico.cram, 0x40*2); + } + } + + if (Pico.video.reg[12]&1) { + len = 320; + } else { + if(!(PicoOpt&0x100)) pd+=32; + len = 256; + } + + if (!sh && rs & 0x20) { + if (dirty_count >= 11) { + blockcpy_or(pd, HighCol+8, len, 0x80); + } else { + blockcpy_or(pd, HighCol+8, len, 0x40); + } + } else { + blockcpy(pd, HighCol+8, len); + } +} + +void (*FinalizeLine)(int sh) = FinalizeLineBGR444; + +// -------------------------------------------- + +static int DrawDisplay(int sh) +{ + struct PicoVideo *pvid=&Pico.video; + int win=0,edge=0,hvwind=0; + int maxw, maxcells; + + if(pvid->reg[12]&1) { + maxw = 328; maxcells = 40; + } else { + maxw = 264; maxcells = 32; + } + + // Find out if the window is on this line: + win=pvid->reg[0x12]; + edge=(win&0x1f)<<3; + + if (win&0x80) { if (Scanline>=edge) hvwind=1; } + else { if (Scanline< edge) hvwind=1; } + + if(!hvwind) { // we might have a vertical window here + win=pvid->reg[0x11]; + edge=win&0x1f; + if(win&0x80) { + if(!edge) hvwind=1; + else if(edge < (maxcells>>1)) hvwind=2; + } else { + if(!edge); + else if(edge < (maxcells>>1)) hvwind=2; + else hvwind=1; + } + } + + DrawLayer(1, HighCacheB, maxcells, sh); + if(hvwind == 1) + DrawWindow(0, maxcells>>1, 0, sh); // HighCacheAW + else if(hvwind == 2) { + // ahh, we have vertical window + DrawLayer(0, HighCacheA, (win&0x80) ? edge<<1 : maxcells, sh); + DrawWindow((win&0x80) ? edge : 0, (win&0x80) ? maxcells>>1 : edge, 0, sh); // HighCacheW + } else + DrawLayer(0, HighCacheA, maxcells, sh); + DrawAllSprites(HighCacheS, maxw, 0, sh); + + if(HighCacheB[0]) DrawTilesFromCache(HighCacheB, sh); + if(hvwind == 1) + DrawWindow(0, maxcells>>1, 1, sh); + else if(hvwind == 2) { + if(HighCacheA[0]) DrawTilesFromCache(HighCacheA, sh); + DrawWindow((win&0x80) ? edge : 0, (win&0x80) ? maxcells>>1 : edge, 1, sh); + } else + if(HighCacheA[0]) DrawTilesFromCache(HighCacheA, sh); + DrawAllSprites(HighCacheS, maxw, 1, sh); + + return 0; +} + + +static int Skip=0; + +void PicoFrameStart() +{ + // prepare to do this frame + rendstatus = (PicoOpt&0x80)>>5; // accurate sprites + if(rendstatus) + Pico.video.status &= ~0x0020; + else Pico.video.status |= 0x0020; // sprite collision + if((Pico.video.reg[12]&6) == 6) rendstatus |= 8; // interlace mode + if(Pico.m.dirtyPal) Pico.m.dirtyPal = 2; // reset dirty if needed + + PrepareSprites(1); + Skip=0; +} + +int PicoLine(int scan) +{ + int sh; + if (Skip>0) { Skip--; return 0; } // Skip rendering lines + + Scanline=scan; + sh=(Pico.video.reg[0xC]&8)>>3; // shadow/hilight? + + // Draw screen: + BackFill(Pico.video.reg[7], sh); + if (Pico.video.reg[1]&0x40) + DrawDisplay(sh); + + FinalizeLine(sh); + //if (SpriteBlocks & (1<<(scan>>3))) for (sh=0; sh < 30; sh++) DrawLineDest[sh] = 0xf; + + Skip=PicoScan(Scanline,DrawLineDest); + + return 0; +} + + +void PicoDrawSetColorFormat(int which) +{ + if (which == 2) + FinalizeLine = FinalizeLine8bit; + else if (which == 1) + FinalizeLine = FinalizeLineRGB555; + else FinalizeLine = FinalizeLineBGR444; +} diff --git a/Pico/Draw.s b/Pico/Draw.s new file mode 100644 index 00000000..749aac53 --- /dev/null +++ b/Pico/Draw.s @@ -0,0 +1,1429 @@ +@ assembly "optimized" version of some funtions from draw.c +@ this is highly specialized, be careful if changing related C code! + +@ (c) Copyright 2006, notaz +@ All Rights Reserved + + +.extern Pico +.extern PicoOpt +.extern HighCol +.extern Scanline +.extern HighSprZ +.extern rendstatus +.extern DrawLineDest +.extern DrawStripVSRam +.extern DrawStripInterlace + + +@ helper +.macro TilePixel pat lsrr offs +.if !\lsrr + ands r4, \pat, r2 +.else + ands r4, \pat, r2, lsr #\lsrr +.endif + orrne r4, r3, r4 + strneb r4, [r1,#\offs] +.endm + +@ TileNorm (r1=pdest, r2=pixels8, r3=pal) r4: scratch, pat: register with helper pattern 0xf +.macro TileNorm pat + TilePixel \pat, 12, 0 @ #0x0000f000 + TilePixel \pat, 8, 1 @ #0x00000f00 + TilePixel \pat, 4, 2 @ #0x000000f0 + TilePixel \pat, 0, 3 @ #0x0000000f + TilePixel \pat, 28, 4 @ #0xf0000000 + TilePixel \pat, 24, 5 @ #0x0f000000 + TilePixel \pat, 20, 6 @ #0x00f00000 + TilePixel \pat, 16, 7 @ #0x000f0000 +.endm + +@ TileFlip (r1=pdest, r2=pixels8, r3=pal) r4: scratch, pat: register with helper pattern 0xf +.macro TileFlip pat + TilePixel \pat, 16, 0 @ #0x000f0000 + TilePixel \pat, 20, 1 @ #0x00f00000 + TilePixel \pat, 24, 2 @ #0x0f000000 + TilePixel \pat, 28, 3 @ #0xf0000000 + TilePixel \pat, 0, 4 @ #0x0000000f + TilePixel \pat, 4, 5 @ #0x000000f0 + TilePixel \pat, 8, 6 @ #0x00000f00 + TilePixel \pat, 12, 7 @ #0x0000f000 +.endm + +@ shadow/hilight mode + +@ this one is for hi priority layer +.macro TilePixelShHP lsrr offs +.if !\lsrr + ands r4, r12, r2 +.else + ands r4, r12, r2, lsr #\lsrr +.endif + ldreqb r4, [r1,#\offs] + orrne r4, r3, r4 + strneb r4, [r1,#\offs] + tsteq r4, #0x80 + andeq r4, r4, #0x3f + streqb r4, [r1,#\offs] +.endm + +@ TileNorm (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r12: register with helper pattern 0xf, touches r3 high bits +.macro TileNormShHP + TilePixelShHP 12, 0 @ #0x0000f000 + TilePixelShHP 8, 1 @ #0x00000f00 + TilePixelShHP 4, 2 @ #0x000000f0 + TilePixelShHP 0, 3 @ #0x0000000f + TilePixelShHP 28, 4 @ #0xf0000000 + TilePixelShHP 24, 5 @ #0x0f000000 + TilePixelShHP 20, 6 @ #0x00f00000 + TilePixelShHP 16, 7 @ #0x000f0000 +.endm + +@ TileFlip (r1=pdest, r2=pixels8, r3=pal) r4: scratch, pat: register with helper pattern 0xf +.macro TileFlipShHP + TilePixelShHP 16, 0 @ #0x000f0000 + TilePixelShHP 20, 1 @ #0x00f00000 + TilePixelShHP 24, 2 @ #0x0f000000 + TilePixelShHP 28, 3 @ #0xf0000000 + TilePixelShHP 0, 4 @ #0x0000000f + TilePixelShHP 4, 5 @ #0x000000f0 + TilePixelShHP 8, 6 @ #0x00000f00 + TilePixelShHP 12, 7 @ #0x0000f000 +.endm + + +@ TileSingleSh (r1=pdest, r2=pixels8, r3=pal) r4,r7: scratch, r0=sx; r12: helper pattern 0xf +.macro TileSingleSh + tst r0, #1 @ not aligned? + mov r7, #0x00c000 + orr r7, r7, #0xc0 + ldrneb r4, [r1] + ldreqh r4, [r1] + orr r4, r4, r7 + strneb r4, [r1], #1 + streqh r4, [r1], #2 + ldrh r4, [r1] + orr r4, r4, r7 + strh r4, [r1], #2 + ldrh r4, [r1] + orr r4, r4, r7 + strh r4, [r1], #2 + ldrh r4, [r1] + orr r4, r4, r7 + strh r4, [r1], #2 + ldrneb r4, [r1] + orr r4, r4, r7 + strneb r4, [r1], #1 +.endm + +@ TileSingleHi (r1=pdest, r2=pixels8, r3=pal) r4,r7: scratch, r0=sx, r12: register with helper pattern 0xf +.macro TileSingleHi + tst r1, #1 @ not aligned? + mov r7, #0x008000 + orr r7, r7, #0x80 + ldrneb r4, [r1], #1 + ldreqh r4, [r1], #2 @ 1ci + ldrh r12, [r1], #2 + bic r4, r4, r7, lsr #1 + orr r4, r4, r7 + strneb r4, [r1, #-3] + streqh r4, [r1, #-4] + ldrh r4, [r1], #2 + bic r12, r12, r7, lsr #1 + orr r12, r12, r7 + strh r12, [r1, #-4] + ldrh r12, [r1], #2 + bic r4, r4, r7, lsr #1 + orr r4, r4, r7 + strh r4, [r1, #-4] + ldrneb r4, [r1] + bic r12, r12, r7, lsr #1 + orr r12, r12, r7 + strh r12, [r1, #-2] + bicne r4, r4, r7, lsr #1 + orrne r4, r4, r7 + strneb r4, [r1], #1 + mov r12, #0xf +.endm + +.macro TileDoShGenPixel shift ofs +.if \shift + ands r4, r12, r2, lsr #\shift +.else + ands r4, r12, r2 +.endif + beq 3f + cmp r4, #0xe + beq 2f + bgt 1f + orr r4, r3, r4 + strb r4, [r1,#\ofs] + b 3f +1: + ldrb r4, [r1,#\ofs] @ 2ci + orr r4, r4, #0xc0 + strb r4, [r1,#\ofs] + b 3f +2: + ldrb r4, [r1,#\ofs] @ 2ci + bic r4, r4, #0xc0 + orr r4, r4, #0x80 + strb r4, [r1,#\ofs] +3: +.endm + +@ TileFlipSh (r1=pdest, r2=pixels8, r3=pal) r4,r7: scratch, r0=sx, r12: register with helper pattern 0xf +.macro TileFlipSh + TileDoShGenPixel 16, 0 @ #0x000f0000 + TileDoShGenPixel 20, 1 @ #0x00f00000 + TileDoShGenPixel 24, 2 @ #0x0f000000 + TileDoShGenPixel 28, 3 @ #0xf0000000 + TileDoShGenPixel 0, 4 @ #0x0000000f + TileDoShGenPixel 4, 5 @ #0x000000f0 + TileDoShGenPixel 8, 6 @ #0x00000f00 + TileDoShGenPixel 12, 7 @ #0x0000f000 +.endm + +@ TileNormSh (r1=pdest, r2=pixels8, r3=pal) r4,r7: scratch, r0=sx, r12: register with helper pattern 0xf +.macro TileNormSh + TileDoShGenPixel 12, 0 @ #0x0000f000 + TileDoShGenPixel 8, 1 @ #0x00000f00 + TileDoShGenPixel 4, 2 @ #0x000000f0 + TileDoShGenPixel 0, 3 @ #0x0000000f + TileDoShGenPixel 28, 4 @ #0xf0000000 + TileDoShGenPixel 24, 5 @ #0x0f000000 + TileDoShGenPixel 20, 6 @ #0x00f00000 + TileDoShGenPixel 16, 7 @ #0x000f0000 +.endm + + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +@ struct TileStrip +@ { +@ int nametab; // 0x00 +@ int line; // 0x04 +@ int hscroll; // 0x08 +@ int xmask; // 0x0C +@ int *hc; // 0x10 (pointer to cache buffer) +@ int cells; // 0x14 +@ }; + +@ int DrawLayer(int plane, int *hcache, int maxcells, int sh) + +.global DrawLayer @ int plane, int *hcache, int maxcells, int sh + +DrawLayer: + stmfd sp!, {r4-r11,lr} + + ldr r11, =(Pico+0x22228) @ Pico.video + mov r8, #1 + + ldrb r7, [r11, #16] @ ??hh??ww + + mov r6, r1 @ hcache + orr r9, r2, r3, lsl #31 @ r9=maxcells|(sh<<31) + + mov r1, r7, lsl #4 + orr r1, r1, #0x00ff + + and r10, r7, #3 + cmp r10, #1 + biclt r1, r1, #0xfc00 + biceq r1, r1, #0xfe00 + bicgt r1, r1, #0xff00 @ r1=ymask=(height<<8)|0xff; ...; // Y Mask in pixels + + add r10, r10, #5 + cmp r10, #7 + subge r10, r10, #1 @ r10=shift[width] (5,6,6,7) + + @ calculate xmask: + mov r5, r8, lsl r10 + sub r5, r5, #1 @ r5=xmask + + @ Find name table: + tst r0, r0 + ldreqb r12, [r11, #2] + ldrneb r12, [r11, #4] + + ldr r2, =Scanline @ trying to make good use of pipeline here + ldr lr, =(Pico+0x10000) @ lr=Pico.vram + + moveq r12, r12, lsl #10 + movne r12, r12, lsl #13 + and r12, r12, #(7<<13) @ r12=(ts->nametab<<1) (halfword compliant) + + ldrh r8, [r11, #12] + ldrb r7, [r11, #11] + ldr r2, [r2] + + mov r4, r8, lsr #8 @ pvid->reg[13] + mov r4, r4, lsl #10 @ htab=pvid->reg[13]<<9; (halfwords) + tst r7, #2 + addne r4, r4, r2, lsl #2 @ htab+=Scanline<<1; // Offset by line + tst r7, #1 + biceq r4, r4, #0x1f @ htab&=~0xf; // Offset by tile + add r4, r4, r0, lsl #1 @ htab+=plane + bic r4, r4, #0x00ff0000 @ just in case + ldrh r3, [lr, r4] @ r3=hscroll + + tst r7, #4 + bne .DrawStrip_vsscroll + + @ Get vertical scroll value: + add r7, lr, #0x012000 + add r7, r7, #0x000180 @ r7=Pico.vsram (Pico+0x22180) + ldr r7, [r7] + + tst r8, #2 + tstne r8, #4 + bne .DrawStrip_interlace + + tst r0, r0 + movne r7, r7, lsr #16 + + @ Find the line in the name table + add r2, r2, r7 + and r2, r2, r1 + mov r4, r2, lsr #3 + add r10, r10, #1 @ shift[width]++ + add r12, r12, r4, lsl r10 @ nametab+=(ts.line>>3)<hscroll, r5=ts->xmask, r6=ts->hc, r9=ts->cells +@ mov r12,r1, lsl #1 @ r12=(ts->nametab<<1) (halfword compliant) + + and r10,r2, #7 + mov r10,r10, lsl #1 @ r10=ty=(ts->line&7)<<1; + orr r10,r10, r9, lsl #24 + + rsb r8, r3, #0 + mov r8, r8, lsr #3 @ r8=tilex=(-ts->hscroll)>>3 + + sub r1, r3, #1 + and r1, r1, #7 + add r7, r1, #1 @ r7=dx=((ts->hscroll-1)&7)+1 + + tst r9, #1<<31 + mov r3, #0 + orrne r10,r10, #1<<23 @ r10=(cells<<24|sh<<23|hi_not_empty<<22|ty) + movne r3, #0x40 @ default to shadowed pal on sh mode + + mvn r9, #0 @ r9=prevcode=-1 + + cmp r7, #8 + addne r10,r10, #0x01000000 @ we will loop cells+1 times if there is scroll + + @ cache some stuff to avoid mem access + ldr r11,=HighCol + mov r0, #0xf + add r1, r11, r7 @ r1=pdest + + + @ r4 & r7 are scratch in this loop +.dsloop_subr1: + sub r1, r1, #8 +.dsloop: @ 40-41 times + subs r10,r10, #0x01000000 + bmi .dsloop_exit + +.dsloop_enter: + and r7, r5, r8 + add r7, lr, r7, lsl #1 @ Pico.vram+((tilex&ts->xmask) as halfwords) + ldrh r7, [r7, r12] @ r7=code (int, but from unsigned, no sign extend) + + add r1, r1, #8 + add r8, r8, #1 + + tst r7, #0x8000 + bne .DrawStrip_hiprio + + cmp r7, r9 + beq .DrawStrip_samecode @ we know stuff about this tile already + + mov r9, r7 @ remember code + + movs r2, r9, lsl #20 @ if (code&0x1000) + mov r2, r2, lsl #1 + add r2, r2, r10, lsl #17 + mov r2, r2, lsr #17 + eorcs r2, r2, #0x0e @ if (code&0x1000) addr^=0xe; + + ldr r2, [lr, r2, lsl #1] @ pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + + bic r7, r3, #0x3f + and r3, r9, #0x6000 + add r3, r7, r3, lsr #9 @ r3=pal=((code&0x6000)>>9); + +.DrawStrip_samecode: + tst r2, r2 + beq .dsloop @ tileline blank + + cmp r2, r2, ror #4 + beq .DrawStrip_SingleColor @ tileline singlecolor + + tst r9, #0x0800 + beq .DrawStrip_TileNorm + + @ (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r0: helper pattern + TileFlip r0 + b .dsloop + +.DrawStrip_TileNorm: + TileNorm r0 + b .dsloop + +.DrawStrip_SingleColor: + and r4, r2, #0xf + orr r4, r3, r4 + orr r4, r4, r4, lsl #8 + tst r1, #1 @ not aligned? + strneb r4, [r1], #1 + streqh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strneb r4, [r1], #1 @ have a remaining unaligned pixel? + b .dsloop_subr1 + +.DrawStrip_hiprio: + tst r10, #0x00c00000 + beq .DrawStrip_hiprio_maybempt + sub r0, r1, r11 + orr r7, r7, r0, lsl #16 + orr r7, r7, r10, lsl #25 @ (ty<<25) + tst r7, #0x1000 + eorne r7, r7, #7<<26 @ if(code&0x1000) cval^=7<<26; + str r7, [r6], #4 @ cache hi priority tile + mov r0, #0xf + b .dsloop + +.DrawStrip_hiprio_maybempt: + cmp r7, r9 + beq .dsloop @ must've been empty, otherwise we wouldn't get here + movs r2, r7, lsl #20 @ if (code&0x1000) + mov r2, r2, lsl #1 + add r2, r2, r10, lsl #17 + mov r2, r2, lsr #17 + eorcs r2, r2, #0x0e @ if (code&0x1000) addr^=0xe; + ldr r2, [lr, r2, lsl #1] @ pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + mov r9, r7 @ remember code + tst r2, r2 + orrne r10, r10, #1<<22 + bne .DrawStrip_hiprio + b .dsloop + +.dsloop_exit: + mov r0, #0 + str r0, [r6] @ terminate the cache list + + ldmfd sp!, {r4-r11,lr} + bx lr + + +.DrawStrip_vsscroll: + @ shit, we have 2-cell column based vscroll + @ let the c code handle this (for now) + + @ int nametab; // 0x00 + @ int line; // 0x04 + @ int hscroll; // 0x08 + @ int xmask; // 0x0C + @ int *hc; // 0x10 (pointer to cache buffer) + @ int cells; // 0x14 + + sub sp, sp, #6*4 + orr r2, r1, r10, lsl #24 @ ts.line=ymask|(shift[width]<<24); // save some stuff instead of line + mov r1, r0 @ plane + mov r0, r12, lsr #1 @ halfwords + and r9, r9, #0xff + stmia sp, {r0,r2,r3,r5,r6,r9} + + mov r0, sp + bl DrawStripVSRam @ struct TileStrip *ts, int plane + + add sp, sp, #6*4 + ldmfd sp!, {r4-r11,lr} + bx lr + +@ interlace mode 2? Sonic 2? +.DrawStrip_interlace: + tst r0, r0 + moveq r7, r7, lsl #21 + movne r7, r7, lsl #5 + + @ Find the line in the name table + add r2, r7, r2, lsl #22 @ r2=(vscroll+(Scanline<<1))<<21 (11 bits); + orr r1, r1, #0x80000000 + and r2, r2, r1, ror #10 @ &((ymask<<1)|1)<<21; + mov r2, r2, lsr #21 + mov r4, r2, lsr #4 + mov r12, r12, lsr #1 @ halfwords + add r0, r12, r4, lsl r10 @ nametab+=(ts.line>>4)<>9); + + ldr r2, [lr, r2, lsl #1] @ pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + +.dtfc_samecode: + tst r8, r8 + bne .dtfc_shadow + + tst r2, r2 + beq .dtfc_loop + + cmp r2, r2, ror #4 + beq .dtfc_SingleColor @ tileline singlecolor + + tst r5, #0x0800 + beq .dtfc_TileNorm + + @ (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r12: helper pattern + TileFlip r12 + b .dtfc_loop + +.dtfc_TileNorm: + TileNorm r12 + b .dtfc_loop + +.dtfc_SingleColor: + and r4, r2, #0xf + orr r4, r3, r4 + orr r4, r4, r4, lsl #8 + tst r1, #1 @ not aligned? + strneb r4, [r1], #1 + streqh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strneb r4, [r1], #1 @ have a remaining unaligned pixel? + b .dtfc_loop + +.dtfc_shadow: + tst r2, r2 + beq .dtfc_shadow_blank + + cmp r2, r2, ror #4 + beq .dtfc_SingleColor @ tileline singlecolor + + tst r5, #0x0800 + beq .dtfc_TileNormShHP + + @ (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r12: helper pattern + TileFlipShHP + b .dtfc_loop + +.dtfc_TileNormShHP: + TileNormShHP + b .dtfc_loop + +.dtfc_shadow_blank: + ldrb r4, [r1] @ 1ci + ldrb r12,[r1,#1] + tst r4, #0x80 + andeq r4, r4,#0x3f + streqb r4, [r1] + tst r12,#0x80 + ldrb r4, [r1,#2] + andeq r12,r12,#0x3f + streqb r12,[r1,#1] + tst r4, #0x80 + ldrb r12,[r1,#3] + andeq r4, r4,#0x3f + streqb r4, [r1,#2] + tst r12,#0x80 + ldrb r4, [r1,#4] + andeq r12,r12,#0x3f + streqb r12,[r1,#3] + tst r4, #0x80 + ldrb r12,[r1,#5] + andeq r4, r4,#0x3f + streqb r4, [r1,#4] + tst r12,#0x80 + ldrb r4, [r1,#6] + andeq r12,r12,#0x3f + streqb r12,[r1,#5] + tst r4, #0x80 + ldrb r12,[r1,#7] + andeq r4, r4,#0x3f + streqb r4, [r1,#6] + tst r12,#0x80 + andeq r12,r12,#0x3f + streqb r12,[r1,#7] + mov r12, #0xf + b .dtfc_loop + +.pool + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + +.global DrawSpritesFromCache @ int *hc, int sh + +DrawSpritesFromCache: + stmfd sp!, {r4-r11,lr} + + @ cache some stuff to avoid mem access + ldr r11,=HighCol + ldr lr, =(Pico+0x10000) @ lr=Pico.vram + mov r6, r1, lsl #31 + orr r6, r6, #1<<30 + mov r12,#0xf + + mov r10, r0 + +.dsfc_loop: + ldr r9, [r10], #4 @ read code + bic r6, r6, #7 @ using pipeline + tst r9, r9 + ldmeqfd sp!, {r4-r11,pc} + + mov r4, r9, lsl #28 + orr r6, r6, r4, lsr #30 + add r6, r6, #1 @ r6=s1cc???? ... ?????www (s=shadow/hilight, cc=pal, w=width) + + and r5, r9, #3 + add r5, r5, #1 @ r5=delta + tst r9, #0x10000 + rsbne r5, r5, #0 @ Flip X + mov r5, r5, lsl #4 + + mov r2, r9, lsr #17 + mov r8, r2, lsl #1 @ tile=((unsigned int)code>>17)<<1; + + and r3, r9, #0x30 @ r3=pal=(code&0x30); + + bic r6, r6, #3<<28 + orr r6, r6, r3, lsl #24 + + mov r0, r9, lsl #16 + mov r0, r0, asr #22 @ sx=(code<<16)>>22 + adds r0, r0, #0 @ set ZV + b .dsfc_inloop_enter + +@ scratch: r4, r7 +.dsfc_inloop: + sub r6, r6, #1 + tst r6, #7 + beq .dsfc_loop + adds r0, r0, #8 + add r8, r8, r5 + +.dsfc_inloop_enter: + ble .dsfc_inloop + cmp r0, #328 + bge .dsfc_loop + + mov r8, r8, lsl #17 + mov r8, r8, lsr #17 @ tile&=0x7fff; // Clip tile address + + ldr r2, [lr, r8, lsl #1] @ pack=*(unsigned int *)(Pico.vram+tile); // Get 8 pixels + add r1, r11, r0 @ r1=pdest + tst r2, r2 + beq .dsfc_inloop + + cmp r12, r6, lsr #28 + beq .dsfc_shadow + + cmp r2, r2, ror #4 + beq .dsfc_SingleColor @ tileline singlecolor + + tst r9, #0x10000 + beq .dsfc_TileNorm + + @ TileFlip (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r12: helper pattern + TileFlip r12 + b .dsfc_inloop + +.dsfc_TileNorm: + TileNorm r12 + b .dsfc_inloop + +.dsfc_SingleColor: + tst r0, #1 @ not aligned? + and r4, r2, #0xf + orr r4, r3, r4 + orr r4, r4, r4, lsl #8 + strneb r4, [r1], #1 + streqh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strneb r4, [r1], #1 + b .dsfc_inloop + +.dsfc_shadow: + cmp r2, r2, ror #4 + beq .dsfc_singlec_sh + + tst r9, #0x10000 + beq .dsfc_TileNorm_sh + + @ (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r12: helper pattern + TileFlipSh + b .dsfc_inloop + +.dsfc_TileNorm_sh: + TileNormSh + b .dsfc_inloop + +.dsfc_singlec_sh: + cmp r2, #0xe0000000 + bcc .dsfc_SingleColor @ normal singlecolor tileline (carry inverted in ARM) + tst r2, #0x10000000 + bne .dsfc_sh_sh + TileSingleHi + b .dsfc_inloop + +.dsfc_sh_sh: + TileSingleSh + b .dsfc_inloop + +.pool + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +@ + 0 : hhhhvvvv ab--hhvv yyyyyyyy yyyyyyyy // a: offscreen h, b: offs. v, h: horiz. size +@ + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8 + +.global DrawSprite @ unsigned int *sprite, int **hc, int sh + +DrawSprite: + stmfd sp!, {r4-r9,r11,lr} + + ldr r3, [r0] @ sprite[0] + ldr r7, =Scanline + mov r6, r3, lsr #28 + sub r6, r6, #1 @ r6=width-1 (inc later) + mov r5, r3, lsr #24 + and r5, r5, #7 @ r5=height + + mov r4, r3, lsl #16 @ r4=sy<<16 (tmp) + + ldr r7, [r7] + ldr r9, [r0, #4] + sub r7, r7, r4, asr #16 @ r7=row=Scanline-sy + + tst r2, r2 + mov r2, r9, asr #16 @ r2=sx + bic r9, r9, #0xfe000000 + orrne r9, r9, #1<<31 @ r9=code|(sh<<31) + + tst r9, #0x1000 + movne r4, r5, lsl #3 + subne r4, r4, #1 + subne r7, r4, r7 @ if (code&0x1000) row=(height<<3)-1-row; // Flip Y + + mov r8, r9, lsl #21 + mov r8, r8, lsr #21 + add r8, r8, r7, lsr #3 @ tile+=row>>3; // Tile number increases going down + + tst r9, #0x0800 + mlane r8, r5, r6, r8 @ if (code&0x0800) { tile+=delta*(width-1); + rsbne r5, r5, #0 @ delta=-delta; } // r5=delta now + + mov r8, r8, lsl #4 + and r7, r7, #7 + add r8, r8, r7, lsl #1 @ tile+=(row&7)<<1; // Tile address + + tst r9, #0x8000 + bne .dspr_cache @ if(code&0x8000) // high priority - cache it + + @ cache some stuff to avoid mem access + ldr r11,=HighCol + ldr lr, =(Pico+0x10000) @ lr=Pico.vram + mov r12,#0xf + + mov r5, r5, lsl #4 @ delta<<=4; // Delta of address + and r4, r9, #0x6000 + orr r9, r9, r4, lsl #16 + orr r9, r9, #0x10000000 @ r9=scc1 ???? ... (s=shadow/hilight, cc=pal) + + tst r9, #1<<31 + mov r3, r4, lsr #9 @ r3=pal=((code>>9)&0x30); + orrne r3, r3, #0x40 @ shadow by default + + add r6, r6, #1 @ inc now + adds r0, r2, #0 @ mov sx to r0 and set ZV flags + b .dspr_loop_enter + +.dspr_loop: + subs r6, r6, #1 @ width-- + ldmeqfd sp!, {r4-r9,r11,pc}@ return + adds r0, r0, #8 @ sx+=8 + add r8, r8, r5 @ tile+=delta + +.dspr_loop_enter: + ble .dspr_loop @ sx <= 0 + cmp r0, #328 + ldmgefd sp!, {r4-r9,r11,pc}@ return + + mov r8, r8, lsl #17 + mov r8, r8, lsr #17 @ tile&=0x7fff; // Clip tile address + + ldr r2, [lr, r8, lsl #1] @ pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + add r1, r11, r0 @ r1=pdest + tst r2, r2 + beq .dspr_loop + + cmp r12, r9, lsr #28 + beq .dspr_shadow + + cmp r2, r2, ror #4 + beq .dspr_SingleColor @ tileline singlecolor + + tst r9, #0x0800 + beq .dspr_TileNorm + + @ (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r12: helper pattern + TileFlip r12 + b .dspr_loop + +@ scratch: r4, r7 +.dspr_TileNorm: + TileNorm r12 + b .dspr_loop + +.dspr_SingleColor: + and r4, r2, #0xf + orr r4, r3, r4 + orr r4, r4, r4, lsl #8 + tst r0, #1 @ not aligned? + strneb r4, [r1], #1 + streqh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strneb r4, [r1], #1 + b .dspr_loop + +.dspr_shadow: + cmp r2, r2, ror #4 + beq .dspr_singlec_sh + + tst r9, #0x0800 + beq .dspr_TileNorm_sh + + @ (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r12: helper pattern + TileFlipSh + b .dspr_loop + +.dspr_TileNorm_sh: + TileNormSh + b .dspr_loop + +.dspr_singlec_sh: + cmp r2, #0xe0000000 + bcc .dspr_SingleColor @ normal tileline + tst r2, #0x10000000 + bne .dspr_sh_sh + TileSingleHi + b .dspr_loop + +.dspr_sh_sh: + TileSingleSh + b .dspr_loop + + +.dspr_cache: + @ *(*hc)++ = (tile<<16)|((code&0x0800)<<5)|((sx<<6)&0x0000ffc0)|((code>>9)&0x30)|((sprite[0]>>24)&0xf); + mov r4, r8, lsl #16 @ tile + tst r9, #0x0800 + orrne r4, r4, #0x10000 @ code&0x0800 + mov r2, r2, lsl #22 + orr r4, r4, r2, lsr #16 @ (sx<<6)&0x0000ffc0 + and r2, r9, #0x6000 + orr r4, r4, r2, lsr #9 @ (code>>9)&0x30 + mov r3, r3, lsl #12 + ldr r2, [r1] + orr r4, r4, r3, lsr #28 @ (sprite[0]>>24)&0xf + + str r4, [r2], #4 + str r2, [r1] + + ldmfd sp!, {r4-r9,r11,lr} + bx lr + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +.global DrawWindow @ int tstart, int tend, int prio, int sh // int *hcache + +DrawWindow: + stmfd sp!, {r4-r11,lr} + + ldr r11, =(Pico+0x22228) @ Pico.video + ldr r10, =Scanline + ldrb r12, [r11, #3] @ pvid->reg[3] + + ldr r10, [r10] + ldr r4, [r11, #12] + mov r5, r10, lsr #3 + and r10, r10, #7 + mov r10, r10, lsl #1 @ r10=ty + + mov r12, r12, lsl #10 + + tst r4, #1 @ 40 cell mode? + andne r12, r12, #0xf000 @ 0x3c<<10 + andeq r12, r12, #0xf800 + addne r12, r12, r5, lsl #7 + addeq r12, r12, r5, lsl #6 @ nametab + add r12, r12, r0, lsl #2 @ +starttile + + ldr r6, =rendstatus + ldr lr, =(Pico+0x10000) @ lr=Pico.vram + ldrb r6, [r6] + + @ fetch the first code now + ldrh r7, [lr, r12] + + ands r6, r6, #2 @ we care about bit 1 only + orr r6, r6, r2 + bne .dw_no_sameprio + + cmp r2, r7, lsr #15 + ldmnefd sp!, {r4-r11,pc} @ assume that whole window uses same priority + +.dw_no_sameprio: + orr r6, r6, r3, lsl #8 @ shadow mode + + sub r8, r1, r0 + mov r8, r8, lsl #1 @ cells + + mvn r9, #0 @ r9=prevcode=-1 + + @ cache some stuff to avoid mem access + ldr r11,=(HighCol+8) + add r1, r11, r0, lsl #4 @ r1=pdest + mov r0, #0xf + b .dwloop_enter + + @ r4,r5 & r7 are scratch in this loop +.dwloop: + add r1, r1, #8 +.dwloop_nor1: + add r12, r12, #2 @ halfwords + ldrh r7, [lr, r12] @ r7=code (int, but from unsigned, no sign extend) + subs r8, r8, #1 + beq .dwloop_end @ done + + eor r5, r6, r7, lsr #15 + tst r5, #1 + orrne r6, r6, #2 @ wrong pri + bne .dwloop + + cmp r7, r9 + beq .dw_samecode @ we know stuff about this tile already + +.dwloop_enter: + mov r9, r7 @ remember code + + movs r2, r9, lsl #20 @ if (code&0x1000) + mov r2, r2, lsl #1 + add r2, r10, r2, lsr #17 @ r2=addr=(code&0x7ff)<<4; addr+=ty + eorcs r2, r2, #0x0e @ if (code&0x1000) addr^=0xe; + + and r3, r9, #0x6000 + mov r3, r3, lsr #9 @ r3=pal=((code&0x6000)>>9); + + ldr r2, [lr, r2, lsl #1] @ pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + +.dw_samecode: + tst r6, #0x100 + bne .dw_shadow +.dw_shadow_done: + tst r2, r2 + beq .dwloop @ tileline blank + + cmp r2, r2, ror #4 + beq .dw_SingleColor @ tileline singlecolor + + tst r9, #0x0800 + beq .dw_TileNorm + + @ (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r0: helper pattern + TileFlip r0 + b .dwloop + +.dw_TileNorm: + TileNorm r0 + b .dwloop + +.dw_SingleColor: + and r4, r0, r2 @ #0x0000000f + orr r4, r3, r4 + orr r4, r4, r4, lsl #8 + orr r4, r4, r4, lsl #16 + mov r5, r4 + stmia r1!, {r4,r5} + b .dwloop_nor1 @ we incremeted r1 ourselves + +.dw_shadow: + tst r6, #1 @ hi pri? + orreq r3, r3, #0x40 + beq .dw_shadow_done + ldr r4, [r1] + tst r4, #0x00000080 + biceq r4, r4, #0x000000c0 + tst r4, #0x00008000 + biceq r4, r4, #0x0000c000 + tst r4, #0x00800000 + biceq r4, r4, #0x00c00000 + tst r4, #0x80000000 + biceq r4, r4, #0xc0000000 + str r4, [r1] + ldr r4, [r1,#4] + tst r4, #0x00000080 + biceq r4, r4, #0x000000c0 + tst r4, #0x00008000 + biceq r4, r4, #0x0000c000 + tst r4, #0x00800000 + biceq r4, r4, #0x00c00000 + tst r4, #0x80000000 + biceq r4, r4, #0xc0000000 + str r4, [r1,#4] + b .dw_shadow_done + +.dwloop_end: + ldr r0, =rendstatus + ldr r1, [r0] + and r6, r6, #2 + orr r1, r1, r6 + str r1, [r0] + + ldmfd sp!, {r4-r11,r12} + bx r12 + + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + +@ hilights 2 pixels in RGB444/BGR444 format +.macro TileDoShHi2Pixels444 reg + mov \reg, \reg, ror #12 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #28 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #28 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #24 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #28 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #28 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #12 +.endm + + +.global FinalizeLineBGR444 @ int sh + +FinalizeLineBGR444: + stmfd sp!, {r4-r6,lr} + mov r6, r0 + ldr lr, =(Pico+0x22228) @ Pico.video + ldr r0, =DrawLineDest + ldrb r12, [lr, #12] + ldr r0, [r0] + sub r3, lr, #0x128 @ r3=Pico.cram + + tst r12, #1 + movne r2, #320/4 @ len + bne .fl_no32colBGR444 + ldr r4, =PicoOpt + mov r2, #256/4 + ldr r4, [r4] + tst r4, #0x100 + addeq r0, r0, #32*2 + +.fl_no32colBGR444: + tst r6, r6 + beq .fl_noshBGR444 + + ldr r4, =HighPal + + ldrb r12, [lr, #-0x1a] @ 0x2220e ~ dirtyPal + tst r12, r12 + moveq r3, r4 + beq .fl_noshBGR444 + mov r12, #0 + strb r12, [lr, #-0x1a] + + mov lr, #0x40/8 + @ copy pal: +.fl_loopcpBGR444: + ldmia r3!, {r1,r5,r6,r12} + subs lr, lr, #1 + stmia r4!, {r1,r5,r6,r12} + bne .fl_loopcpBGR444 + + @ shadowed pixels: + mov r12, #0x0077 + orr r12,r12,#0x0700 + orr r12,r12,r12,lsl #16 + sub r3, r3, #0x40*2 + add r5, r4, #0x80*2 + mov lr, #0x40/4 +.fl_loopcpBGR444_sh: + ldmia r3!, {r1,r6} + subs lr, lr, #1 + and r1, r12, r1, lsr #1 + and r6, r12, r6, lsr #1 + stmia r4!, {r1,r6} + stmia r5!, {r1,r6} + bne .fl_loopcpBGR444_sh + + @ hilighted pixels: + sub r3, r3, #0x40*2 + mov lr, #0x40/2 +.fl_loopcpBGR444_hi: + ldr r1, [r3], #4 + TileDoShHi2Pixels444 r1 + str r1, [r4], #4 + subs lr, lr, #1 + bne .fl_loopcpBGR444_hi + + sub r3, r4, #0x40*3*2 + + +.fl_noshBGR444: + ldr r1, =(HighCol+8) + mov lr, #0xff + mov lr, lr, lsl #1 + +.fl_loopBGR444: + + ldr r12, [r1], #4 + subs r2, r2, #1 + + and r4, lr, r12, lsl #1 + ldrh r4, [r3, r4] + and r5, lr, r12, lsr #7 + ldrh r5, [r3, r5] + and r6, lr, r12, lsr #15 + ldrh r6, [r3, r6] + orr r4, r4, r5, lsl #16 + + and r5, lr, r12, lsr #23 + ldrh r5, [r3, r5] @ 2c.i. + orr r5, r6, r5, lsl #16 + + stmia r0!, {r4,r5} + bne .fl_loopBGR444 + + + ldmfd sp!, {r4-r6,lr} + bx lr + + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + +@ hilights 2 pixels in RGB555/BGR555 format +.macro TileDoShHi2Pixels555 reg + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #27 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #26 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #27 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #27 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #26 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #27 +.endm + + +@ Convert 0000bbb0 ggg0rrr0 +@ to rrrrrggg gggbbbbb + +@ r2,r3,r9 - scratch, lr = 0x001c001c, r8 = 0x00030003 +.macro convRGB565 reg + and r2, lr, \reg,lsl #1 + and r9, r8, \reg,lsr #2 + orr r2, r2, r9 @ r2=red + and r3, lr, \reg,lsr #7 + and r9, r8, \reg,lsr #10 + orr r3, r3, r9 @ r3=blue + and \reg, \reg, lr, lsl #3 + orr \reg, \reg, \reg,lsl #3 @ green + orr \reg, \reg, r2, lsl #11 @ add red back + orr \reg, \reg, r3 @ add blue back +.endm + +vidConvCpyRGB565: @ void *to, void *from, int pixels + stmfd sp!, {r4-r9,lr} + + mov r12, r2, lsr #3 @ repeats + mov lr, #0x001c0000 + orr lr, lr, #0x01c @ lr == pattern 0x001c001c + mov r8, #0x00030000 + orr r8, r8, #0x003 @ lr == pattern 0x001c001c + +.loopRGB565: + ldmia r1!, {r4-r7} + subs r12, r12, #1 + convRGB565 r4 + str r4, [r0], #4 + convRGB565 r5 + str r5, [r0], #4 + convRGB565 r6 + str r6, [r0], #4 + convRGB565 r7 + str r7, [r0], #4 + + bgt .loopRGB565 + + ldmfd sp!, {r4-r9,lr} + bx lr + + + +.global FinalizeLineRGB555 @ int sh + +FinalizeLineRGB555: + stmfd sp!, {r4-r8,lr} + ldr r5, =(Pico+0x22228) @ Pico.video + ldr r4, =HighPal + + ldrb r7, [r5, #-0x1a] @ 0x2220e ~ dirtyPal + mov r6, r0 + mov r1, #0 + tst r7, r7 + beq .fl_noconvRGB555 + strb r1, [r5, #-0x1a] + sub r1, r5, #0x128 @ r1=Pico.cram + mov r0, r4 + mov r2, #0x40 + bl vidConvCpyRGB565 + +.fl_noconvRGB555: + ldrb r12, [r5, #12] + ldr r0, =DrawLineDest + ldr r0, [r0] + + tst r12, #1 + movne r2, #320/8 @ len + bne .fl_no32colRGB555 + ldr r3, =PicoOpt + mov r2, #256/8 + ldr r3, [r3] + tst r3, #0x100 + addeq r0, r0, #32*2 + +.fl_no32colRGB555: + mov r3, r4 + tst r6, r6 + beq .fl_noshRGB555 + tst r7, r7 + beq .fl_noshRGB555 + + @ shadowed pixels: + mov r12, #0x008e + orr r12,r12,#0x7300 + orr r12,r12,r12,lsl #16 + add r4, r3, #0x40*2 + add r5, r3, #0xc0*2 + mov lr, #0x40/4 +.fl_loopcpRGB555_sh: + ldmia r3!, {r1,r6} + subs lr, lr, #1 + and r1, r12, r1, lsr #1 + and r6, r12, r6, lsr #1 + stmia r4!, {r1,r6} + stmia r5!, {r1,r6} + bne .fl_loopcpRGB555_sh + + @ hilighted pixels: + sub r3, r3, #0x40*2 + mov lr, #0x40/2 +.fl_loopcpRGB555_hi: + ldr r1, [r3], #4 + TileDoShHi2Pixels555 r1 + str r1, [r4], #4 + subs lr, lr, #1 + bne .fl_loopcpRGB555_hi + + sub r3, r3, #0x40*2 + + +.fl_noshRGB555: + ldr r1, =(HighCol+8) + mov lr, #0xff + mov lr, lr, lsl #1 + +.fl_loopRGB555: + + ldr r12, [r1], #4 + ldr r7, [r1], #4 + + and r4, lr, r12, lsl #1 + ldrh r4, [r3, r4] + and r5, lr, r12, lsr #7 + ldrh r5, [r3, r5] + and r6, lr, r12, lsr #15 + ldrh r6, [r3, r6] + orr r4, r4, r5, lsl #16 + + and r5, lr, r12, lsr #23 + ldrh r5, [r3, r5] + and r8, lr, r7, lsl #1 + ldrh r8, [r3, r8] + orr r5, r6, r5, lsl #16 + + and r6, lr, r7, lsr #7 + ldrh r6, [r3, r6] + and r12,lr, r7, lsr #15 + ldrh r12,[r3, r12] + orr r8, r8, r6, lsl #16 + + and r6, lr, r7, lsr #23 + ldrh r6, [r3, r6] @ 1 cycle interlock here (r6) + subs r2, r2, #1 + orr r12,r12, r6, lsl #16 + + stmia r0!, {r4,r5,r8,r12} + bne .fl_loopRGB555 + + + ldmfd sp!, {r4-r8,lr} + bx lr + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +@ utility +.global blockcpy @ void *dst, void *src, size_t n + +blockcpy: + stmfd sp!, {r4,r5} + mov r2, r2, lsr #4 +blockcpy_loop: + ldmia r1!, {r3-r5,r12} + subs r2, r2, #1 + stmia r0!, {r3-r5,r12} + bne blockcpy_loop + ldmfd sp!, {r4,r5} + bx lr + + +.global blockcpy_or @ void *dst, void *src, size_t n, int pat + +blockcpy_or: + stmfd sp!, {r4-r6} + orr r3, r3, r3, lsl #8 + orr r3, r3, r3, lsl #16 + mov r2, r2, lsr #4 +blockcpy_loop_or: + ldmia r1!, {r4-r6,r12} + subs r2, r2, #1 + orr r4, r4, r3 + orr r5, r5, r3 + orr r6, r6, r3 + orr r12,r12,r3 + stmia r0!, {r4-r6,r12} + bne blockcpy_loop_or + ldmfd sp!, {r4-r6} + bx lr + diff --git a/Pico/Draw2.c b/Pico/Draw2.c new file mode 100644 index 00000000..b8fa76ad --- /dev/null +++ b/Pico/Draw2.c @@ -0,0 +1,633 @@ +// This is part of Pico Library + +// (c) Copyright 2006 notaz, All rights reserved. +// Free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + + +// this is a frame-based renderer, alternative to Dave's line based which is in Draw.c + + +#include "PicoInt.h" +#include +#ifndef __GNUC__ +#pragma warning (disable:4706) // Disable assignment within conditional +#endif + +// port_config.h include must define these 2 defines: +// #define START_ROW 1 // which row of tiles to start rendering at? +// #define END_ROW 27 // ..end +// one row means 8 pixels. If above example was used, (27-1)*8=208 lines would be rendered. + +#define TILE_ROWS END_ROW-START_ROW + +#define USE_CACHE + + +extern unsigned char *framebuff; // in format (8+320)x(8+224+8) (eights for borders) +int currpri = 0; + +static int HighCacheA[41*(TILE_ROWS+1)+1+1]; // caches for high layers +static int HighCacheB[41*(TILE_ROWS+1)+1+1]; + +unsigned short *PicoCramHigh=Pico.cram; // pointer to CRAM buff (0x40 shorts), converted to native device color (works only with 16bit for now) +void (*PicoPrepareCram)()=0; // prepares PicoCramHigh for renderer to use + + +// stuff available in asm: +#ifdef _ASM_DRAW_C +void BackFillFull(int reg7); +void DrawLayerFull(int plane, int *hcache, int planestart, int planeend); +void DrawTilesFromCacheF(int *hc); +void DrawWindowFull(int start, int end, int prio); +void DrawSpriteFull(unsigned int *sprite); +#else + + +static int TileXnormYnorm(unsigned char *pd,int addr,unsigned char pal) +{ + unsigned int pack=0; unsigned int t=0, blank = 1; + int i; + + for(i=8; i; i--, addr+=2, pd += 320+8) { + pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + if(!pack) continue; + + t=pack&0x0000f000; if (t) pd[0]=(unsigned char)((t>>12)|pal); + t=pack&0x00000f00; if (t) pd[1]=(unsigned char)((t>> 8)|pal); + t=pack&0x000000f0; if (t) pd[2]=(unsigned char)((t>> 4)|pal); + t=pack&0x0000000f; if (t) pd[3]=(unsigned char)((t )|pal); + t=pack&0xf0000000; if (t) pd[4]=(unsigned char)((t>>28)|pal); + t=pack&0x0f000000; if (t) pd[5]=(unsigned char)((t>>24)|pal); + t=pack&0x00f00000; if (t) pd[6]=(unsigned char)((t>>20)|pal); + t=pack&0x000f0000; if (t) pd[7]=(unsigned char)((t>>16)|pal); + blank = 0; + } + + return blank; // Tile blank? +} + +static int TileXflipYnorm(unsigned char *pd,int addr,unsigned char pal) +{ + unsigned int pack=0; unsigned int t=0, blank = 1; + int i; + + for(i=8; i; i--, addr+=2, pd += 320+8) { + pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + if(!pack) continue; + + t=pack&0x000f0000; if (t) pd[0]=(unsigned char)((t>>16)|pal); + t=pack&0x00f00000; if (t) pd[1]=(unsigned char)((t>>20)|pal); + t=pack&0x0f000000; if (t) pd[2]=(unsigned char)((t>>24)|pal); + t=pack&0xf0000000; if (t) pd[3]=(unsigned char)((t>>28)|pal); + t=pack&0x0000000f; if (t) pd[4]=(unsigned char)((t )|pal); + t=pack&0x000000f0; if (t) pd[5]=(unsigned char)((t>> 4)|pal); + t=pack&0x00000f00; if (t) pd[6]=(unsigned char)((t>> 8)|pal); + t=pack&0x0000f000; if (t) pd[7]=(unsigned char)((t>>12)|pal); + blank = 0; + } + return blank; // Tile blank? +} + +static int TileXnormYflip(unsigned char *pd,int addr,unsigned char pal) +{ + unsigned int pack=0; unsigned int t=0, blank = 1; + int i; + + addr+=14; + for(i=8; i; i--, addr-=2, pd += 320+8) { + pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + if(!pack) continue; + + t=pack&0x0000f000; if (t) pd[0]=(unsigned char)((t>>12)|pal); + t=pack&0x00000f00; if (t) pd[1]=(unsigned char)((t>> 8)|pal); + t=pack&0x000000f0; if (t) pd[2]=(unsigned char)((t>> 4)|pal); + t=pack&0x0000000f; if (t) pd[3]=(unsigned char)((t )|pal); + t=pack&0xf0000000; if (t) pd[4]=(unsigned char)((t>>28)|pal); + t=pack&0x0f000000; if (t) pd[5]=(unsigned char)((t>>24)|pal); + t=pack&0x00f00000; if (t) pd[6]=(unsigned char)((t>>20)|pal); + t=pack&0x000f0000; if (t) pd[7]=(unsigned char)((t>>16)|pal); + blank = 0; + } + + return blank; // Tile blank? +} + +static int TileXflipYflip(unsigned char *pd,int addr,unsigned char pal) +{ + unsigned int pack=0; unsigned int t=0, blank = 1; + int i; + + addr+=14; + for(i=8; i; i--, addr-=2, pd += 320+8) { + pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + if(!pack) continue; + + t=pack&0x000f0000; if (t) pd[0]=(unsigned char)((t>>16)|pal); + t=pack&0x00f00000; if (t) pd[1]=(unsigned char)((t>>20)|pal); + t=pack&0x0f000000; if (t) pd[2]=(unsigned char)((t>>24)|pal); + t=pack&0xf0000000; if (t) pd[3]=(unsigned char)((t>>28)|pal); + t=pack&0x0000000f; if (t) pd[4]=(unsigned char)((t )|pal); + t=pack&0x000000f0; if (t) pd[5]=(unsigned char)((t>> 4)|pal); + t=pack&0x00000f00; if (t) pd[6]=(unsigned char)((t>> 8)|pal); + t=pack&0x0000f000; if (t) pd[7]=(unsigned char)((t>>12)|pal); + blank = 0; + } + return blank; // Tile blank? +} + + +// start: (tile_start<<16)|row_start, end: [same] +static void DrawWindowFull(int start, int end, int prio) +{ + struct PicoVideo *pvid=&Pico.video; + int nametab, nametab_step, trow, tilex, blank=-1, code; + unsigned char *scrpos = framebuff; + int tile_start, tile_end; // in cells + + // parse ranges + tile_start = start>>16; + tile_end = end>>16; + start = start<<16>>16; + end = end<<16>>16; + + // Find name table line: + if (pvid->reg[12]&1) + { + nametab=(pvid->reg[3]&0x3c)<<9; // 40-cell mode + nametab_step = 1<<6; + } + else + { + nametab=(pvid->reg[3]&0x3e)<<9; // 32-cell mode + nametab_step = 1<<5; + } + nametab += nametab_step*start; + + // check priority + code=Pico.vram[nametab+tile_start]; + if ((code>>15) != prio) return; // hack: just assume that whole window uses same priority + + scrpos+=8*328+8; + scrpos+=8*328*(start-START_ROW); + + // do a window until we reach planestart row + for(trow = start; trow < end; trow++, nametab+=nametab_step) { // current tile row + for (tilex=tile_start; tilex>9)&0x30); + pal=(unsigned char)((code>>9)&0x30); + + switch((code>>11)&3) { + case 0: zero=TileXnormYnorm(scrpos+(tilex<<3),addr,pal); break; + case 1: zero=TileXflipYnorm(scrpos+(tilex<<3),addr,pal); break; + case 2: zero=TileXnormYflip(scrpos+(tilex<<3),addr,pal); break; + case 3: zero=TileXflipYflip(scrpos+(tilex<<3),addr,pal); break; + } + if(zero) blank=code; // We know this tile is blank now + } + + scrpos += 328*8; + } +} + + +static void DrawLayerFull(int plane, int *hcache, int planestart, int planeend) +{ + struct PicoVideo *pvid=&Pico.video; + static char shift[4]={5,6,6,7}; // 32,64 or 128 sized tilemaps + int width, height, ymask, htab; + int nametab, hscroll=0, vscroll, cells; + unsigned char *scrpos; + int blank=-1, xmask, nametab_row, trow; + + // parse ranges + cells = (planeend>>16)-(planestart>>16); + planestart = planestart<<16>>16; + planeend = planeend<<16>>16; + + // Work out the Tiles to draw + + htab=pvid->reg[13]<<9; // Horizontal scroll table address +// if ( pvid->reg[11]&2) htab+=Scanline<<1; // Offset by line +// if ((pvid->reg[11]&1)==0) htab&=~0xf; // Offset by tile + htab+=plane; // A or B + + if(!(pvid->reg[11]&3)) { // full screen scroll + // Get horizontal scroll value + hscroll=Pico.vram[htab&0x7fff]; + htab = 0; // this marks that we don't have to update scroll value + } + + // Work out the name table size: 32 64 or 128 tiles (0-3) + width=pvid->reg[16]; + height=(width>>4)&3; width&=3; + + xmask=(1<1) ymask =0x1f; + + // Find name table: + if (plane==0) nametab=(pvid->reg[2]&0x38)<< 9; // A + else nametab=(pvid->reg[4]&0x07)<<12; // B + + scrpos = framebuff; + scrpos+=8*328*(planestart-START_ROW); + + // Get vertical scroll value: + vscroll=Pico.vsram[plane]&0x1ff; + scrpos+=(8-(vscroll&7))*328; + if(vscroll&7) planeend++; // we have vertically clipped tiles due to vscroll, so we need 1 more row + + *hcache++ = 8-(vscroll&7); // push y-offset to tilecache + + + for(trow = planestart; trow < planeend; trow++) { // current tile row + int cellc=cells,tilex,dx; + + // Find the tile row in the name table + //ts.line=(vscroll+Scanline)&ymask; + //ts.nametab+=(ts.line>>3)<>3))&ymask)<>3; + dx=((hscroll-1)&7)+1; + if(dx != 8) cellc++; // have hscroll, do more cells + + for (; cellc; dx+=8,tilex++,cellc--) + { + int code=0,addr=0,zero=0; +// unsigned short *pal=NULL; + unsigned char pal; + + code=Pico.vram[nametab_row+(tilex&xmask)]; + if (code==blank) continue; + +#ifdef USE_CACHE + if (code>>15) { // high priority tile + *hcache++ = code|(dx<<16)|(trow<<27); // cache it +#else + if ((code>>15) != currpri) { +#endif + continue; + } + + // Get tile address/2: + addr=(code&0x7ff)<<4; + +// pal=PicoCramHigh+((code>>9)&0x30); + pal=(unsigned char)((code>>9)&0x30); + + switch((code>>11)&3) { + case 0: zero=TileXnormYnorm(scrpos+dx,addr,pal); break; + case 1: zero=TileXflipYnorm(scrpos+dx,addr,pal); break; + case 2: zero=TileXnormYflip(scrpos+dx,addr,pal); break; + case 3: zero=TileXflipYflip(scrpos+dx,addr,pal); break; + } + if(zero) blank=code; // We know this tile is blank now + } + + scrpos += 328*8; + } + + *hcache = 0; // terminate cache +} + + +static void DrawTilesFromCacheF(int *hc) +{ + int code, addr, zero = 0; + unsigned int prevy=0xFFFFFFFF; +// unsigned short *pal; + unsigned char pal; + short blank=-1; // The tile we know is blank + unsigned char *scrpos = framebuff, *pd = 0; + + // *hcache++ = code|(dx<<16)|(trow<<27); // cache it + scrpos+=(*hc++)*328 - START_ROW*328*8; + + while((code=*hc++)) { + if((short)code == blank) continue; + + // y pos + if(((unsigned)code>>27) != prevy) { + prevy = (unsigned)code>>27; + pd = scrpos + prevy*328*8; + } + + // Get tile address/2: + addr=(code&0x7ff)<<4; +// pal=PicoCramHigh+((code>>9)&0x30); + pal=(unsigned char)((code>>9)&0x30); + + switch((code>>11)&3) { + case 0: zero=TileXnormYnorm(pd+((code>>16)&0x1ff),addr,pal); break; + case 1: zero=TileXflipYnorm(pd+((code>>16)&0x1ff),addr,pal); break; + case 2: zero=TileXnormYflip(pd+((code>>16)&0x1ff),addr,pal); break; + case 3: zero=TileXflipYflip(pd+((code>>16)&0x1ff),addr,pal); break; + } + + if(zero) blank=(short)code; + } +} + + +// sx and sy are coords of virtual screen with 8pix borders on top and on left +static void DrawSpriteFull(unsigned int *sprite) +{ + int width=0,height=0; +// unsigned short *pal=NULL; + unsigned char pal; + int tile,code,tdeltax,tdeltay; + unsigned char *scrpos; + int sx, sy; + + sy=sprite[0]; + height=sy>>24; + sy=(sy&0x1ff)-0x78; // Y + width=(height>>2)&3; height&=3; + width++; height++; // Width and height in tiles + + code=sprite[1]; + sx=((code>>16)&0x1ff)-0x78; // X + + tile=code&0x7ff; // Tile number + tdeltax=height; // Delta to increase tile by going right + tdeltay=1; // Delta to increase tile by going down + if (code&0x0800) { tdeltax=-tdeltax; tile+=height*(width-1); } // Flip X + if (code&0x1000) { tdeltay=-tdeltay; tile+=height-1; } // Flip Y + + //delta<<=4; // Delta of address +// pal=PicoCramHigh+((code>>9)&0x30); // Get palette pointer + pal=(unsigned char)((code>>9)&0x30); + + // goto first vertically visible tile + while(sy <= START_ROW*8) { sy+=8; tile+=tdeltay; height--; } + + scrpos = framebuff; + scrpos+=(sy-START_ROW*8)*328; + + for (; height > 0; height--, sy+=8, tile+=tdeltay) + { + int w = width, x=sx, t=tile; + + if(sy >= END_ROW*8+8) return; // offscreen + + for (; w; w--,x+=8,t+=tdeltax) + { + if(x<=0) continue; + if(x>=328) break; // Offscreen + + t&=0x7fff; // Clip tile address + switch((code>>11)&3) { + case 0: TileXnormYnorm(scrpos+x,t<<4,pal); break; + case 1: TileXflipYnorm(scrpos+x,t<<4,pal); break; + case 2: TileXnormYflip(scrpos+x,t<<4,pal); break; + case 3: TileXflipYflip(scrpos+x,t<<4,pal); break; + } + } + + scrpos+=8*328; + } +} +#endif + + +static void DrawAllSpritesFull(int prio, int maxwidth) +{ + struct PicoVideo *pvid=&Pico.video; + int table=0,maskrange=0; + int i,u,link=0; + unsigned int *sprites[80]; // Sprites + int y_min=START_ROW*8, y_max=END_ROW*8; // for a simple sprite masking + + table=pvid->reg[5]&0x7f; + if (pvid->reg[12]&1) table&=0x7e; // Lowest bit 0 in 40-cell mode + table<<=8; // Get sprite table address/2 + + for (i=u=0; u < 80; u++) + { + unsigned int *sprite=NULL; + int code, code2, sx, sy, height; + + sprite=(unsigned int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite + + // get sprite info + code = sprite[0]; + + // check if it is not hidden vertically + sy = (code&0x1ff)-0x80; + height = (((code>>24)&3)+1)<<3; + if(sy+height <= y_min || sy > y_max) goto nextsprite; + + // masking sprite? + code2=sprite[1]; + sx = (code2>>16)&0x1ff; + if(!sx) { + int to = sy+height; // sy ~ from + if(maskrange) { + // try to merge with previous range + if((maskrange>>16)+1 >= sy && (maskrange>>16) <= to && (maskrange&0xffff) < sy) sy = (maskrange&0xffff); + else if((maskrange&0xffff)-1 <= to && (maskrange&0xffff) >= sy && (maskrange>>16) > to) to = (maskrange>>16); + } + // support only very simple masking (top and bottom of screen) + if(sy <= y_min && to+1 > y_min) y_min = to+1; + else if(to >= y_max && sy-1 < y_max) y_max = sy-1; + else maskrange=sy|(to<<16); + + goto nextsprite; + } + + // priority + if(((code2>>15)&1) != prio) goto nextsprite; // wrong priority + + // check if sprite is not hidden horizontally + sx -= 0x78; // Get X coordinate + 8 + if(sx <= -8*3 || sx >= maxwidth) goto nextsprite; + + // sprite is good, save it's index + sprites[i++]=sprite; + + nextsprite: + // Find next sprite + link=(code>>16)&0x7f; + if(!link) break; // End of sprites + } + + // Go through sprites backwards: + for (i-- ;i>=0; i--) + { + DrawSpriteFull(sprites[i]); + } +} + +#ifndef _ASM_DRAW_C +static void BackFillFull(int reg7) +{ + unsigned int back, i; + unsigned int *p=(unsigned int *)framebuff; + + // Start with a background color: +// back=PicoCramHigh[reg7&0x3f]; + back=reg7&0x3f; + back|=back<<8; + back|=back<<16; + + for(i = (8+320)*(8+(END_ROW-START_ROW)*8)/16; i; i--) { + *p++ = back; // do 16 pixels per iteration + *p++ = back; + *p++ = back; + *p++ = back; + } +} +#endif + +static void DrawDisplayFull() +{ + struct PicoVideo *pvid=&Pico.video; + int win, edge=0, hvwin=0; // LSb->MSb: hwin&plane, vwin&plane, full + int planestart=START_ROW, planeend=END_ROW; // plane A start/end when window shares display with plane A (in tile rows or columns) + int winstart=START_ROW, winend=END_ROW; // same for window + int maxw, maxcolc; // max width and col cells + + if(pvid->reg[12]&1) { + maxw = 328; maxcolc = 40; + } else { + maxw = 264; maxcolc = 32; + } + + // horizontal window? + if((win=pvid->reg[0x12])) { + hvwin=1; // hwindow shares display with plane A + edge=win&0x1f; + if(win == 0x80) { + // fullscreen window + hvwin=4; + } else if(win < 0x80) { + // window on the top + if(edge <= START_ROW) hvwin=0; // window not visible in our drawing region + else if(edge >= END_ROW) hvwin=4; + else planestart = winend = edge; + } else if(win > 0x80) { + // window at the bottom + if(edge >= END_ROW) hvwin=0; + else planeend = winstart = edge; + } + } + + // check for vertical window, but only if win is not fullscreen + if(hvwin != 4) { + win=pvid->reg[0x11]; + edge=win&0x1f; + if (win&0x80) { + if(!edge) hvwin=4; + else if(edge < (maxcolc>>1)) { + // window is on the right + hvwin|=2; + planeend|=edge<<17; + winstart|=edge<<17; + winend|=maxcolc<<16; + } + } else { + if(edge >= (maxcolc>>1)) hvwin=4; + else if(edge) { + // window is on the left + hvwin|=2; + winend|=edge<<17; + planestart|=edge<<17; + planeend|=maxcolc<<16; + } + } + } + + if(hvwin==1) { winend|=maxcolc<<16; planeend|=maxcolc<<16; } + + currpri = 0; + DrawLayerFull(1, HighCacheB, START_ROW, (maxcolc<<16)|END_ROW); + switch(hvwin) { + case 4: + // fullscreen window + DrawWindowFull(START_ROW, (maxcolc<<16)|END_ROW, 0); + HighCacheA[1] = 0; + break; + + case 3: + // we have plane A and both v and h windows + DrawLayerFull(0, HighCacheA, planestart, planeend); + DrawWindowFull( winstart&~0xff0000, (winend&~0xff0000)|(maxcolc<<16), 0); // h + DrawWindowFull((winstart&~0xff)|START_ROW, (winend&~0xff)|END_ROW, 0); // v + break; + + case 2: + case 1: + // both window and plane A visible, window is vertical XOR horizontal + DrawLayerFull(0, HighCacheA, planestart, planeend); + DrawWindowFull(winstart, winend, 0); + break; + + default: + // fullscreen plane A + DrawLayerFull(0, HighCacheA, START_ROW, (maxcolc<<16)|END_ROW); + break; + } + DrawAllSpritesFull(0, maxw); + +#ifdef USE_CACHE + if(HighCacheB[1]) DrawTilesFromCacheF(HighCacheB); + if(HighCacheA[1]) DrawTilesFromCacheF(HighCacheA); + switch(hvwin) { + case 4: + // fullscreen window + DrawWindowFull(START_ROW, (maxcolc<<16)|END_ROW, 1); + break; + + case 3: + // we have plane A and both v and h windows + DrawWindowFull( winstart&~0xff0000, (winend&~0xff0000)|(maxcolc<<16), 1); // h + DrawWindowFull((winstart&~0xff)|START_ROW, (winend&~0xff)|END_ROW, 1); // v + break; + + case 2: + case 1: + // both window and plane A visible, window is vertical XOR horizontal + DrawWindowFull(winstart, winend, 1); + break; + } +#else + currpri = 1; + // TODO +#endif + DrawAllSpritesFull(1, maxw); +} + + +void PicoFrameFull() +{ + // prepare cram? + if(PicoPrepareCram) PicoPrepareCram(); + + // Draw screen: + BackFillFull(Pico.video.reg[7]); + if (Pico.video.reg[1]&0x40) DrawDisplayFull(); +} + diff --git a/Pico/Draw2.s b/Pico/Draw2.s new file mode 100644 index 00000000..f8463cf2 --- /dev/null +++ b/Pico/Draw2.s @@ -0,0 +1,928 @@ +@ assembly optimized versions of most funtions from draw2.c +@ this is highly specialized, be careful if changing related C code! + +@ (c) Copyright 2006, notaz +@ All Rights Reserved + + +.extern Pico +.extern framebuff + +@ define these constants in your include file: +@ .equiv START_ROW, 1 +@ .equiv END_ROW, 27 +@ one row means 8 pixels. If above example was used, (27-1)*8=208 lines would be rendered. +.include "port_config.s" + + +.global BackFillFull @ int reg7 + +BackFillFull: + stmfd sp!, {r4-r9,lr} + + ldr lr, =framebuff @ lr=framebuff + ldr lr, [lr] + add lr, lr, #328*8 + + mov r0, r0, lsl #26 + mov r0, r0, lsr #26 + orr r0, r0, r0, lsl #8 + orr r0, r0, r0, lsl #16 + + mov r1, r0 @ 25 opcodes wasted? + mov r2, r0 + mov r3, r0 + mov r4, r0 + mov r5, r0 + mov r6, r0 + mov r7, r0 + mov r8, r0 + mov r9, r0 + + mov r12, #(END_ROW-START_ROW)*8 + + @ go go go! +.bff_loop: + add lr, lr, #8 + subs r12, r12, #1 + + stmia lr!, {r0-r9} @ 10*4*8 + stmia lr!, {r0-r9} + stmia lr!, {r0-r9} + stmia lr!, {r0-r9} + stmia lr!, {r0-r9} + stmia lr!, {r0-r9} + stmia lr!, {r0-r9} + stmia lr!, {r0-r9} + + bne .bff_loop + + ldmfd sp!, {r4-r9,r12} + bx r12 + +.pool + +@ -------- some macros -------- + + +@ helper +@ TileLineSinglecol (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r0: pixels8_old +.macro TileLineSinglecol notsinglecol=0 + and r2, r2, #0xf @ #0x0000000f +.if !\notsinglecol + cmp r2, r0, lsr #28 @ if these don't match, + bicne r9, r9, #2 @ it is a sign that whole tile is not singlecolor (only it's lines may be) +.endif + orr r4, r3, r2 + orr r4, r4, r4, lsl #8 + + tst r1, #1 @ not aligned? + strneb r4, [r1], #1 + streqh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strneb r4, [r1], #1 @ have a remaining unaligned pixel? + sub r1, r1, #8 +.if !\notsinglecol + mov r0, #0xf + orr r0, r0, r2, lsl #28 @ we will need the old palindex later +.endif +.endm + +@ TileNorm (r1=pdest, r2=pixels8, r3=pal) r0,r4: scratch +.macro TileLineNorm + ands r4, r0, r2, lsr #12 @ #0x0000f000 + orrne r4, r3, r4 + strneb r4, [r1] + ands r4, r0, r2, lsr #8 @ #0x00000f00 + orrne r4, r3, r4 + strneb r4, [r1,#1] + ands r4, r0, r2, lsr #4 @ #0x000000f0 + orrne r4, r3, r4 + strneb r4, [r1,#2] + ands r4, r0, r2 @ #0x0000000f + orrne r4, r3, r4 + strneb r4, [r1,#3] + ands r4, r0, r2, lsr #28 @ #0xf0000000 + orrne r4, r3, r4 + strneb r4, [r1,#4] + ands r4, r0, r2, lsr #24 @ #0x0f000000 + orrne r4, r3, r4 + strneb r4, [r1,#5] + ands r4, r0, r2, lsr #20 @ #0x00f00000 + orrne r4, r3, r4 + strneb r4, [r1,#6] + ands r4, r0, r2, lsr #16 @ #0x000f0000 + orrne r4, r3, r4 + strneb r4, [r1,#7] +.endm + +@ TileFlip (r1=pdest, r2=pixels8, r3=pal) r0,r4: scratch +.macro TileLineFlip + ands r4, r0, r2, lsr #16 @ #0x000f0000 + orrne r4, r3, r4 + strneb r4, [r1] + ands r4, r0, r2, lsr #20 @ #0x00f00000 + orrne r4, r3, r4 + strneb r4, [r1,#1] + ands r4, r0, r2, lsr #24 @ #0x0f000000 + orrne r4, r3, r4 + strneb r4, [r1,#2] + ands r4, r0, r2, lsr #28 @ #0xf0000000 + orrne r4, r3, r4 + strneb r4, [r1,#3] + ands r4, r0, r2 @ #0x0000000f + orrne r4, r3, r4 + strneb r4, [r1,#4] + ands r4, r0, r2, lsr #4 @ #0x000000f0 + orrne r4, r3, r4 + strneb r4, [r1,#5] + ands r4, r0, r2, lsr #8 @ #0x00000f00 + orrne r4, r3, r4 + strneb r4, [r1,#6] + ands r4, r0, r2, lsr #12 @ #0x0000f000 + orrne r4, r3, r4 + strneb r4, [r1,#7] +.endm + +@ Tile (r1=pdest, r3=pal, r9=prevcode, r10=Pico.vram) r2,r4,r7: scratch, r0=0xf +.macro Tile hflip vflip + mov r7, r9, lsl #13 @ r9=code<<8; addr=(code&0x7ff)<<4; + add r7, r10, r7, lsr #16 + orr r9, r9, #3 @ emptytile=singlecolor=1, r9 must be 00000xxx +.if \vflip + @ we read tilecodes in reverse order if we have vflip + add r7, r7, #8*4 +.endif + @ loop through 8 lines + orr r9, r9, #(7<<24) + b 1f @ loop_enter + +0: @ singlecol_loop + subs r9, r9, #(1<<24) + add r1, r1, #328 @ set pointer to next line + bmi 8f @ loop_exit with r0 restore +1: +.if \vflip + ldr r2, [r7, #-4]! @ pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels +.else + ldr r2, [r7], #4 +.endif + tst r2, r2 + beq 2f @ empty line + bic r9, r9, #1 + cmp r2, r2, ror #4 + bne 3f @ not singlecolor + TileLineSinglecol + b 0b + +2: + bic r9, r9, #2 +2: @ empty_loop + subs r9, r9, #(1<<24) + add r1, r1, #328 @ set pointer to next line + bmi 8f @ loop_exit with r0 restore +.if \vflip + ldr r2, [r7, #-4]! @ next pack +.else + ldr r2, [r7], #4 +.endif + mov r0, #0xf @ singlecol_loop might have messed r0 + tst r2, r2 + beq 2b + + bic r9, r9, #3 @ if we are here, it means we have empty and not empty line + b 5f + +3: @ not empty, not singlecol + mov r0, #0xf + bic r9, r9, #3 + b 6f + +4: @ not empty, not singlecol loop + subs r9, r9, #(1<<24) + add r1, r1, #328 @ set pointer to next line + bmi 9f @ loop_exit +.if \vflip + ldr r2, [r7, #-4]! @ next pack +.else + ldr r2, [r7], #4 +.endif + tst r2, r2 + beq 4b @ empty line +5: + cmp r2, r2, ror #4 + beq 7f @ singlecolor line +6: +.if \hflip + TileLineFlip +.else + TileLineNorm +.endif + b 4b +7: + TileLineSinglecol 1 + b 4b + +8: + mov r0, #0xf +9: @ loop_exit + add r9, r9, #(1<<24) @ fix r9 + sub r1, r1, #328*8 @ restore pdest pointer +.endm + + +@ TileLineSinglecolAl (r1=pdest, r4,r7=color) +.macro TileLineSinglecolAl0 + stmia r1!, {r4,r7} + add r1, r1, #320 +.endm + +.macro TileLineSinglecolAl1 + strb r4, [r1], #1 + strh r4, [r1], #2 + str r4, [r1], #4 + strb r4, [r1], #1+320 +@ add r1, r1, #320 +.endm + +.macro TileLineSinglecolAl2 + strh r4, [r1], #2 + str r4, [r1], #4 + strh r4, [r1], #2 + add r1, r1, #320 +.endm + +.macro TileLineSinglecolAl3 + strb r4, [r1], #1 + str r4, [r1], #4 + strh r4, [r1], #2 + strb r4, [r1], #1+320 +@ add r1, r1, #320 +.endm + +@ TileSinglecol (r1=pdest, r2=pixels8, r3=pal) r4,r7: scratch, r0=0xf +@ kaligned==1, if dest is always aligned +.macro TileSinglecol kaligned=0 + and r4, r2, #0xf @ we assume we have good r2 from previous time + orr r4, r4, r3 + orr r4, r4, r4, lsl #8 + orr r4, r4, r4, lsl #16 + mov r7, r4 + +.if !\kaligned + tst r1, #2 @ not aligned? + bne 2f + tst r1, #1 + bne 1f +.endif + + TileLineSinglecolAl0 + TileLineSinglecolAl0 + TileLineSinglecolAl0 + TileLineSinglecolAl0 + TileLineSinglecolAl0 + TileLineSinglecolAl0 + TileLineSinglecolAl0 + TileLineSinglecolAl0 + +.if !\kaligned + b 4f +1: + TileLineSinglecolAl1 + TileLineSinglecolAl1 + TileLineSinglecolAl1 + TileLineSinglecolAl1 + TileLineSinglecolAl1 + TileLineSinglecolAl1 + TileLineSinglecolAl1 + TileLineSinglecolAl1 + b 4f + +2: + tst r1, #1 + bne 3f + + TileLineSinglecolAl2 + TileLineSinglecolAl2 + TileLineSinglecolAl2 + TileLineSinglecolAl2 + TileLineSinglecolAl2 + TileLineSinglecolAl2 + TileLineSinglecolAl2 + TileLineSinglecolAl2 + b 4f + +3: + TileLineSinglecolAl3 + TileLineSinglecolAl3 + TileLineSinglecolAl3 + TileLineSinglecolAl3 + TileLineSinglecolAl3 + TileLineSinglecolAl3 + TileLineSinglecolAl3 + TileLineSinglecolAl3 + +4: +.endif + sub r1, r1, #328*8 @ restore pdest pointer +.endm + + + +@ DrawLayerTiles(*hcache, *scrpos, (cells<<24)|(nametab<<9)|(vscroll&0x3ff)<<11|(shift[width]<<8)|planeend, (ymask<<24)|(planestart<<16)|[htab||hscroll] + +@static void DrawLayerFull(int plane, int *hcache, int planestart, int planeend) + +.global DrawLayerFull + +DrawLayerFull: + stmfd sp!, {r4-r11,lr} + + mov r6, r1 @ hcache + + sub lr, r3, r2 + and lr, lr, #0x00ff0000 @ lr=cells + + ldr r10, =(Pico+0x10000) @ r10=Pico.vram + + ldr r11, =(Pico+0x22228) @ Pico.video + ldrb r5, [r11, #13] @ pvid->reg[13] + mov r5, r5, lsl #10 @ htab=pvid->reg[13]<<9; (halfwords) + add r5, r5, r0, lsl #1 @ htab+=plane + bic r5, r5, #0x00ff0000 @ just in case + + ldrb r7, [r11, #11] + tst r7, #3 @ full screen scroll? (if ==0) + ldreqh r5, [r10, r5] + biceq r5, r5, #0x0000fc00 @ r5=hscroll (0-0x3ff) + movne r5, r5, lsr #1 + orrne r5, r5, #0x8000 @ this marks that we have htab pointer, not hscroll here + + ldrb r7, [r11, #16] @ ??hh??ww + and r8, r7, #3 + + orr r5, r5, r7, lsl #1+24 + orr r5, r5, #0x1f000000 + cmp r8, #1 + biclt r5, r5, #0x80000000 + biceq r5, r5, #0xc0000000 + bicgt r5, r5, #0xe0000000 + + mov r9, r2, lsl #24 + orr r5, r5, r9, lsr #8 @ r5=(ymask<<24)|(trow<<16)|[htab||hscroll] + + add r4, r8, #5 + cmp r4, #7 + subge r4, r4, #1 @ r4=shift[width] (5,6,6,7) + + orr lr, lr, r4 + orr lr, lr, r3, lsl #24 @ lr=(planeend<<24)|(cells<<16)|shift[width] + + @ calculate xmask: + mov r8, r8, lsl #24+5 + orr r8, r8, #0x1f000000 + + @ Find name table: + tst r0, r0 + ldreqb r4, [r11, #2] + moveq r4, r4, lsr #3 + ldrneb r4, [r11, #4] + and r4, r4, #7 + orr lr, lr, r4, lsl #13 @ lr|=nametab_bits{3}<<13 + + ldr r11, =framebuff @ r11=framebuff + ldr r11, [r11] + sub r4, r9, #(START_ROW<<24) + mov r4, r4, asr #24 + mov r7, #328*8 + mla r11, r4, r7, r11 @ scrpos+=8*328*(planestart-START_ROW); + + @ Get vertical scroll value: + add r7, r10, #0x012000 + add r7, r7, #0x000180 @ r7=Pico.vsram (Pico+0x22180) + ldr r7, [r7] + tst r0, r0 + moveq r7, r7, lsl #22 + movne r7, r7, lsl #6 + mov r7, r7, lsr #22 @ r7=vscroll (10 bits) + + orr lr, lr, r7, lsl #3 + mov lr, lr, ror #24 @ packed: cccccccc nnnvvvvv vvvvvsss pppppppp: cells, nametab, vscroll, shift[width], planeend + + ands r7, r7, #7 + addne lr, lr, #1 @ we have vertically clipped tiles due to vscroll, so we need 1 more row + + rsb r7, r7, #8 + str r7, [r6], #4 @ push y-offset to tilecache + mov r4, #328 + mla r11, r4, r7, r11 @ scrpos+=(8-(vscroll&7))*328; + + mov r9, #0xff000000 @ r9=(prevcode<<8)|flags: 1~tile empty, 2~tile singlecolor + +.rtrloop_outer: + mov r4, lr, lsl #11 + mov r4, r4, lsr #25 @ r4=vscroll>>3 (7 bits) + add r4, r4, r5, lsr #16 @ +trow + and r4, r4, r5, lsr #24 @ &=ymask + mov r7, lr, lsr #8 + and r7, r7, #7 @ shift[width] + mov r0, lr, lsr #9 + and r0, r0, #0x7000 @ nametab + add r12,r0, r4, lsl r7 @ nametab_row = nametab + (((trow+(vscroll>>3))&ymask)<hscroll)>>3 + mov r4, r4, asr #3 + and r4, r4, #0xff + and r8, r8, #0xff000000 + orr r8, r8, r4 @ r8=(xmask<<24)|tilex + + sub r7, r7, #1 + and r7, r7, #7 + add r7, r7, #1 @ r7=dx=((ts->hscroll-1)&7)+1 + + cmp r7, #8 + subeq r12,r12, #0x01000000 @ we will loop cells+1 times, so loop less when there is no hscroll + + add r1, r11, r7 @ r1=pdest + mov r0, #0xf + b .rtrloop_enter + + @ r4 & r7 are scratch in this loop +.rtrloop: @ 40-41 times + add r1, r1, #8 + subs r12,r12, #0x01000000 + add r8, r8, #1 + bmi .rtrloop_exit + +.rtrloop_enter: + and r7, r8, r8, lsr #24 + add r7, r10, r7, lsl #1 + bic r4, r12, #0xff000000 @ Pico.vram[nametab_row+(tilex&xmask)]; + ldrh r7, [r7, r4] @ r7=code (int, but from unsigned, no sign extend) + + tst r7, #0x8000 + bne .rtr_hiprio + + cmp r7, r9, lsr #8 + bne .rtr_notsamecode + @ we know stuff about this tile already + tst r9, #1 + bne .rtrloop @ empty tile + tst r9, #2 + bne .rtr_singlecolor @ singlecolor tile + b .rtr_samecode + +.rtr_notsamecode: + and r4, r9, #0x600000 + mov r9, r7, lsl #8 @ remember new code + + @ update cram + and r7, r7, #0x6000 + mov r3, r7, asr #9 @ r3=pal=((code&0x6000)>>9); + +.rtr_samecode: + tst r9, #0x100000 @ vflip? + bne .rtr_vflip + + tst r9, #0x080000 @ hflip? + bne .rtr_hflip + + @ Tile (r1=pdest, r3=pal, r9=prevcode, r10=Pico.vram) r2,r4,r7: scratch, r0=0xf + Tile 0, 0 + b .rtrloop + +.rtr_hflip: + Tile 1, 0 + b .rtrloop + +.rtr_vflip: + tst r9, #0x080000 @ hflip? + bne .rtr_vflip_hflip + + Tile 0, 1 + b .rtrloop + +.rtr_vflip_hflip: + Tile 1, 1 + b .rtrloop + +.rtr_singlecolor: + TileSinglecol + b .rtrloop + +.rtr_hiprio: + @ *(*hcache)++ = code|(dx<<16)|(trow<<27); + sub r4, r1, r11 + orr r7, r7, r4, lsl #16 + and r4, r5, #0x00ff0000 + orr r7, r7, r4, lsl #11 @ (trow<<27) + str r7, [r6], #4 @ cache hi priority tile + b .rtrloop + +.rtrloop_exit: + add r5, r5, #0x00010000 + mov r4, r5, lsl #8 + cmp r4, lr, lsl #24 + bge .rtrloop_outer_exit + add r11, r11, #328*8 + b .rtrloop_outer + +.rtrloop_outer_exit: + + @ terminate cache list + mov r0, #0 + str r0, [r6] @ save cache pointer + + ldmfd sp!, {r4-r11,lr} + bx lr + +.pool + + + +.global DrawTilesFromCacheF @ int *hc + +DrawTilesFromCacheF: + stmfd sp!, {r4-r10,lr} + + mov r9, #0xff000000 @ r9=prevcode=-1 + mvn r6, #0 @ r6=prevy=-1 + + ldr r4, =framebuff @ r4=framebuff + ldr r4, [r4] + ldr r1, [r0], #4 @ read y offset + mov r7, #328 + mla r1, r7, r1, r4 + sub r12, r1, #(328*8*START_ROW) @ r12=scrpos + + ldr r10, =(Pico+0x10000) @ r10=Pico.vram + mov r8, r0 @ hc + mov r0, #0xf + + @ scratch: r4, r7 + @ *hcache++ = code|(dx<<16)|(trow<<27); // cache it + +.dtfcf_loop: + ldr r7, [r8], #4 @ read code + movs r1, r7, lsr #16 @ r1=dx; + ldmeqfd sp!, {r4-r10,pc} @ dx is never zero, this must be a terminator, return + + @ trow changed? + cmp r6, r7, lsr #27 + movne r6, r7, lsr #27 + movne r4, #328*8 + mlane r5, r4, r6, r12 @ r5=pd = scrpos + prevy*328*8 + + bic r1, r1, #0xf800 + add r1, r5, r1 @ r1=pdest (halfwords) + + mov r7, r7, lsl #16 + mov r7, r7, lsr #16 + + cmp r7, r9, lsr #8 + bne .dtfcf_notsamecode + @ we know stuff about this tile already + tst r9, #1 + bne .dtfcf_loop @ empty tile + tst r9, #2 + bne .dtfcf_singlecolor @ singlecolor tile + b .dtfcf_samecode + +.dtfcf_notsamecode: + and r4, r9, #0x600000 + mov r9, r7, lsl #8 @ remember new code + + @ update cram val + and r7, r7, #0x6000 + mov r3, r7, asr #9 @ r3=pal=((code&0x6000)>>9); + + +.dtfcf_samecode: + + tst r9, #0x100000 @ vflip? + bne .dtfcf_vflip + + tst r9, #0x080000 @ hflip? + bne .dtfcf_hflip + + @ Tile (r1=pdest, r3=pal, r9=prevcode, r10=Pico.vram) r2,r4,r7: scratch, r0=0xf + Tile 0, 0 + b .dtfcf_loop + +.dtfcf_hflip: + Tile 1, 0 + b .dtfcf_loop + +.dtfcf_vflip: + tst r9, #0x080000 @ hflip? + bne .dtfcf_vflip_hflip + + Tile 0, 1 + b .dtfcf_loop + +.dtfcf_vflip_hflip: + Tile 1, 1 + b .dtfcf_loop + +.dtfcf_singlecolor: + TileSinglecol + b .dtfcf_loop + +.pool + + +@ @@@@@@@@@@@@@@@ + +@ (tile_start<<16)|row_start +.global DrawWindowFull @ int tstart, int tend, int prio + +DrawWindowFull: + stmfd sp!, {r4-r11,lr} + + ldr r11, =(Pico+0x22228) @ Pico.video + ldrb r12, [r11, #3] @ pvid->reg[3] + mov r12, r12, lsl #10 + + ldr r4, [r11, #12] + mov r5, #1 @ nametab_step + tst r4, #1 @ 40 cell mode? + andne r12, r12, #0xf000 @ 0x3c<<10 + andeq r12, r12, #0xf800 + movne r5, r5, lsl #7 + moveq r5, r5, lsl #6 @ nametab_step + + and r4, r0, #0xff + mla r12, r5, r4, r12 @ nametab += nametab_step*start; + + mov r4, r0, lsr #16 @ r4=start_cell_h + add r7, r12, r4, lsl #1 + + @ fetch the first code now + ldr r10, =(Pico+0x10000) @ lr=Pico.vram + ldrh r7, [r10, r7] + cmp r2, r7, lsr #15 + ldmnefd sp!, {r4-r11,pc} @ hack: simply assume that whole window uses same priority + + rsb r8, r4, r1, lsr #16 @ cells (h) + orr r8, r8, r4, lsl #8 + mov r4, r1, lsl #24 + sub r4, r4, r0, lsl #24 + orr r8, r8, r4, lsr #8 @ r8=cells_h|(start_cell_h<<8)|(cells_v<<16) + sub r8, r8, #0x010000 @ adjust for algo + + mov r9, #0xff000000 @ r9=prevcode=-1 + + ldr r11, =framebuff @ r11=scrpos + ldr r11, [r11] + add r11, r11, #328*8 + add r11, r11, #8 + + and r4, r0, #0xff + sub r4, r4, #START_ROW + mov r7, #328*8 + mla r11, r7, r4, r11 @ scrpos+=8*328*(start-START_ROW); + mov r0, #0xf + +.dwfloop_outer: + and r6, r8, #0xff00 @ r6=tilex + add r1, r11, r6, lsr #5 @ r1=pdest + add r6, r12, r6, lsr #7 + add r6, r10, r6 @ r6=Pico.vram+nametab+tilex + orr r8, r8, r8, lsl #24 + sub r8, r8, #0x01000000 @ cell loop counter + b .dwfloop_enter + + @ r4 & r7 are scratch in this loop +.dwfloop: + add r1, r1, #8 + subs r8, r8, #0x01000000 + bmi .dwfloop_exit + +.dwfloop_enter: + ldrh r7, [r6], #2 @ r7=code + + cmp r7, r9, lsr #8 + bne .dwf_notsamecode + @ we know stuff about this tile already + tst r9, #1 + bne .dwfloop @ empty tile + tst r9, #2 + bne .dwf_singlecolor @ singlecolor tile + b .dwf_samecode + +.dwf_notsamecode: + and r4, r9, #0x600000 + mov r9, r7, lsl #8 @ remember new code + + @ update cram val + and r7, r7, #0x6000 + mov r3, r7, asr #9 @ r3=pal=((code&0x6000)>>9); + +.dwf_samecode: + + tst r9, #0x100000 @ vflip? + bne .dwf_vflip + + tst r9, #0x080000 @ hflip? + bne .dwf_hflip + + @ Tile (r1=pdest, r3=pal, r9=prevcode, r10=Pico.vram) r2,r4,r7: scratch, r0=0xf + Tile 0, 0 + b .dwfloop + +.dwf_hflip: + Tile 1, 0 + b .dwfloop + +.dwf_vflip: + tst r9, #0x080000 @ hflip? + bne .dwf_vflip_hflip + + Tile 0, 1 + b .dwfloop + +.dwf_vflip_hflip: + Tile 1, 1 + b .dwfloop + +.dwf_singlecolor: + TileSinglecol 1 + b .dwfloop + +.dwfloop_exit: + bic r8, r8, #0xff000000 @ fix r8 + subs r8, r8, #0x010000 + ldmmifd sp!, {r4-r11,pc} + add r11, r11, #328*8 + add r12, r12, r5 @ nametab+=nametab_step + b .dwfloop_outer + +.pool + + +@ ---------------- sprites --------------- + +.macro SpriteLoop hflip vflip +.if \vflip + mov r1, r5, lsr #24 @ height + mov r0, #328*8 + mla r11, r1, r0, r11 @ scrpos+=height*328*8; + add r12, r12, r1, lsl #3 @ sy+=height*8 +.endif + mov r0, #0xf +.if \hflip + and r1, r5, #0xff + add r8, r8, r1, lsl #3 @ sx+=width*8 +58: + cmp r8, #336 + blt 51f + add r9, r9, r5, lsr #16 + sub r5, r5, #1 @ sub width + sub r8, r8, #8 + b 58b +.else + cmp r8, #0 @ skip tiles hidden on the left of screen + bgt 51f +58: + add r9, r9, r5, lsr #16 + sub r5, r5, #1 + adds r8, r8, #8 + ble 58b + b 51f +.endif + +50: @ outer +.if !\hflip + add r8, r8, #8 @ sx+=8 +.endif + bic r5, r5, #0xff000000 @ fix height + orr r5, r5, r5, lsl #16 + +51: @ outer_enter + sub r5, r5, #1 @ width-- + movs r1, r5, lsl #24 + ldmmifd sp!, {r4-r11,pc} @ end of tile +.if \hflip + subs r8, r8, #8 @ sx-=8 + ldmlefd sp!, {r4-r11,pc} @ tile offscreen +.else + cmp r8, #328 + ldmgefd sp!, {r4-r11,pc} @ tile offscreen +.endif + mov r6, r12 @ r6=sy + add r1, r11, r8 @ pdest=scrpos+sx + b 53f + +52: @ inner + add r9, r9, #1<<8 @ tile++ +.if !\vflip + add r6, r6, #8 @ sy+=8 + add r1, r1, #328*8 +.endif + +53: @ inner_enter + @ end of sprite? + subs r5, r5, #0x01000000 + bmi 50b @ ->outer +.if \vflip + sub r6, r6, #8 @ sy-=8 + sub r1, r1, #328*8 +.endif + + @ offscreen? + cmp r6, #(START_ROW*8) + ble 52b + + cmp r6, #(END_ROW*8+8) + bge 52b + + @ Tile (r1=pdest, r3=pal, r9=prevcode, r10=Pico.vram) r2,r4,r7: scratch, r0=0xf + Tile \hflip, \vflip + b 52b +.endm + + +.global DrawSpriteFull @ unsigned int *sprite + +DrawSpriteFull: + stmfd sp!, {r4-r11,lr} + + ldr r3, [r0] @ sprite[0] + mov r5, r3, lsl #4 + mov r6, r5, lsr #30 + add r6, r6, #1 @ r6=width + mov r5, r5, lsl #2 + mov r5, r5, lsr #30 + add r5, r5, #1 @ r5=height + + mov r12, r3, lsl #23 + mov r12, r12, lsr #23 + sub r12, r12, #0x78 @ r12=sy + + ldr lr, [r0, #4] @ lr=code + mov r8, lr, lsl #7 + mov r8, r8, lsr #23 + sub r8, r8, #0x78 @ r8=sx + + mov r9, lr, lsl #21 + mov r9, r9, lsr #13 @ r9=tile<<8 + + and r3, lr, #0x6000 + mov r3, r3, lsr #9 @ r3=pal=((code>>9)&0x30); + + ldr r10, =(Pico+0x10000) @ r10=Pico.vram + + ldr r11, =framebuff @ r11=scrpos + ldr r11, [r11] + sub r1, r12, #(START_ROW*8) + mov r0, #328 + mla r11, r1, r0, r11 @ scrpos+=(sy-START_ROW*8)*328; + + orr r5, r5, r5, lsl #16 @ + orr r5, r6, r5, lsl #8 @ r5=width|(height<<8)|(height<<24) + + tst lr, #0x1000 @ vflip? + bne .dsf_vflip + + tst lr, #0x0800 @ hflip? + bne .dsf_hflip + + SpriteLoop 0, 0 + +.dsf_hflip: + SpriteLoop 1, 0 + +.dsf_vflip: + tst lr, #0x0800 @ hflip? + bne .dsf_vflip_hflip + + SpriteLoop 0, 1 + +.dsf_vflip_hflip: + SpriteLoop 1, 1 + +.pool + + diff --git a/Pico/Draw_.s b/Pico/Draw_.s new file mode 100644 index 00000000..ccfdbe24 --- /dev/null +++ b/Pico/Draw_.s @@ -0,0 +1,1423 @@ +@ assembly "optimized" version of some funtions from draw.c +@ this is highly specialized, be careful if changing related C code! + +@ (c) Copyright 2006, notaz +@ All Rights Reserved + + +.extern Pico +.extern PicoOpt +.extern HighCol +.extern Scanline +.extern HighSprZ +.extern rendstatus +.extern DrawLineDest +.extern DrawStripVSRam +.extern DrawStripInterlace + + +@ helper +.macro TilePixel pat lsrr offs +.if !\lsrr + ands r4, \pat, r2 +.else + ands r4, \pat, r2, lsr #\lsrr +.endif + orrne r4, r3, r4 + strneb r4, [r1,#\offs] +.endm + +@ TileNorm (r1=pdest, r2=pixels8, r3=pal) r4: scratch, pat: register with helper pattern 0xf +.macro TileNorm pat + TilePixel \pat, 12, 0 @ #0x0000f000 + TilePixel \pat, 8, 1 @ #0x00000f00 + TilePixel \pat, 4, 2 @ #0x000000f0 + TilePixel \pat, 0, 3 @ #0x0000000f + TilePixel \pat, 28, 4 @ #0xf0000000 + TilePixel \pat, 24, 5 @ #0x0f000000 + TilePixel \pat, 20, 6 @ #0x00f00000 + TilePixel \pat, 16, 7 @ #0x000f0000 +.endm + +@ TileFlip (r1=pdest, r2=pixels8, r3=pal) r4: scratch, pat: register with helper pattern 0xf +.macro TileFlip pat + TilePixel \pat, 16, 0 @ #0x000f0000 + TilePixel \pat, 20, 1 @ #0x00f00000 + TilePixel \pat, 24, 2 @ #0x0f000000 + TilePixel \pat, 28, 3 @ #0xf0000000 + TilePixel \pat, 0, 4 @ #0x0000000f + TilePixel \pat, 4, 5 @ #0x000000f0 + TilePixel \pat, 8, 6 @ #0x00000f00 + TilePixel \pat, 12, 7 @ #0x0000f000 +.endm + +@ shadow/hilight mode + +@ this one is for hi priority layer +.macro TilePixelShHP pat lsrr offs + TilePixel \pat, \lsrr, \offs + ldreqb r4, [r1,#\offs] + tsteq r4, #0x80 + andeq r4, r4, #0x3f + streqb r4, [r1,#\offs] +.endm + +@ TileNorm (r1=pdest, r2=pixels8, r3=pal) r4: scratch, pat: register with helper pattern 0xf +.macro TileNormShHP pat + TilePixelShHP \pat, 12, 0 @ #0x0000f000 + TilePixelShHP \pat, 8, 1 @ #0x00000f00 + TilePixelShHP \pat, 4, 2 @ #0x000000f0 + TilePixelShHP \pat, 0, 3 @ #0x0000000f + TilePixelShHP \pat, 28, 4 @ #0xf0000000 + TilePixelShHP \pat, 24, 5 @ #0x0f000000 + TilePixelShHP \pat, 20, 6 @ #0x00f00000 + TilePixelShHP \pat, 16, 7 @ #0x000f0000 +.endm + +@ TileFlip (r1=pdest, r2=pixels8, r3=pal) r4: scratch, pat: register with helper pattern 0xf +.macro TileFlipShHP pat + TilePixelShHP \pat, 16, 0 @ #0x000f0000 + TilePixelShHP \pat, 20, 1 @ #0x00f00000 + TilePixelShHP \pat, 24, 2 @ #0x0f000000 + TilePixelShHP \pat, 28, 3 @ #0xf0000000 + TilePixelShHP \pat, 0, 4 @ #0x0000000f + TilePixelShHP \pat, 4, 5 @ #0x000000f0 + TilePixelShHP \pat, 8, 6 @ #0x00000f00 + TilePixelShHP \pat, 12, 7 @ #0x0000f000 +.endm + + +@ TileSingleSh (r1=pdest, r2=pixels8, r3=pal) r4,r7: scratch, r0=sx; r12: helper pattern 0xf +.macro TileSingleSh + tst r0, #1 @ not aligned? + mov r7, #0x00c000 + orr r7, r7, #0xc0 + ldrneb r4, [r1] + ldreqh r4, [r1] + orr r4, r4, r7 + strneb r4, [r1], #1 + streqh r4, [r1], #2 + ldrh r4, [r1] + orr r4, r4, r7 + strh r4, [r1], #2 + ldrh r4, [r1] + orr r4, r4, r7 + strh r4, [r1], #2 + ldrh r4, [r1] + orr r4, r4, r7 + strh r4, [r1], #2 + ldrneb r4, [r1] + orr r4, r4, r7 + strneb r4, [r1], #1 +.endm + +@ TileSingleHi (r1=pdest, r2=pixels8, r3=pal) r4,r7: scratch, r0=sx, r12: register with helper pattern 0xf +.macro TileSingleHi + tst r1, #1 @ not aligned? + mov r7, #0x008000 + orr r7, r7, #0x80 + ldrneb r4, [r1] + ldreqh r4, [r1] + bic r4, r4, r7, lsr #1 + orr r4, r4, r7 + strneb r4, [r1], #1 + streqh r4, [r1], #2 + ldrh r4, [r1] + bic r4, r4, r7, lsr #1 + orr r4, r4, r7 + strh r4, [r1], #2 + ldrh r4, [r1] + bic r4, r4, r7, lsr #1 + orr r4, r4, r7 + strh r4, [r1], #2 + ldrh r4, [r1] + bic r4, r4, r7, lsr #1 + orr r4, r4, r7 + strh r4, [r1], #2 + ldrneb r4, [r1] + bic r4, r4, r7, lsr #1 + orr r4, r4, r7 + strneb r4, [r1], #1 +.endm + +.macro TileDoShGenPixel shift ofs +.if \shift + ands r4, r12, r2, lsr #\shift +.else + ands r4, r12, r2 +.endif + beq 3f + cmp r4, #0xe + beq 2f + bgt 1f + orr r4, r3, r4 + strb r4, [r1,#\ofs] + b 3f +1: + ldrb r4, [r1,#\ofs] + orr r4, r4, #0xc0 + strb r4, [r1,#\ofs] + b 3f +2: + ldrb r4, [r1,#\ofs] + bic r4, r4, #0xc0 + orr r4, r4, #0x80 + strb r4, [r1,#\ofs] +3: +.endm + +@ TileFlipSh (r1=pdest, r2=pixels8, r3=pal) r4,r7: scratch, r0=sx, r12: register with helper pattern 0xf +.macro TileFlipSh + TileDoShGenPixel 16, 0 @ #0x000f0000 + TileDoShGenPixel 20, 1 @ #0x00f00000 + TileDoShGenPixel 24, 2 @ #0x0f000000 + TileDoShGenPixel 28, 3 @ #0xf0000000 + TileDoShGenPixel 0, 4 @ #0x0000000f + TileDoShGenPixel 4, 5 @ #0x000000f0 + TileDoShGenPixel 8, 6 @ #0x00000f00 + TileDoShGenPixel 12, 7 @ #0x0000f000 +.endm + +@ TileNormSh (r1=pdest, r2=pixels8, r3=pal) r4,r7: scratch, r0=sx, r12: register with helper pattern 0xf +.macro TileNormSh + TileDoShGenPixel 12, 0 @ #0x0000f000 + TileDoShGenPixel 8, 1 @ #0x00000f00 + TileDoShGenPixel 4, 2 @ #0x000000f0 + TileDoShGenPixel 0, 3 @ #0x0000000f + TileDoShGenPixel 28, 4 @ #0xf0000000 + TileDoShGenPixel 24, 5 @ #0x0f000000 + TileDoShGenPixel 20, 6 @ #0x00f00000 + TileDoShGenPixel 16, 7 @ #0x000f0000 +.endm + + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +@ struct TileStrip +@ { +@ int nametab; // 0x00 +@ int line; // 0x04 +@ int hscroll; // 0x08 +@ int xmask; // 0x0C +@ int *hc; // 0x10 (pointer to cache buffer) +@ int cells; // 0x14 +@ }; + +@ int DrawLayer(int plane, int *hcache, int maxcells, int sh) + +.global DrawLayer @ int plane, int *hcache, int maxcells, int sh + +DrawLayer: + stmfd sp!, {r4-r11,lr} + + ldr r11, =(Pico+0x22228) @ Pico.video + + mov r6, r1 @ hcache + orr r9, r2, r3, lsl #31 @ r9=maxcells|(sh<<31) + + ldrb r7, [r11, #16] @ ??hh??ww + + mov r1, r7, lsl #4 + orr r1, r1, #0x00ff + + and r10, r7, #3 + cmp r10, #1 + biclt r1, r1, #0xfc00 + biceq r1, r1, #0xfe00 + bicgt r1, r1, #0xff00 @ r1=ymask=(height<<8)|0xff; ...; // Y Mask in pixels + + add r10, r10, #5 + cmp r10, #7 + subge r10, r10, #1 @ r10=shift[width] (5,6,6,7) + + @ calculate xmask: + mov r8, #1 + mov r5, r8, lsl r10 + sub r5, r5, #1 @ r5=xmask + + @ Find name table: + tst r0, r0 + ldreqb r12, [r11, #2] + moveq r12, r12, lsl #10 + ldrneb r12, [r11, #4] + movne r12, r12, lsl #13 + and r12, r12, #(7<<13) @ r12=(ts->nametab<<1) (halfword compliant) + + ldr r2, =Scanline + ldr r2, [r2] + ldr lr, =(Pico+0x10000) @ lr=Pico.vram + + ldrh r8, [r11, #12] + mov r4, r8, lsr #8 @ pvid->reg[13] + mov r4, r4, lsl #10 @ htab=pvid->reg[13]<<9; (halfwords) + ldrb r7, [r11, #11] + tst r7, #2 + addne r4, r4, r2, lsl #2 @ htab+=Scanline<<1; // Offset by line + tst r7, #1 + biceq r4, r4, #0x1f @ htab&=~0xf; // Offset by tile + add r4, r4, r0, lsl #1 @ htab+=plane + bic r4, r4, #0x00ff0000 @ just in case + ldrh r3, [lr, r4] @ r3=hscroll + + tst r7, #4 + bne .DrawStrip_vsscroll + + @ Get vertical scroll value: + add r7, lr, #0x012000 + add r7, r7, #0x000180 @ r7=Pico.vsram (Pico+0x22180) + ldr r7, [r7] + + tst r8, #2 + tstne r8, #4 + bne .DrawStrip_interlace + + tst r0, r0 + movne r7, r7, lsr #16 + + @ Find the line in the name table + add r2, r2, r7 + and r2, r2, r1 + mov r4, r2, lsr #3 + add r10, r10, #1 @ shift[width]++ + add r12, r12, r4, lsl r10 @ nametab+=(ts.line>>3)<hscroll, r5=ts->xmask, r6=ts->hc, r9=ts->cells +@ mov r12,r1, lsl #1 @ r12=(ts->nametab<<1) (halfword compliant) + + and r10,r2, #7 + mov r10,r10, lsl #1 @ r10=ty=(ts->line&7)<<1; + orr r10,r10, r9, lsl #24 + + rsb r8, r3, #0 + mov r8, r8, lsr #3 @ r8=tilex=(-ts->hscroll)>>3 + + sub r1, r3, #1 + and r1, r1, #7 + add r7, r1, #1 @ r7=dx=((ts->hscroll-1)&7)+1 + + tst r9, #1<<31 + mov r3, #0 + orrne r10,r10, #1<<23 @ r10=(cells<<24|sh<<23|hi_not_empty<<22|ty) + movne r3, #0x40 @ default to shadowed pal on sh mode + + mvn r9, #0 @ r9=prevcode=-1 + + cmp r7, #8 + subeq r10,r10, #0x01000000 @ we will loop cells+1 times, so loop less when there is no scroll + + @ cache some stuff to avoid mem access + ldr r11,=HighCol + add r1, r11, r7 @ r1=pdest + mov r0, #0xf + b .dsloop_enter + + @ r4 & r7 are scratch in this loop +.dsloop: @ 40-41 times + add r1, r1, #8 +.dsloop_nor1: + subs r10,r10, #0x01000000 + add r8, r8, #1 + bmi .dsloop_exit + +.dsloop_enter: + and r7, r5, r8 + add r7, lr, r7, lsl #1 @ Pico.vram+((tilex&ts->xmask) as halfwords) + ldrh r7, [r7, r12] @ r7=code (int, but from unsigned, no sign extend) + + tst r7, #0x8000 + bne .DrawStrip_hiprio + + cmp r7, r9 + beq .DrawStrip_samecode @ we know stuff about this tile already + + mov r9, r7 @ remember code + + movs r2, r9, lsl #20 @ if (code&0x1000) + mov r2, r2, lsl #1 +@ bic r7, r10,#0xff000000 +@ add r2, r7, r2, lsr #17 @ r2=addr=(code&0x7ff)<<4; addr+=ty + add r2, r2, r10, lsl #17 + mov r2, r2, lsr #17 + eorcs r2, r2, #0x0e @ if (code&0x1000) addr^=0xe; + + bic r7, r3, #0x3f + and r3, r9, #0x6000 + add r3, r7, r3, lsr #9 @ r3=pal=((code&0x6000)>>9); + + ldr r2, [lr, r2, lsl #1] @ pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + +.DrawStrip_samecode: + tst r2, r2 + beq .dsloop @ tileline blank + + cmp r2, r2, ror #4 + beq .DrawStrip_SingleColor @ tileline singlecolor + + tst r9, #0x0800 + beq .DrawStrip_TileNorm + + @ (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r0: helper pattern + TileFlip r0 + b .dsloop + +.DrawStrip_TileNorm: + TileNorm r0 + b .dsloop + +.DrawStrip_SingleColor: + and r4, r2, #0xf + orr r4, r3, r4 + orr r4, r4, r4, lsl #8 + tst r1, #1 @ not aligned? + strneb r4, [r1], #1 + streqh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strneb r4, [r1], #1 @ have a remaining unaligned pixel? + b .dsloop_nor1 @ we incremeted r1 ourselves + +.DrawStrip_hiprio: + tst r10, #0x00c00000 + beq .DrawStrip_hiprio_maybempt + sub r0, r1, r11 + orr r7, r7, r0, lsl #16 + orr r7, r7, r10, lsl #25 @ (ty<<25) + tst r7, #0x1000 + eorne r7, r7, #7<<26 @ if(code&0x1000) cval^=7<<26; + str r7, [r6], #4 @ cache hi priority tile + mov r0, #0xf + b .dsloop + +.DrawStrip_hiprio_maybempt: + cmp r7, r9 + beq .dsloop @ must've been empty, otherwise we wouldn't get here + mov r9, r7 @ remember code + movs r2, r9, lsl #20 @ if (code&0x1000) + mov r2, r2, lsl #1 + add r2, r2, r10, lsl #17 + mov r2, r2, lsr #17 + eorcs r2, r2, #0x0e @ if (code&0x1000) addr^=0xe; + ldr r2, [lr, r2, lsl #1] @ pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + tst r2, r2 + orrne r10, r10, #1<<22 + bne .DrawStrip_hiprio + b .dsloop + +.dsloop_exit: + mov r0, #0 + str r0, [r6] @ terminate the cache list + + ldmfd sp!, {r4-r11,lr} + bx lr + + +.DrawStrip_vsscroll: + @ shit, we have 2-cell column based vscroll + @ let the c code handle this (for now) + + @ int nametab; // 0x00 + @ int line; // 0x04 + @ int hscroll; // 0x08 + @ int xmask; // 0x0C + @ int *hc; // 0x10 (pointer to cache buffer) + @ int cells; // 0x14 + + sub sp, sp, #6*4 + orr r2, r1, r10, lsl #24 @ ts.line=ymask|(shift[width]<<24); // save some stuff instead of line + mov r1, r0 @ plane + mov r0, r12, lsr #1 @ halfwords + and r9, r9, #0xff + stmia sp, {r0,r2,r3,r5,r6,r9} + + mov r0, sp + bl DrawStripVSRam @ struct TileStrip *ts, int plane + + add sp, sp, #6*4 + ldmfd sp!, {r4-r11,lr} + bx lr + +@ interlace mode 2? Sonic 2? +.DrawStrip_interlace: + tst r0, r0 + moveq r7, r7, lsl #21 + movne r7, r7, lsl #5 + + @ Find the line in the name table + add r2, r7, r2, lsl #22 @ r2=(vscroll+(Scanline<<1))<<21 (11 bits); + orr r1, r1, #0x80000000 + and r2, r2, r1, ror #10 @ &((ymask<<1)|1)<<21; + mov r2, r2, lsr #21 + mov r4, r2, lsr #4 + mov r12, r12, lsr #1 @ halfwords + add r0, r12, r4, lsl r10 @ nametab+=(ts.line>>4)<>9); + + ldr r2, [lr, r2, lsl #1] @ pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + +.dtfc_samecode: + tst r8, r8 + bne .dtfc_shadow + + tst r2, r2 + beq .dtfc_loop + + cmp r2, r2, ror #4 + beq .dtfc_SingleColor @ tileline singlecolor + + tst r5, #0x0800 + beq .dtfc_TileNorm + + @ (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r12: helper pattern + TileFlip r12 + b .dtfc_loop + +.dtfc_TileNorm: + TileNorm r12 + b .dtfc_loop + +.dtfc_SingleColor: + and r4, r2, #0xf + orr r4, r3, r4 + orr r4, r4, r4, lsl #8 + tst r1, #1 @ not aligned? + strneb r4, [r1], #1 + streqh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strneb r4, [r1], #1 @ have a remaining unaligned pixel? + b .dtfc_loop + +.dtfc_shadow: + tst r2, r2 + beq .dtfc_shadow_blank + + cmp r2, r2, ror #4 + beq .dtfc_SingleColor @ tileline singlecolor + + tst r5, #0x0800 + beq .dtfc_TileNormShHP + + @ (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r12: helper pattern + TileFlipShHP r12 + b .dtfc_loop + +.dtfc_TileNormShHP: + TileNormShHP r12 + b .dtfc_loop + +.dtfc_shadow_blank: + ldrb r4, [r1] + tst r4, #0x80 + andeq r4, r4,#0x3f + streqb r4, [r1] + ldrb r4, [r1,#1] + tst r4, #0x80 + andeq r4, r4,#0x3f + streqb r4, [r1,#1] + ldrb r4, [r1,#2] + tst r4, #0x80 + andeq r4, r4,#0x3f + streqb r4, [r1,#2] + ldrb r4, [r1,#3] + tst r4, #0x80 + andeq r4, r4,#0x3f + streqb r4, [r1,#3] + ldrb r4, [r1,#4] + tst r4, #0x80 + andeq r4, r4,#0x3f + streqb r4, [r1,#4] + ldrb r4, [r1,#5] + tst r4, #0x80 + andeq r4, r4,#0x3f + streqb r4, [r1,#5] + ldrb r4, [r1,#6] + tst r4, #0x80 + andeq r4, r4,#0x3f + streqb r4, [r1,#6] + ldrb r4, [r1,#7] + tst r4, #0x80 + andeq r4, r4,#0x3f + streqb r4, [r1,#7] + b .dtfc_loop + +.pool + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + +.global DrawSpritesFromCache @ int *hc, int sh + +DrawSpritesFromCache: + stmfd sp!, {r4-r11,lr} + + @ cache some stuff to avoid mem access + ldr r11,=HighCol + ldr lr, =(Pico+0x10000) @ lr=Pico.vram + mov r6, r1, lsl #31 + orr r6, r6, #1<<30 + mov r12,#0xf + + mov r10, r0 + +.dsfc_loop: + ldr r9, [r10], #4 @ read code + tst r9, r9 + ldmeqfd sp!, {r4-r11,pc} + + mov r4, r9, lsl #28 + bic r6, r6, #7 + orr r6, r6, r4, lsr #30 + add r6, r6, #1 @ r6=s1cc???? ... ?????www (s=shadow/hilight, cc=pal, w=width) + + and r5, r9, #3 + add r5, r5, #1 @ r5=delta + tst r9, #0x10000 + rsbne r5, r5, #0 @ Flip X + mov r5, r5, lsl #4 + + mov r2, r9, lsr #17 + mov r8, r2, lsl #1 @ tile=((unsigned int)code>>17)<<1; + + and r3, r9, #0x30 @ r3=pal=(code&0x30); + + bic r6, r6, #3<<28 + orr r6, r6, r3, lsl #24 + + mov r0, r9, lsl #16 + mov r0, r0, asr #22 @ sx=(code<<16)>>22 + adds r0, r0, #0 @ set ZV + b .dsfc_inloop_enter + +@ scratch: r4, r7 +.dsfc_inloop: + sub r6, r6, #1 + tst r6, #7 + beq .dsfc_loop + adds r0, r0, #8 + add r8, r8, r5 + +.dsfc_inloop_enter: + ble .dsfc_inloop + cmp r0, #328 + bge .dsfc_loop + + mov r8, r8, lsl #17 + mov r8, r8, lsr #17 @ tile&=0x7fff; // Clip tile address + + ldr r2, [lr, r8, lsl #1] @ pack=*(unsigned int *)(Pico.vram+tile); // Get 8 pixels + tst r2, r2 + beq .dsfc_inloop + + add r1, r11, r0 @ r1=pdest + + cmp r12, r6, lsr #28 + beq .dsfc_shadow + + cmp r2, r2, ror #4 + beq .dsfc_SingleColor @ tileline singlecolor + + tst r9, #0x10000 + beq .dsfc_TileNorm + + @ TileFlip (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r12: helper pattern + TileFlip r12 + b .dsfc_inloop + +.dsfc_TileNorm: + TileNorm r12 + b .dsfc_inloop + +.dsfc_SingleColor: + tst r0, #1 @ not aligned? + and r4, r2, #0xf + orr r4, r3, r4 + orr r4, r4, r4, lsl #8 + strneb r4, [r1], #1 + streqh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strneb r4, [r1], #1 + b .dsfc_inloop + +.dsfc_shadow: + cmp r2, r2, ror #4 + beq .dsfc_singlec_sh + + tst r9, #0x10000 + beq .dsfc_TileNorm_sh + + @ (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r12: helper pattern + TileFlipSh + b .dsfc_inloop + +.dsfc_TileNorm_sh: + TileNormSh + b .dsfc_inloop + +.dsfc_singlec_sh: + cmp r2, #0xe0000000 + bcc .dsfc_SingleColor @ normal singlecolor tileline (carry inverted in ARM) + tst r2, #0x10000000 + bne .dsfc_sh_sh + TileSingleHi + b .dsfc_inloop + +.dsfc_sh_sh: + TileSingleSh + b .dsfc_inloop + +.pool + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +@ + 0 : hhhhvvvv ab--hhvv yyyyyyyy yyyyyyyy // a: offscreen h, b: offs. v, h: horiz. size +@ + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8 + +.global DrawSprite @ unsigned int *sprite, int **hc, int sh + +DrawSprite: + stmfd sp!, {r4-r9,r11,lr} + + ldr r3, [r0] @ sprite[0] + mov r6, r3, lsr #28 + sub r6, r6, #1 @ r6=width-1 (inc later) + mov r5, r3, lsr #24 + and r5, r5, #7 @ r5=height + + mov r4, r3, lsl #16 @ r4=sy<<16 (tmp) + + ldr r7, =Scanline + ldr r7, [r7] + sub r7, r7, r4, asr #16 @ r7=row=Scanline-sy + + tst r2, r2 + ldr r9, [r0, #4] + mov r2, r9, asr #16 @ r2=sx + bic r9, r9, #0xfe000000 + orrne r9, r9, #1<<31 @ r9=code|(sh<<31) + + tst r9, #0x1000 + movne r4, r5, lsl #3 + subne r4, r4, #1 + subne r7, r4, r7 @ if (code&0x1000) row=(height<<3)-1-row; // Flip Y + + mov r8, r9, lsl #21 + mov r8, r8, lsr #21 + add r8, r8, r7, lsr #3 @ tile+=row>>3; // Tile number increases going down + + tst r9, #0x0800 + mlane r8, r5, r6, r8 @ if (code&0x0800) { tile+=delta*(width-1); + rsbne r5, r5, #0 @ delta=-delta; } // r5=delta now + + mov r8, r8, lsl #4 + and r7, r7, #7 + add r8, r8, r7, lsl #1 @ tile+=(row&7)<<1; // Tile address + + tst r9, #0x8000 + bne .dspr_cache @ if(code&0x8000) // high priority - cache it + + @ cache some stuff to avoid mem access + ldr r11,=HighCol + ldr lr, =(Pico+0x10000) @ lr=Pico.vram + mov r12,#0xf + + mov r5, r5, lsl #4 @ delta<<=4; // Delta of address + and r4, r9, #0x6000 + orr r9, r9, r4, lsl #16 + orr r9, r9, #0x10000000 @ r9=scc1 ???? ... (s=shadow/hilight, cc=pal) + + tst r9, #1<<31 + mov r3, r4, lsr #9 @ r3=pal=((code>>9)&0x30); + orrne r3, r3, #0x40 @ shadow by default + + add r6, r6, #1 @ inc now + adds r0, r2, #0 @ mov sx to r0 and set ZV flags + b .dspr_loop_enter + +.dspr_loop: + subs r6, r6, #1 @ width-- + ldmeqfd sp!, {r4-r9,r11,pc}@ return + adds r0, r0, #8 @ sx+=8 + add r8, r8, r5 @ tile+=delta + +.dspr_loop_enter: + ble .dspr_loop @ sx <= 0 + cmp r0, #328 + ldmgefd sp!, {r4-r9,r11,pc}@ return + + mov r8, r8, lsl #17 + mov r8, r8, lsr #17 @ tile&=0x7fff; // Clip tile address + + ldr r2, [lr, r8, lsl #1] @ pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + tst r2, r2 + beq .dspr_loop + + add r1, r11, r0 @ r1=pdest + + cmp r12, r9, lsr #28 + beq .dspr_shadow + + cmp r2, r2, ror #4 + beq .dspr_SingleColor @ tileline singlecolor + + tst r9, #0x0800 + beq .dspr_TileNorm + + @ (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r12: helper pattern + TileFlip r12 + b .dspr_loop + +@ scratch: r4, r7 +.dspr_TileNorm: + TileNorm r12 + b .dspr_loop + +.dspr_SingleColor: + and r4, r2, #0xf + orr r4, r3, r4 + orr r4, r4, r4, lsl #8 + tst r0, #1 @ not aligned? + strneb r4, [r1], #1 + streqh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strneb r4, [r1], #1 + b .dspr_loop + +.dspr_shadow: + cmp r2, r2, ror #4 + beq .dspr_singlec_sh + + tst r9, #0x0800 + beq .dspr_TileNorm_sh + + @ (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r12: helper pattern + TileFlipSh + b .dspr_loop + +.dspr_TileNorm_sh: + TileNormSh + b .dspr_loop + +.dspr_singlec_sh: + cmp r2, #0xe0000000 + bcc .dspr_SingleColor @ normal tileline + tst r2, #0x10000000 + bne .dspr_sh_sh + TileSingleHi + b .dspr_loop + +.dspr_sh_sh: + TileSingleSh + b .dspr_loop + + +.dspr_cache: + @ *(*hc)++ = (tile<<16)|((code&0x0800)<<5)|((sx<<6)&0x0000ffc0)|((code>>9)&0x30)|((sprite[0]>>24)&0xf); + mov r4, r8, lsl #16 @ tile + tst r9, #0x0800 + orrne r4, r4, #0x10000 @ code&0x0800 + mov r2, r2, lsl #22 + orr r4, r4, r2, lsr #16 @ (sx<<6)&0x0000ffc0 + and r2, r9, #0x6000 + orr r4, r4, r2, lsr #9 @ (code>>9)&0x30 + mov r2, r3, lsl #12 + orr r4, r4, r2, lsr #28 @ (sprite[0]>>24)&0xf + + ldr r2, [r1] + str r4, [r2], #4 + str r2, [r1] + + ldmfd sp!, {r4-r9,r11,lr} + bx lr + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +.global DrawWindow @ int tstart, int tend, int prio, int sh // int *hcache + +DrawWindow: + stmfd sp!, {r4-r11,lr} + + ldr r11, =(Pico+0x22228) @ Pico.video + ldrb r12, [r11, #3] @ pvid->reg[3] + mov r12, r12, lsl #10 + + ldr r10, =Scanline + ldr r10, [r10] + mov r5, r10, lsr #3 + and r10, r10, #7 + mov r10, r10, lsl #1 @ r10=ty + + ldr r4, [r11, #12] + tst r4, #1 @ 40 cell mode? + andne r12, r12, #0xf000 @ 0x3c<<10 + andeq r12, r12, #0xf800 + addne r12, r12, r5, lsl #7 + addeq r12, r12, r5, lsl #6 @ nametab + add r12, r12, r0, lsl #2 @ +starttile + + ldr lr, =(Pico+0x10000) @ lr=Pico.vram + + @ fetch the first code now + ldrh r7, [lr, r12] + + ldr r6, =rendstatus + ldrb r6, [r6] + ands r6, r6, #2 @ we care about bit 1 only + orr r6, r6, r2 + bne .dw_no_sameprio + + cmp r2, r7, lsr #15 + ldmnefd sp!, {r4-r11,pc} @ assume that whole window uses same priority + +.dw_no_sameprio: + orr r6, r6, r3, lsl #8 @ shadow mode + + sub r8, r1, r0 + mov r8, r8, lsl #1 @ cells + + mvn r9, #0 @ r9=prevcode=-1 + + @ cache some stuff to avoid mem access + ldr r11,=(HighCol+8) + add r1, r11, r0, lsl #4 @ r1=pdest + mov r0, #0xf + b .dwloop_enter + + @ r4,r5 & r7 are scratch in this loop +.dwloop: + add r1, r1, #8 +.dwloop_nor1: + subs r8, r8, #1 + add r12, r12, #2 @ halfwords + beq .dwloop_end @ done + + ldrh r7, [lr, r12] @ r7=code (int, but from unsigned, no sign extend) + + eor r5, r6, r7, lsr #15 + tst r5, #1 + orrne r6, r6, #2 @ wrong pri + bne .dwloop + + cmp r7, r9 + beq .dw_samecode @ we know stuff about this tile already + +.dwloop_enter: + mov r9, r7 @ remember code + + movs r2, r9, lsl #20 @ if (code&0x1000) + mov r2, r2, lsl #1 + add r2, r10, r2, lsr #17 @ r2=addr=(code&0x7ff)<<4; addr+=ty + eorcs r2, r2, #0x0e @ if (code&0x1000) addr^=0xe; + + and r3, r9, #0x6000 + mov r3, r3, lsr #9 @ r3=pal=((code&0x6000)>>9); + + ldr r2, [lr, r2, lsl #1] @ pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + +.dw_samecode: + tst r6, #0x100 + bne .dw_shadow +.dw_shadow_done: + tst r2, r2 + beq .dwloop @ tileline blank + + cmp r2, r2, ror #4 + beq .dw_SingleColor @ tileline singlecolor + + tst r9, #0x0800 + beq .dw_TileNorm + + @ (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r0: helper pattern + TileFlip r0 + b .dwloop + +.dw_TileNorm: + TileNorm r0 + b .dwloop + +.dw_SingleColor: + and r4, r0, r2 @ #0x0000000f + orr r4, r3, r4 + orr r4, r4, r4, lsl #8 + orr r4, r4, r4, lsl #16 + mov r5, r4 + stmia r1!, {r4,r5} + b .dwloop_nor1 @ we incremeted r1 ourselves + +.dw_shadow: + tst r6, #1 @ hi pri? + orreq r3, r3, #0x40 + beq .dw_shadow_done + ldr r4, [r1] + tst r4, #0x00000080 + biceq r4, r4, #0x000000c0 + tst r4, #0x00008000 + biceq r4, r4, #0x0000c000 + tst r4, #0x00800000 + biceq r4, r4, #0x00c00000 + tst r4, #0x80000000 + biceq r4, r4, #0xc0000000 + str r4, [r1] + ldr r4, [r1,#4] + tst r4, #0x00000080 + biceq r4, r4, #0x000000c0 + tst r4, #0x00008000 + biceq r4, r4, #0x0000c000 + tst r4, #0x00800000 + biceq r4, r4, #0x00c00000 + tst r4, #0x80000000 + biceq r4, r4, #0xc0000000 + str r4, [r1,#4] + b .dw_shadow_done + +.dwloop_end: + ldr r0, =rendstatus + ldr r1, [r0] + and r6, r6, #2 + orr r1, r1, r6 + str r1, [r0] + + ldmfd sp!, {r4-r11,r12} + bx r12 + + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + +@ hilights 2 pixels in RGB444/BGR444 format +.macro TileDoShHi2Pixels444 reg + mov \reg, \reg, ror #12 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #28 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #28 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #24 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #28 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #28 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #12 +.endm + + +.global FinalizeLineBGR444 @ int sh + +FinalizeLineBGR444: + stmfd sp!, {r4-r6,lr} + mov r6, r0 + ldr r0, =DrawLineDest + ldr r0, [r0] + ldr lr, =(Pico+0x22228) @ Pico.video + sub r3, lr, #0x128 @ r3=Pico.cram + + ldrb r12, [lr, #12] + tst r12, #1 + movne r2, #320/4 @ len + moveq r2, #256/4 + addeq r0, r0, #32*2 + ldreq r4, =PicoOpt + ldreq r4, [r4] + tsteq r4, #0x100 + addeq r0, r0, #32*2 + + tst r6, r6 + beq .fl_noshBGR444 + + ldr r4, =HighPal + + ldrb r12, [lr, #-0x1a] @ 0x2220e ~ dirtyPal + tst r12, r12 + moveq r3, r4 + beq .fl_noshBGR444 + mov r12, #0 + strb r12, [lr, #-0x1a] + + mov lr, #0x40/8 + @ copy pal: +.fl_loopcpBGR444: + subs lr, lr, #1 + ldmia r3!, {r1,r5,r6,r12} + stmia r4!, {r1,r5,r6,r12} + bne .fl_loopcpBGR444 + + @ shadowed pixels: + mov r12, #0x0077 + orr r12,r12,#0x0700 + orr r12,r12,r12,lsl #16 + sub r3, r3, #0x40*2 + add r5, r4, #0x80*2 + mov lr, #0x40/4 +.fl_loopcpBGR444_sh: + subs lr, lr, #1 + ldmia r3!, {r1,r6} + and r1, r12, r1, lsr #1 + and r6, r12, r6, lsr #1 + stmia r4!, {r1,r6} + stmia r5!, {r1,r6} + bne .fl_loopcpBGR444_sh + + @ hilighted pixels: + sub r3, r3, #0x40*2 + mov lr, #0x40/2 +.fl_loopcpBGR444_hi: + ldr r1, [r3], #4 + TileDoShHi2Pixels444 r1 + str r1, [r4], #4 + subs lr, lr, #1 + bne .fl_loopcpBGR444_hi + + sub r3, r4, #0x40*3*2 + + +.fl_noshBGR444: + ldr r1, =(HighCol+8) + mov lr, #0xff + mov lr, lr, lsl #1 + +.fl_loopBGR444: + subs r2, r2, #1 + + ldr r12, [r1], #4 + + and r4, lr, r12, lsl #1 + ldrh r4, [r3, r4] + and r5, lr, r12, lsr #7 + ldrh r5, [r3, r5] + orr r4, r4, r5, lsl #16 + + and r5, lr, r12, lsr #15 + ldrh r5, [r3, r5] + and r6, lr, r12, lsr #23 + ldrh r6, [r3, r6] + orr r5, r5, r6, lsl #16 + + stmia r0!, {r4,r5} + bne .fl_loopBGR444 + + + ldmfd sp!, {r4-r6,lr} + bx lr + + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + +@ hilights 2 pixels in RGB555/BGR555 format +.macro TileDoShHi2Pixels555 reg + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #27 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #26 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #27 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #27 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #26 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #27 +.endm + + +@ Convert 0000bbb0 ggg0rrr0 +@ to rrrrrggg gggbbbbb + +@ r2,r3,r9 - scratch, lr = 0x001c001c, r8 = 0x00030003 +.macro convRGB565 reg + and r2, lr, \reg,lsl #1 + and r9, r8, \reg,lsr #2 + orr r2, r2, r9 @ r2=red + and r3, lr, \reg,lsr #7 + and r9, r8, \reg,lsr #10 + orr r3, r3, r9 @ r3=blue + and \reg, \reg, lr, lsl #3 + orr \reg, \reg, \reg,lsl #3 @ green + orr \reg, \reg, r2, lsl #11 @ add red back + orr \reg, \reg, r3 @ add blue back +.endm + +vidConvCpyRGB565: @ void *to, void *from, int pixels + stmfd sp!, {r4-r9,lr} + + mov r12, r2, lsr #3 @ repeats + mov lr, #0x001c0000 + orr lr, lr, #0x01c @ lr == pattern 0x001c001c + mov r8, #0x00030000 + orr r8, r8, #0x003 @ lr == pattern 0x001c001c + +.loopRGB565: + subs r12, r12, #1 + + ldmia r1!, {r4-r7} + convRGB565 r4 + str r4, [r0], #4 + convRGB565 r5 + str r5, [r0], #4 + convRGB565 r6 + str r6, [r0], #4 + convRGB565 r7 + str r7, [r0], #4 + + bgt .loopRGB565 + + ldmfd sp!, {r4-r9,lr} + bx lr + + + +.global FinalizeLineRGB555 @ int sh + +FinalizeLineRGB555: + stmfd sp!, {r4-r8,lr} + ldr r5, =(Pico+0x22228) @ Pico.video + ldr r4, =HighPal + mov r6, r0 + + ldrb r7, [r5, #-0x1a] @ 0x2220e ~ dirtyPal + tst r7, r7 + beq .fl_noconvRGB555 + mov r1, #0 + strb r1, [r5, #-0x1a] + sub r1, r5, #0x128 @ r1=Pico.cram + mov r0, r4 + mov r2, #0x40 + bl vidConvCpyRGB565 + +.fl_noconvRGB555: + ldr r0, =DrawLineDest + ldr r0, [r0] + + ldrb r12, [r5, #12] + tst r12, #1 + movne r2, #320/8 @ len + moveq r2, #256/8 + ldreq r3, =PicoOpt + ldreq r3, [r3] + tsteq r3, #0x100 + addeq r0, r0, #32*2 + + mov r3, r4 + tst r6, r6 + beq .fl_noshRGB555 + tst r7, r7 + beq .fl_noshRGB555 + + @ shadowed pixels: + mov r12, #0x008e + orr r12,r12,#0x7300 + orr r12,r12,r12,lsl #16 + add r4, r3, #0x40*2 + add r5, r3, #0xc0*2 + mov lr, #0x40/4 +.fl_loopcpRGB555_sh: + subs lr, lr, #1 + ldmia r3!, {r1,r6} + and r1, r12, r1, lsr #1 + and r6, r12, r6, lsr #1 + stmia r4!, {r1,r6} + stmia r5!, {r1,r6} + bne .fl_loopcpRGB555_sh + + @ hilighted pixels: + sub r3, r3, #0x40*2 + mov lr, #0x40/2 +.fl_loopcpRGB555_hi: + ldr r1, [r3], #4 + TileDoShHi2Pixels555 r1 + str r1, [r4], #4 + subs lr, lr, #1 + bne .fl_loopcpRGB555_hi + + sub r3, r3, #0x40*2 + + +.fl_noshRGB555: + ldr r1, =(HighCol+8) + mov lr, #0xff + mov lr, lr, lsl #1 + +.fl_loopRGB555: + subs r2, r2, #1 + + ldr r12, [r1], #4 + ldr r7, [r1], #4 + + and r4, lr, r12, lsl #1 + ldrh r4, [r3, r4] + and r5, lr, r12, lsr #7 + ldrh r5, [r3, r5] + orr r4, r4, r5, lsl #16 + + and r5, lr, r12, lsr #15 + ldrh r5, [r3, r5] + and r6, lr, r12, lsr #23 + ldrh r6, [r3, r6] + orr r5, r5, r6, lsl #16 + + and r8, lr, r7, lsl #1 + ldrh r8, [r3, r8] + and r6, lr, r7, lsr #7 + ldrh r6, [r3, r6] + orr r8, r8, r6, lsl #16 + + and r12,lr, r7, lsr #15 + ldrh r12,[r3, r12] + and r6, lr, r7, lsr #23 + ldrh r6, [r3, r6] + orr r12,r12, r6, lsl #16 + + stmia r0!, {r4,r5,r8,r12} + bne .fl_loopRGB555 + + + ldmfd sp!, {r4-r8,lr} + bx lr + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +@ utility +.global blockcpy @ void *dst, void *src, size_t n + +blockcpy: + stmfd sp!, {r4,r5} + mov r2, r2, lsr #4 +blockcpy_loop: + subs r2, r2, #1 + ldmia r1!, {r3-r5,r12} + stmia r0!, {r3-r5,r12} + bne blockcpy_loop + ldmfd sp!, {r4,r5} + bx lr + + +.global blockcpy_or @ void *dst, void *src, size_t n, int pat + +blockcpy_or: + stmfd sp!, {r4-r6} + orr r3, r3, r3, lsl #8 + orr r3, r3, r3, lsl #16 + mov r2, r2, lsr #4 +blockcpy_loop_or: + subs r2, r2, #1 + ldmia r1!, {r4-r6,r12} + orr r4, r4, r3 + orr r5, r5, r3 + orr r6, r6, r3 + orr r12,r12,r3 + stmia r0!, {r4-r6,r12} + bne blockcpy_loop_or + ldmfd sp!, {r4-r6} + bx lr + diff --git a/Pico/Draw_sh.c b/Pico/Draw_sh.c new file mode 100644 index 00000000..2f05a69a --- /dev/null +++ b/Pico/Draw_sh.c @@ -0,0 +1,1301 @@ +// This is part of Pico Library + +// (c) Copyright 2004 Dave, All rights reserved. +// (c) Copyright 2006 notaz, All rights reserved. +// Free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + + +#include "PicoInt.h" +#ifndef __GNUC__ +#pragma warning (disable:4706) // Disable assignment within conditional +#endif + +int (*PicoScan)(unsigned int num, void *data)=NULL; + +//unsigned short DefOutBuff[320*2]; +unsigned char HighCol[320*2]; +static int HighCacheA[41+1]; // caches for high layers +static int HighCacheB[41+1]; +static int HighCacheS[80+1]; // and sprites +static int HighPreSpr[80*2+1]; // slightly preprocessed sprites +char HighSprZ[320+8+8]; // Z-buffer for accurate sprites and shadow/hilight mode + // (if bit 7 == 0, sh caused by tile; if bit 6 == 0 pixel must be shadowed, else hilighted, if bit5 == 1) +// lsb->msb: moved sprites, all window tiles don't use same priority, accurate sprites (copied from PicoOpt), interlace +// dirty sprites, sonic mode, 16bit mode +int rendstatus=0x40; +void *DrawLineDest=HighCol; // pointer to dest buffer where to draw this line to +unsigned char *DrawLineInt=HighCol; // dest for internal code +int Scanline=0; // Scanline + +static int SpriteBlocks; +//unsigned short ppt[] = { 0x0f11, 0x0ff1, 0x01f1, 0x011f, 0x01ff, 0x0f1f, 0x0f0e, 0x0e7c }; + +struct TileStrip +{ + int nametab; // Position in VRAM of name table (for this tile line) + int line; // Line number in pixels 0x000-0x3ff within the virtual tilemap + int hscroll; // Horizontal scroll value in pixels for the line + int xmask; // X-Mask (0x1f - 0x7f) for horizontal wraparound in the tilemap + int *hc; // cache for high tile codes and their positions + int cells; // cells (tiles) to draw (32 col mode doesn't need to update whole 320) +}; + +// stuff available in asm: +#ifdef _ASM_DRAW_C +void DrawWindow(int tstart, int tend, int prio, int sh); +void BackFill(int reg7, int sh); +void DrawSprite(int *sprite, int **hc, int sh); +void DrawTilesFromCache(int *hc, int sh); +void DrawSpritesFromCache(int *hc, int sh); +void DrawLayer(int plane, int *hcache, int maxcells, int sh); +void FinalizeLineBGR444(int sh); +void FinalizeLineRGB555(int sh); +void blockcpy_or(void *dst, void *src, size_t n, int pat); +#else +// utility +void blockcpy_or(void *dst, void *src, size_t n, int pat) +{ + unsigned char *pd = dst, *ps = src; + for (; n; n--) + *pd++ = (unsigned char) (*ps++ | pat); +} +#endif + + +static int TileNorm(int sx,int addr,int pal) +{ + unsigned char *pd = DrawLineInt+sx; + unsigned int pack=0; unsigned int t=0; + + pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + if (pack) + { + t=pack&0x0000f000; if (t) pd[0]=(unsigned char)(pal|(t>>12)); + t=pack&0x00000f00; if (t) pd[1]=(unsigned char)(pal|(t>> 8)); + t=pack&0x000000f0; if (t) pd[2]=(unsigned char)(pal|(t>> 4)); + t=pack&0x0000000f; if (t) pd[3]=(unsigned char)(pal|(t )); + t=pack&0xf0000000; if (t) pd[4]=(unsigned char)(pal|(t>>28)); + t=pack&0x0f000000; if (t) pd[5]=(unsigned char)(pal|(t>>24)); + t=pack&0x00f00000; if (t) pd[6]=(unsigned char)(pal|(t>>20)); + t=pack&0x000f0000; if (t) pd[7]=(unsigned char)(pal|(t>>16)); + return 0; + } + + return 1; // Tile blank +} + +static int TileFlip(int sx,int addr,int pal) +{ + unsigned char *pd = DrawLineInt+sx; + unsigned int pack=0; unsigned int t=0; + + pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + if (pack) + { + t=pack&0x000f0000; if (t) pd[0]=(unsigned char)(pal|(t>>16)); + t=pack&0x00f00000; if (t) pd[1]=(unsigned char)(pal|(t>>20)); + t=pack&0x0f000000; if (t) pd[2]=(unsigned char)(pal|(t>>24)); + t=pack&0xf0000000; if (t) pd[3]=(unsigned char)(pal|(t>>28)); + t=pack&0x0000000f; if (t) pd[4]=(unsigned char)(pal|(t )); + t=pack&0x000000f0; if (t) pd[5]=(unsigned char)(pal|(t>> 4)); + t=pack&0x00000f00; if (t) pd[6]=(unsigned char)(pal|(t>> 8)); + t=pack&0x0000f000; if (t) pd[7]=(unsigned char)(pal|(t>>12)); + return 0; + } + return 1; // Tile blank +} + + +// tile renderers for hacky operator sprite support +#define sh_pix(x) \ + if(!t); \ + else if(t==0xe) pd[x]=(unsigned char)((pd[x]&0x3f)|0x80); /* hilight */ \ + else if(t==0xf) pd[x]=(unsigned char)((pd[x]&0x3f)|0xc0); /* shadow */ \ + else pd[x]=(unsigned char)(pal|t); + +#ifndef _ASM_DRAW_C +static int TileNormSH(int sx,int addr,int pal) +{ + unsigned int pack=0; unsigned int t=0; + unsigned char *pd = DrawLineInt+sx; + + pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + if (pack) + { + t=(pack&0x0000f000)>>12; sh_pix(0); + t=(pack&0x00000f00)>> 8; sh_pix(1); + t=(pack&0x000000f0)>> 4; sh_pix(2); + t=(pack&0x0000000f) ; sh_pix(3); + t=(pack&0xf0000000)>>28; sh_pix(4); + t=(pack&0x0f000000)>>24; sh_pix(5); + t=(pack&0x00f00000)>>20; sh_pix(6); + t=(pack&0x000f0000)>>16; sh_pix(7); + return 0; + } + + return 1; // Tile blank +} + +static int TileFlipSH(int sx,int addr,int pal) +{ + unsigned int pack=0; unsigned int t=0; + unsigned char *pd = DrawLineInt+sx; + + pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + if (pack) + { + t=(pack&0x000f0000)>>16; sh_pix(0); + t=(pack&0x00f00000)>>20; sh_pix(1); + t=(pack&0x0f000000)>>24; sh_pix(2); + t=(pack&0xf0000000)>>28; sh_pix(3); + t=(pack&0x0000000f) ; sh_pix(4); + t=(pack&0x000000f0)>> 4; sh_pix(5); + t=(pack&0x00000f00)>> 8; sh_pix(6); + t=(pack&0x0000f000)>>12; sh_pix(7); + return 0; + } + return 1; // Tile blank +} +#endif + +static int TileNormZ(int sx,int addr,int pal,int zval) +{ + unsigned int pack=0; unsigned int t=0; + unsigned char *pd = DrawLineInt+sx; + char *zb = HighSprZ+sx; + int collision = 0, zb_s; + + pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + if (pack) + { + t=pack&0x0000f000; if(t) { zb_s=zb[0]; if(zb_s) collision=1; if(zval>zb_s) { pd[0]=(unsigned char)(pal|(t>>12)); zb[0]=(char)zval; } } + t=pack&0x00000f00; if(t) { zb_s=zb[1]; if(zb_s) collision=1; if(zval>zb_s) { pd[1]=(unsigned char)(pal|(t>> 8)); zb[1]=(char)zval; } } + t=pack&0x000000f0; if(t) { zb_s=zb[2]; if(zb_s) collision=1; if(zval>zb_s) { pd[2]=(unsigned char)(pal|(t>> 4)); zb[2]=(char)zval; } } + t=pack&0x0000000f; if(t) { zb_s=zb[3]; if(zb_s) collision=1; if(zval>zb_s) { pd[3]=(unsigned char)(pal|(t )); zb[3]=(char)zval; } } + t=pack&0xf0000000; if(t) { zb_s=zb[4]; if(zb_s) collision=1; if(zval>zb_s) { pd[4]=(unsigned char)(pal|(t>>28)); zb[4]=(char)zval; } } + t=pack&0x0f000000; if(t) { zb_s=zb[5]; if(zb_s) collision=1; if(zval>zb_s) { pd[5]=(unsigned char)(pal|(t>>24)); zb[5]=(char)zval; } } + t=pack&0x00f00000; if(t) { zb_s=zb[6]; if(zb_s) collision=1; if(zval>zb_s) { pd[6]=(unsigned char)(pal|(t>>20)); zb[6]=(char)zval; } } + t=pack&0x000f0000; if(t) { zb_s=zb[7]; if(zb_s) collision=1; if(zval>zb_s) { pd[7]=(unsigned char)(pal|(t>>16)); zb[7]=(char)zval; } } + if(collision) Pico.video.status|=0x20; + return 0; + } + + return 1; // Tile blank +} + +static int TileFlipZ(int sx,int addr,int pal,int zval) +{ + unsigned int pack=0; unsigned int t=0; + unsigned char *pd = DrawLineInt+sx; + char *zb = HighSprZ+sx; + int collision = 0, zb_s; + + pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + if (pack) + { + t=pack&0x000f0000; if(t) { zb_s=zb[0]&0x1f; if(zb_s) collision=1; if(zval>zb_s) { pd[0]=(unsigned char)(pal|(t>>16)); zb[0]=(char)zval; } } + t=pack&0x00f00000; if(t) { zb_s=zb[1]&0x1f; if(zb_s) collision=1; if(zval>zb_s) { pd[1]=(unsigned char)(pal|(t>>20)); zb[1]=(char)zval; } } + t=pack&0x0f000000; if(t) { zb_s=zb[2]&0x1f; if(zb_s) collision=1; if(zval>zb_s) { pd[2]=(unsigned char)(pal|(t>>24)); zb[2]=(char)zval; } } + t=pack&0xf0000000; if(t) { zb_s=zb[3]&0x1f; if(zb_s) collision=1; if(zval>zb_s) { pd[3]=(unsigned char)(pal|(t>>28)); zb[3]=(char)zval; } } + t=pack&0x0000000f; if(t) { zb_s=zb[4]&0x1f; if(zb_s) collision=1; if(zval>zb_s) { pd[4]=(unsigned char)(pal|(t )); zb[4]=(char)zval; } } + t=pack&0x000000f0; if(t) { zb_s=zb[5]&0x1f; if(zb_s) collision=1; if(zval>zb_s) { pd[5]=(unsigned char)(pal|(t>> 4)); zb[5]=(char)zval; } } + t=pack&0x00000f00; if(t) { zb_s=zb[6]&0x1f; if(zb_s) collision=1; if(zval>zb_s) { pd[6]=(unsigned char)(pal|(t>> 8)); zb[6]=(char)zval; } } + t=pack&0x0000f000; if(t) { zb_s=zb[7]&0x1f; if(zb_s) collision=1; if(zval>zb_s) { pd[7]=(unsigned char)(pal|(t>>12)); zb[7]=(char)zval; } } + if(collision) Pico.video.status|=0x20; + return 0; + } + return 1; // Tile blank +} + + +#define sh_pixZ(x) \ + if(t) { \ + if(zb[x]) collision=1; \ + if(zval>zb[x]) { \ + if (t==0xe) { pd[x]=(unsigned char)((pd[x]&0x3f)|0x80); /* hilight */ } \ + else if(t==0xf) { pd[x]=(unsigned char)((pd[x]&0x3f)|0xc0); /* shadow */ } \ + else { zb[x]=(char)zval; pd[x]=(unsigned char)(pal|t); } \ + } \ + } + +static int TileNormZSH(int sx,int addr,int pal,int zval) +{ + unsigned int pack=0; unsigned int t=0; + unsigned char *pd = DrawLineInt+sx; + char *zb = HighSprZ+sx; + int collision = 0; + + pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + if (pack) + { + t=(pack&0x0000f000)>>12; sh_pixZ(0); + t=(pack&0x00000f00)>> 8; sh_pixZ(1); + t=(pack&0x000000f0)>> 4; sh_pixZ(2); + t=(pack&0x0000000f) ; sh_pixZ(3); + t=(pack&0xf0000000)>>28; sh_pixZ(4); + t=(pack&0x0f000000)>>24; sh_pixZ(5); + t=(pack&0x00f00000)>>20; sh_pixZ(6); + t=(pack&0x000f0000)>>16; sh_pixZ(7); + if(collision) Pico.video.status|=0x20; + return 0; + } + + return 1; // Tile blank +} + +static int TileFlipZSH(int sx,int addr,int pal,int zval) +{ + unsigned int pack=0; unsigned int t=0; + unsigned char *pd = DrawLineInt+sx; + char *zb = HighSprZ+sx; + int collision = 0; + + pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + if (pack) + { + t=(pack&0x000f0000)>>16; sh_pixZ(0); + t=(pack&0x00f00000)>>20; sh_pixZ(1); + t=(pack&0x0f000000)>>24; sh_pixZ(2); + t=(pack&0xf0000000)>>28; sh_pixZ(3); + t=(pack&0x0000000f) ; sh_pixZ(4); + t=(pack&0x000000f0)>> 4; sh_pixZ(5); + t=(pack&0x00000f00)>> 8; sh_pixZ(6); + t=(pack&0x0000f000)>>12; sh_pixZ(7); + if(collision) Pico.video.status|=0x20; + return 0; + } + return 1; // Tile blank +} + +// -------------------------------------------- + +#ifndef _ASM_DRAW_C +static void DrawStrip(struct TileStrip *ts, int sh) +{ + int tilex=0,dx=0,ty=0,code=0,addr=0,cells; + int oldcode=-1,blank=-1; // The tile we know is blank + int pal=0; + + // Draw tiles across screen: + tilex=(-ts->hscroll)>>3; + ty=(ts->line&7)<<1; // Y-Offset into tile + dx=((ts->hscroll-1)&7)+1; + cells = ts->cells; + if(dx != 8) cells++; // have hscroll, need to draw 1 cell more + + for (; cells; dx+=8,tilex++,cells--) + { + int zero=0; + + code=Pico.vram[ts->nametab+(tilex&ts->xmask)]; + if (code==blank) continue; + if (code>>15) { // high priority tile + int cval = code | (dx<<16) | (ty<<25); + if(code&0x1000) cval^=7<<26; + *ts->hc++ = cval; // cache it + continue; + } + + if (code!=oldcode) { + oldcode = code; + // Get tile address/2: + addr=(code&0x7ff)<<4; + addr+=ty; + if (code&0x1000) addr^=0xe; // Y-flip + +// pal=Pico.cram+((code>>9)&0x30); + pal=((code>>9)&0x30)|(sh<<6); + } + + if (code&0x0800) zero=TileFlip(dx,addr,pal); + else zero=TileNorm(dx,addr,pal); + + if (zero) blank=code; // We know this tile is blank now + } + + // terminate the cache list + *ts->hc = 0; +} +#endif + +// this is messy +#ifndef _ASM_DRAW_C +static +#endif +void DrawStripVSRam(struct TileStrip *ts, int plane) +{ + int tilex=0,dx=0,ty=0,code=0,addr=0,cell=0,nametabadd=0; + int oldcode=-1,blank=-1; // The tile we know is blank + int pal=0,scan=Scanline; + + // Draw tiles across screen: + tilex=(-ts->hscroll)>>3; + dx=((ts->hscroll-1)&7)+1; + if(dx != 8) { + int vscroll, line; + cell--; // have hscroll, start with negative cell + // also calculate intial VS stuff + vscroll=Pico.vsram[plane]; + + // Find the line in the name table + line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask .. + nametabadd=(line>>3)<<(ts->line>>24); // .. and shift[width] + ty=(line&7)<<1; // Y-Offset into tile + } + + for (; cell < ts->cells; dx+=8,tilex++,cell++) + { + int zero=0; + + if((cell&1)==0) { + int line,vscroll; + vscroll=Pico.vsram[plane+(cell&~1)]; + + // Find the line in the name table + line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask .. + nametabadd=(line>>3)<<(ts->line>>24); // .. and shift[width] + ty=(line&7)<<1; // Y-Offset into tile + } + + code=Pico.vram[ts->nametab+nametabadd+(tilex&ts->xmask)]; + if (code==blank) continue; + if (code>>15) { // high priority tile + int cval = code | (dx<<16) | (ty<<25); + if(code&0x1000) cval^=7<<26; + *ts->hc++ = cval; // cache it + continue; + } + + if (code!=oldcode) { + oldcode = code; + // Get tile address/2: + addr=(code&0x7ff)<<4; + if (code&0x1000) addr+=14-ty; else addr+=ty; // Y-flip + +// pal=Pico.cram+((code>>9)&0x30); + pal=((code>>9)&0x30); + } + + if (code&0x0800) zero=TileFlip(dx,addr,pal); + else zero=TileNorm(dx,addr,pal); + + if (zero) blank=code; // We know this tile is blank now + } + + // terminate the cache list + *ts->hc = 0; +} + +#ifndef _ASM_DRAW_C +static +#endif +void DrawStripInterlace(struct TileStrip *ts) +{ + int tilex=0,dx=0,ty=0,code=0,addr=0,cells; + int oldcode=-1,blank=-1; // The tile we know is blank + int pal=0; + + // Draw tiles across screen: + tilex=(-ts->hscroll)>>3; + ty=(ts->line&15)<<1; // Y-Offset into tile + dx=((ts->hscroll-1)&7)+1; + cells = ts->cells; + if(dx != 8) cells++; // have hscroll, need to draw 1 cell more + + for (; cells; dx+=8,tilex++,cells--) + { + int zero=0; + + code=Pico.vram[ts->nametab+(tilex&ts->xmask)]; + if (code==blank) continue; + if (code>>15) { // high priority tile + int cval = (code&0xfc00) | (dx<<16) | (ty<<25); + cval|=(code&0x3ff)<<1; + if(code&0x1000) cval^=0xf<<26; + *ts->hc++ = cval; // cache it + continue; + } + + if (code!=oldcode) { + oldcode = code; + // Get tile address/2: + addr=(code&0x7ff)<<5; + if (code&0x1000) addr+=30-ty; else addr+=ty; // Y-flip + +// pal=Pico.cram+((code>>9)&0x30); + pal=((code>>9)&0x30); + } + + if (code&0x0800) zero=TileFlip(dx,addr,pal); + else zero=TileNorm(dx,addr,pal); + + if (zero) blank=code; // We know this tile is blank now + } + + // terminate the cache list + *ts->hc = 0; +} + +// -------------------------------------------- + +#ifndef _ASM_DRAW_C +static void DrawLayer(int plane, int *hcache, int maxcells, int sh) +{ + struct PicoVideo *pvid=&Pico.video; + const char shift[4]={5,6,5,7}; // 32,64 or 128 sized tilemaps (2 is invalid) + struct TileStrip ts; + int width, height, ymask; + int vscroll, htab; + + ts.hc=hcache; + ts.cells=maxcells; + + // Work out the TileStrip to draw + + // Work out the name table size: 32 64 or 128 tiles (0-3) + width=pvid->reg[16]; + height=(width>>4)&3; width&=3; + + ts.xmask=(1<1) ymask =0x0ff; + + // Find name table: + if (plane==0) ts.nametab=(pvid->reg[2]&0x38)<< 9; // A + else ts.nametab=(pvid->reg[4]&0x07)<<12; // B + + htab=pvid->reg[13]<<9; // Horizontal scroll table address + if ( pvid->reg[11]&2) htab+=Scanline<<1; // Offset by line + if ((pvid->reg[11]&1)==0) htab&=~0xf; // Offset by tile + htab+=plane; // A or B + + // Get horizontal scroll value, will be masked later + ts.hscroll=Pico.vram[htab&0x7fff]; + + if((pvid->reg[12]&6) == 6) { + // interlace mode 2 + vscroll=Pico.vsram[plane]; // Get vertical scroll value + + // Find the line in the name table + ts.line=(vscroll+(Scanline<<1))&((ymask<<1)|1); + ts.nametab+=(ts.line>>4)<reg[11]&4) { + // shit, we have 2-cell column based vscroll + // luckily this doesn't happen too often + ts.line=ymask|(shift[width]<<24); // save some stuff instead of line + DrawStripVSRam(&ts, plane); + } else { + vscroll=Pico.vsram[plane]; // Get vertical scroll value + + // Find the line in the name table + ts.line=(vscroll+Scanline)&ymask; + ts.nametab+=(ts.line>>3)<reg[12]&1) + { + nametab=(pvid->reg[3]&0x3c)<<9; // 40-cell mode + nametab+=(Scanline>>3)<<6; + } + else + { + nametab=(pvid->reg[3]&0x3e)<<9; // 32-cell mode + nametab+=(Scanline>>3)<<5; + } + + tilex=tstart<<1; + tend<<=1; + + ty=(Scanline&7)<<1; // Y-Offset into tile + + if(!(rendstatus&2)) { + // check the first tile code + code=Pico.vram[nametab+tilex]; + // if the whole window uses same priority (what is often the case), we may be able to skip this field + if((code>>15) != prio) return; + } + + // Draw tiles across screen: + for (; tilex < tend; tilex++) + { + int addr=0,zero=0; + int pal; + + code=Pico.vram[nametab+tilex]; + if(code==blank) continue; + if((code>>15) != prio) { + rendstatus|=2; + continue; + } + + pal=((code>>9)&0x30); + + if(sh) { + int tmp, *zb = (int *)(DrawLineInt+8+(tilex<<3)); + if(prio) { + tmp = *zb; + if(!(tmp&0x00000080)) tmp&=~0x000000c0; if(!(tmp&0x00008000)) tmp&=~0x0000c000; + if(!(tmp&0x00800000)) tmp&=~0x00c00000; if(!(tmp&0x80000000)) tmp&=~0xc0000000; + *zb++=tmp; tmp = *zb; + if(!(tmp&0x00000080)) tmp&=~0x000000c0; if(!(tmp&0x00008000)) tmp&=~0x0000c000; + if(!(tmp&0x00800000)) tmp&=~0x00c00000; if(!(tmp&0x80000000)) tmp&=~0xc0000000; + *zb++=tmp; + } else { + pal |= 0x40; + } + } + + // Get tile address/2: + addr=(code&0x7ff)<<4; + if (code&0x1000) addr+=14-ty; else addr+=ty; // Y-flip + + if (code&0x0800) zero=TileFlip(8+(tilex<<3),addr,pal); + else zero=TileNorm(8+(tilex<<3),addr,pal); + + if (zero) blank=code; // We know this tile is blank now + } + + // terminate the cache list + //*hcache = 0; +} + +// -------------------------------------------- + +static void DrawTilesFromCache(int *hc, int sh) +{ + int code, addr, zero, dx; + int pal; + short blank=-1; // The tile we know is blank + + // *ts->hc++ = code | (dx<<16) | (ty<<25); // cache it + + while((code=*hc++)) { + if(!sh && (short)code == blank) continue; + + // Get tile address/2: + addr=(code&0x7ff)<<4; + addr+=(unsigned int)code>>25; // y offset into tile + dx=(code>>16)&0x1ff; + if(sh) { + unsigned char *zb = DrawLineInt+dx; + if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++; + if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++; + if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++; + if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++; + } + + pal=((code>>9)&0x30); + + if (code&0x0800) zero=TileFlip(dx,addr,pal); + else zero=TileNorm(dx,addr,pal); + + if(zero) blank=(short)code; + } +} + +// -------------------------------------------- + +// Index + 0 : hhhhvvvv ab--hhvv yyyyyyyy yyyyyyyy // a: offscreen h, b: offs. v, h: horiz. size +// Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8 + +static void DrawSprite(int *sprite, int **hc, int sh) +{ + int width=0,height=0; + int row=0,code=0; + int pal; + int tile=0,delta=0; + int sx, sy; + int (*fTileFunc)(int sx,int addr,int pal); + + // parse the sprite data + sy=sprite[0]; + code=sprite[1]; + sx=code>>16; // X + width=sy>>28; + height=(sy>>24)&7; // Width and height in tiles + sy=(sy<<16)>>16; // Y + + row=Scanline-sy; // Row of the sprite we are on + + if (code&0x1000) row=(height<<3)-1-row; // Flip Y + + tile=code&0x7ff; // Tile number + tile+=row>>3; // Tile number increases going down + delta=height; // Delta to increase tile by going right + if (code&0x0800) { tile+=delta*(width-1); delta=-delta; } // Flip X + + tile<<=4; tile+=(row&7)<<1; // Tile address + + if(code&0x8000) { // high priority - cache it + *(*hc)++ = (tile<<16)|((code&0x0800)<<5)|((sx<<6)&0x0000ffc0)|((code>>9)&0x30)|((sprite[0]>>16)&0xf); + } else { + delta<<=4; // Delta of address + pal=((code>>9)&0x30)|(sh<<6); + + if(sh && (code&0x6000) == 0x6000) { + if(code&0x0800) fTileFunc=TileFlipSH; + else fTileFunc=TileNormSH; + } else { + if(code&0x0800) fTileFunc=TileFlip; + else fTileFunc=TileNorm; + } + + for (; width; width--,sx+=8,tile+=delta) + { + if(sx<=0) continue; + if(sx>=328) break; // Offscreen + + tile&=0x7fff; // Clip tile address + fTileFunc(sx,tile,pal); + } + } +} +#endif + + +// Index + 0 : hhhhvvvv s---hhvv yyyyyyyy yyyyyyyy // s: skip flag, h: horiz. size +// Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8 + +static void DrawSpriteZ(int pack, int pack2, int shpri, int sprio) +{ + int width=0,height=0; + int row=0; + int pal; + int tile=0,delta=0; + int sx, sy; + int (*fTileFunc)(int sx,int addr,int pal,int zval); + + // parse the sprite data + sx=pack2>>16; // X + sy=(pack <<16)>>16; // Y + width=pack>>28; + height=(pack>>24)&7; // Width and height in tiles + + row=Scanline-sy; // Row of the sprite we are on + + if (pack2&0x1000) row=(height<<3)-1-row; // Flip Y + + tile=pack2&0x7ff; // Tile number + tile+=row>>3; // Tile number increases going down + delta=height; // Delta to increase tile by going right + if (pack2&0x0800) { tile+=delta*(width-1); delta=-delta; } // Flip X + + tile<<=4; tile+=(row&7)<<1; // Tile address + delta<<=4; // Delta of address + pal=((pack2>>9)&0x30); + if((shpri&1)&&!(shpri&2)) pal|=0x40; + + shpri&=1; + if((pack2&0x6000) != 0x6000) shpri = 0; + shpri |= (pack2&0x0800)>>10; + switch(shpri) { + default: + case 0: fTileFunc=TileNormZ; break; + case 1: fTileFunc=TileNormZSH; break; + case 2: fTileFunc=TileFlipZ; break; + case 3: fTileFunc=TileFlipZSH; break; + } + + for (; width; width--,sx+=8,tile+=delta) + { + if(sx<=0) continue; + if(sx>=328) break; // Offscreen + + tile&=0x7fff; // Clip tile address + fTileFunc(sx,tile,pal,sprio); + } +} + +static void DrawSpriteInterlace(unsigned int *sprite) +{ + int width=0,height=0; + int row=0,code=0; + int pal; + int tile=0,delta=0; + int sx, sy; + + // parse the sprite data + sy=sprite[0]; + height=sy>>24; + sy=(sy&0x3ff)-0x100; // Y + width=(height>>2)&3; height&=3; + width++; height++; // Width and height in tiles + + row=(Scanline<<1)-sy; // Row of the sprite we are on + + code=sprite[1]; + sx=((code>>16)&0x1ff)-0x78; // X + + if (code&0x1000) row^=(16<>4; // Tile number increases going down + delta=height; // Delta to increase tile by going right + if (code&0x0800) { tile+=delta*(width-1); delta=-delta; } // Flip X + + tile<<=5; tile+=(row&15)<<1; // Tile address + + delta<<=5; // Delta of address + pal=((code>>9)&0x30); // Get palette pointer + + for (; width; width--,sx+=8,tile+=delta) + { + if(sx<=0) continue; + if(sx>=328) break; // Offscreen + + tile&=0x7fff; // Clip tile address + if (code&0x0800) TileFlip(sx,tile,pal); + else TileNorm(sx,tile,pal); + } +} + + +static void DrawAllSpritesInterlace(int pri, int maxwidth) +{ + struct PicoVideo *pvid=&Pico.video; + int i,u,table,link=0,sline=Scanline<<1; + unsigned int *sprites[80]; // Sprite index + + table=pvid->reg[5]&0x7f; + if (pvid->reg[12]&1) table&=0x7e; // Lowest bit 0 in 40-cell mode + table<<=8; // Get sprite table address/2 + + for (i=u=0; u < 80 && i < 21; u++) + { + unsigned int *sprite; + int code, sx, sy, height; + + sprite=(unsigned int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite + + // get sprite info + code = sprite[0]; + sx = sprite[1]; + if(((sx>>15)&1) != pri) goto nextsprite; // wrong priority sprite + + // check if it is on this line + sy = (code&0x3ff)-0x100; + height = (((code>>24)&3)+1)<<4; + if(sline < sy || sline >= sy+height) goto nextsprite; // no + + // check if sprite is not hidden offscreen + sx = (sx>>16)&0x1ff; + sx -= 0x78; // Get X coordinate + 8 + if(sx <= -8*3 || sx >= maxwidth) goto nextsprite; + + // sprite is good, save it's pointer + sprites[i++]=sprite; + + nextsprite: + // Find next sprite + link=(code>>16)&0x7f; + if(!link) break; // End of sprites + } + + // Go through sprites backwards: + for (i-- ;i>=0; i--) + DrawSpriteInterlace(sprites[i]); +} + + +#ifndef _ASM_DRAW_C +static void DrawSpritesFromCache(int *hc, int sh) +{ + int code, tile, sx, delta, width; + int pal; + int (*fTileFunc)(int sx,int addr,int pal); + + // *(*hc)++ = (tile<<16)|((code&0x0800)<<5)|((sx<<6)&0x0000ffc0)|((code>>9)&0x30)|((sprite[0]>>24)&0xf); + + while((code=*hc++)) { + pal=(code&0x30); + delta=code&0xf; + width=delta>>2; delta&=3; + width++; delta++; // Width and height in tiles + if (code&0x10000) delta=-delta; // Flip X + delta<<=4; + tile=((unsigned int)code>>17)<<1; + sx=(code<<16)>>22; // sx can be negative (start offscreen), so sign extend + + if(sh && pal == 0x30) { // + if(code&0x10000) fTileFunc=TileFlipSH; + else fTileFunc=TileNormSH; + } else { + if(code&0x10000) fTileFunc=TileFlip; + else fTileFunc=TileNorm; + } + + for (; width; width--,sx+=8,tile+=delta) + { + if(sx<=0) continue; + if(sx>=328) break; // Offscreen + + tile&=0x7fff; // Clip tile address + fTileFunc(sx,tile,pal); + } + } +} +#endif + + +// Index + 0 : ----hhvv -lllllll -------y yyyyyyyy +// Index + 4 : -------x xxxxxxxx pccvhnnn nnnnnnnn +// v +// Index + 0 : hhhhvvvv ab--hhvv yyyyyyyy yyyyyyyy // a: offscreen h, b: offs. v, h: horiz. size +// Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8 + +static void PrepareSprites(int full) +{ + struct PicoVideo *pvid=&Pico.video; + int u=0,link=0,sblocks=0; + int table=0; + int *pd = HighPreSpr; + + table=pvid->reg[5]&0x7f; + if (pvid->reg[12]&1) table&=0x7e; // Lowest bit 0 in 40-cell mode + table<<=8; // Get sprite table address/2 + + if (!full) + { + int pack; + // updates: tilecode, sx + for (u=0; u < 80 && (pack = *pd); u++, pd+=2) + { + unsigned int *sprite; + int code, code2, sx, sy, skip=0; + + sprite=(unsigned int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite + + // parse sprite info + code = sprite[0]; + code2 = sprite[1]; + code2 &= ~0xfe000000; + code2 -= 0x00780000; // Get X coordinate + 8 in upper 16 bits + sx = code2>>16; + + if((sx <= 8-((pack>>28)<<3) && sx >= -0x76) || sx >= 328) skip=1<<23; + else if ((sy = (pack<<16)>>16) < 240 && sy > -32) { + int sbl = (2<<(pack>>28))-1; + sblocks |= sbl<<(sy>>3); + } + + *pd = (pack&~(1<<23))|skip; + *(pd+1) = code2; + + // Find next sprite + link=(code>>16)&0x7f; + if(!link) break; // End of sprites + } + SpriteBlocks |= sblocks; + } + else + { + for (; u < 80; u++) + { + unsigned int *sprite; + int code, code2, sx, sy, hv, height, width, skip=0, sx_min; + + sprite=(unsigned int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite + + // parse sprite info + code = sprite[0]; + sy = (code&0x1ff)-0x80; + hv = (code>>24)&0xf; + height = (hv&3)+1; + + if(sy > 240 || sy + (height<<3) <= 0) skip|=1<<22; + + width = (hv>>2)+1; + code2 = sprite[1]; + sx = (code2>>16)&0x1ff; + sx -= 0x78; // Get X coordinate + 8 + sx_min = 8-(width<<3); + + if((sx <= sx_min && sx >= -0x76) || sx >= 328) skip|=1<<23; + else if (sx > sx_min && !skip) { + int sbl = (2<>3; + if(shi < 0) shi=0; // negative sy + sblocks |= sbl<>16)&0x7f; + if(!link) break; // End of sprites + } + SpriteBlocks = sblocks; + *pd = 0; // terminate + } +} + +static void DrawAllSprites(int *hcache, int maxwidth, int prio, int sh) +{ + int i,u,n; + int sx1seen=0; // sprite with x coord 1 or 0 seen + int ntiles = 0; // tile counter for sprite limit emulation + int *sprites[40]; // Sprites to draw in fast mode + int *ps, pack, rs = rendstatus, scan=Scanline; + + if(rs&8) { + DrawAllSpritesInterlace(prio, maxwidth); + return; + } + if(rs&0x11) { + //dprintf("PrepareSprites(%i) [%i]", (rs>>4)&1, scan); + PrepareSprites(rs&0x10); + rendstatus=rs&~0x11; + } + if (!(SpriteBlocks & (1<<(scan>>3)))) return; + + if(((rs&4)||sh)&&prio==0) + memset(HighSprZ, 0, 328); + if(!(rs&4)&&prio) { + if(hcache[0]) DrawSpritesFromCache(hcache, sh); + return; + } + + ps = HighPreSpr; + + // Index + 0 : hhhhvvvv ab--hhvv yyyyyyyy yyyyyyyy // a: offscreen h, b: offs. v, h: horiz. size + // Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8 + + for(i=u=n=0; (pack = *ps) && n < 20; ps+=2, u++) + { + int sx, sy, row, pack2; + + if(pack & 0x00400000) continue; + + // get sprite info + pack2 = *(ps+1); + sx = pack2>>16; + sy = (pack <<16)>>16; + row = scan-sy; + + //dprintf("x: %i y: %i %ix%i", sx, sy, (pack>>28)<<3, (pack>>21)&0x38); + + if(sx == -0x77) sx1seen|=1; // for masking mode 2 + + // check if it is on this line + if(row < 0 || row >= ((pack>>21)&0x38)) continue; // no + n++; // number of sprites on this line (both visible and hidden, max is 20) [broken] + + // sprite limit + ntiles += pack>>28; + if(ntiles > 40) break; + + if(pack & 0x00800000) continue; + + // masking sprite? + if(sx == -0x78) { + if(!(sx1seen&1) || sx1seen==3) { + break; // this sprite is not drawn and remaining sprites are masked + } + if((sx1seen>>8) == 0) sx1seen=(i+1)<<8; + continue; + } + else if(sx == -0x77) { + // masking mode2 (Outrun, Galaxy Force II, Shadow of the beast) + if(sx1seen>>8) { i=(sx1seen>>8)-1; break; } // seen both 0 and 1 + sx1seen |= 2; + continue; + } + + // accurate sprites + //dprintf("P:%i",((sx>>15)&1)); + if(rs&4) { + // might need to skip this sprite + if((pack2&0x8000) ^ (prio<<15)) continue; + DrawSpriteZ(pack,pack2,sh|(prio<<1),(char)(0x1f-n)); + continue; + } + + // sprite is good, save it's pointer + sprites[i++]=ps; + } + + // Go through sprites backwards: + if(!(rs&4)) { + for (i--; i>=0; i--) + DrawSprite(sprites[i],&hcache,sh); + + // terminate cache list + *hcache = 0; + } +} + + +// -------------------------------------------- + +#ifndef _ASM_DRAW_C +static void BackFill(int reg7, int sh) +{ + unsigned int back=0; + unsigned int *pd=NULL,*end=NULL; + + // Start with a blank scanline (background colour): + back=reg7&0x3f; + back|=sh<<6; + back|=back<<8; + back|=back<<16; + + pd= (unsigned int *)(DrawLineInt+8); + end=(unsigned int *)(DrawLineInt+8+320); + + do { pd[0]=pd[1]=pd[2]=pd[3]=back; pd+=4; } while (pd= 0; i--) + pal[0x40|i] = pal[0xc0|i] = (unsigned short)((pal[i]>>1)&0x0777); + // hilighted pixels + for(i = 0x3f; i >= 0; i--) { + t=pal[i]&0xeee;t+=0x444;if(t&0x10)t|=0xe;if(t&0x100)t|=0xe0;if(t&0x1000)t|=0xe00;t&=0xeee; + pal[0x80|i]=(unsigned short)t; + } + Pico.m.dirtyPal = 0; + } + } + + for(i = 0; i < len; i++) + pd[i] = pal[ps[i]]; +} + + +static void FinalizeLineRGB555(int sh) +{ + unsigned short *pd=DrawLineDest; + unsigned char *ps=DrawLineInt+8; + unsigned short *pal=HighPal; + int len, i, t, dirtyPal = Pico.m.dirtyPal; + + if(dirtyPal) { + unsigned short *ppal=Pico.cram; + for(i = 0x3f; i >= 0; i--) + pal[i] = (unsigned short) (((ppal[i]&0x00f)<<12)|((ppal[i]&0x0f0)<<3)|((ppal[i]&0xf00)>>7)); + Pico.m.dirtyPal = 0; + } + + if (Pico.video.reg[12]&1) { + len = 320; + } else { + if(!(PicoOpt&0x100)) pd+=32; + len = 256; + } + + if(sh) { + if(dirtyPal) { + // shadowed pixels + for(i = 0x3f; i >= 0; i--) + pal[0x40|i] = pal[0xc0|i] = (unsigned short)((pal[i]>>1)&0x738e); + // hilighted pixels + for(i = 0x3f; i >= 0; i--) { + t=pal[i]&0xe71c;t+=0x4208;if(t&0x20)t|=0x1c;if(t&0x800)t|=0x700;if(t&0x10000)t|=0xe000;t&=0xe71c; + pal[0x80|i]=(unsigned short)t; + } + } + } + + for(i = 0; i < len; i++) + pd[i] = pal[ps[i]]; +} +#endif + +static void FinalizeLine8bit(int sh) +{ + unsigned char *pd=DrawLineDest; + int len, rs = rendstatus; + static int dirty_count; + + if (!sh && Pico.m.dirtyPal && Scanline < 222) { + // a hack for mid-frame palette changes + if (!(rs & 0x20)) + dirty_count = 1; + else dirty_count++; + rs |= 0x20; + rendstatus = rs; + if (dirty_count == 3) { + blockcpy(HighPal, Pico.cram, 0x40*2); + } else if (dirty_count == 11) { + blockcpy(HighPal+0x40, Pico.cram, 0x40*2); + } + } + + if (Pico.video.reg[12]&1) { + len = 320; + } else { + if(!(PicoOpt&0x100)) pd+=32; + len = 256; + } + +/* test + if (!sh && rs & 0x20) { + if (dirty_count >= 11) { + blockcpy_or(pd, HighCol+8, len, 0x80); + } else { + blockcpy_or(pd, HighCol+8, len, 0x40); + } + } else { + blockcpy(pd, HighCol+8, len); + } +*/ +} + +void (*FinalizeLine)(int sh) = FinalizeLineBGR444; + +// -------------------------------------------- + +static int DrawDisplay(int sh) +{ + struct PicoVideo *pvid=&Pico.video; + int win=0,edge=0,hvwind=0; + int maxw, maxcells; + + if(pvid->reg[12]&1) { + maxw = 328; maxcells = 40; + } else { + maxw = 264; maxcells = 32; + } + + // Find out if the window is on this line: + win=pvid->reg[0x12]; + edge=(win&0x1f)<<3; + + if (win&0x80) { if (Scanline>=edge) hvwind=1; } + else { if (Scanline< edge) hvwind=1; } + + if(!hvwind) { // we might have a vertical window here + win=pvid->reg[0x11]; + edge=win&0x1f; + if(win&0x80) { + if(!edge) hvwind=1; + else if(edge < (maxcells>>1)) hvwind=2; + } else { + if(!edge); + else if(edge < (maxcells>>1)) hvwind=2; + else hvwind=1; + } + } + + DrawLayer(1, HighCacheB, maxcells, sh); + if(hvwind == 1) + DrawWindow(0, maxcells>>1, 0, sh); // HighCacheAW + else if(hvwind == 2) { + // ahh, we have vertical window + DrawLayer(0, HighCacheA, (win&0x80) ? edge<<1 : maxcells, sh); + DrawWindow((win&0x80) ? edge : 0, (win&0x80) ? maxcells>>1 : edge, 0, sh); // HighCacheW + } else + DrawLayer(0, HighCacheA, maxcells, sh); + DrawAllSprites(HighCacheS, maxw, 0, sh); + + if(HighCacheB[0]) DrawTilesFromCache(HighCacheB, sh); + if(hvwind == 1) + DrawWindow(0, maxcells>>1, 1, sh); + else if(hvwind == 2) { + if(HighCacheA[0]) DrawTilesFromCache(HighCacheA, sh); + DrawWindow((win&0x80) ? edge : 0, (win&0x80) ? maxcells>>1 : edge, 1, sh); + } else + if(HighCacheA[0]) DrawTilesFromCache(HighCacheA, sh); + DrawAllSprites(HighCacheS, maxw, 1, sh); + + return 0; +} + + +void PicoFrameStart() +{ + // prepare to do this frame + rendstatus &= 0x40; + rendstatus |= (PicoOpt&0x80)>>5; // accurate sprites + if(rendstatus) + Pico.video.status &= ~0x0020; + else Pico.video.status |= 0x0020; // sprite collision + if((Pico.video.reg[12]&6) == 6) rendstatus |= 8; // interlace mode + + PrepareSprites(1); +} + +static int Skip=0; + +int PicoLine(int scan) +{ + int sh; + if (Skip>0) { Skip--; return 0; } // Skip rendering lines + + if(!(rendstatus&0x40)) + DrawLineInt = DrawLineDest; + + Scanline=scan; + sh=(Pico.video.reg[0xC]&8)>>3; // shadow/hilight? + + // Draw screen: + BackFill(Pico.video.reg[7], sh); + if (Pico.video.reg[1]&0x40) + DrawDisplay(sh); + + FinalizeLine(sh); + //if (SpriteBlocks & (1<<(scan>>3))) for (sh=0; sh < 30; sh++) DrawLineDest[sh] = 0xf; + + Skip=PicoScan(Scanline,DrawLineDest); + + return 0; +} + + +void DrawSetColorFormat(int which) +{ + rendstatus |= 0x40; + DrawLineInt = HighCol; + + if (which == 2) { + rendstatus &= ~0x40; + FinalizeLine = FinalizeLine8bit; + } else if (which == 1) + FinalizeLine = FinalizeLineRGB555; + else + FinalizeLine = FinalizeLineBGR444; +} diff --git a/Pico/Draw_sh.s b/Pico/Draw_sh.s new file mode 100644 index 00000000..7811b849 --- /dev/null +++ b/Pico/Draw_sh.s @@ -0,0 +1,1527 @@ +@ assembly "optimized" version of some funtions from draw.c +@ this is highly specialized, be careful if changing related C code! + +@ (c) Copyright 2006, notaz +@ All Rights Reserved + + +.extern Pico +.extern PicoOpt +.extern HighCol +.extern Scanline +.extern HighSprZ +.extern rendstatus +.extern DrawLineInt +.extern DrawLineDest +.extern DrawStripVSRam +.extern DrawStripInterlace + + +@ helper +.macro TilePixel pat lsrr offs +.if !\lsrr + ands r4, \pat, r2 +.else + ands r4, \pat, r2, lsr #\lsrr +.endif + orrne r4, r3, r4 + strneb r4, [r1,#\offs] +.endm + +@ TileNorm (r1=pdest, r2=pixels8, r3=pal) r4: scratch, pat: register with helper pattern 0xf +.macro TileNorm pat + TilePixel \pat, 12, 0 @ #0x0000f000 + TilePixel \pat, 8, 1 @ #0x00000f00 + TilePixel \pat, 4, 2 @ #0x000000f0 + TilePixel \pat, 0, 3 @ #0x0000000f + TilePixel \pat, 28, 4 @ #0xf0000000 + TilePixel \pat, 24, 5 @ #0x0f000000 + TilePixel \pat, 20, 6 @ #0x00f00000 + TilePixel \pat, 16, 7 @ #0x000f0000 +.endm + +@ TileFlip (r1=pdest, r2=pixels8, r3=pal) r4: scratch, pat: register with helper pattern 0xf +.macro TileFlip pat + TilePixel \pat, 16, 0 @ #0x000f0000 + TilePixel \pat, 20, 1 @ #0x00f00000 + TilePixel \pat, 24, 2 @ #0x0f000000 + TilePixel \pat, 28, 3 @ #0xf0000000 + TilePixel \pat, 0, 4 @ #0x0000000f + TilePixel \pat, 4, 5 @ #0x000000f0 + TilePixel \pat, 8, 6 @ #0x00000f00 + TilePixel \pat, 12, 7 @ #0x0000f000 +.endm + +@ shadow/hilight mode + +@ this one is for hi priority layer +.macro TilePixelShHP pat lsrr offs + TilePixel \pat, \lsrr, \offs + ldreqb r4, [r1,#\offs] + tsteq r4, #0x80 + andeq r4, r4, #0x3f + streqb r4, [r1,#\offs] +.endm + +@ TileNorm (r1=pdest, r2=pixels8, r3=pal) r4: scratch, pat: register with helper pattern 0xf +.macro TileNormShHP pat + TilePixelShHP \pat, 12, 0 @ #0x0000f000 + TilePixelShHP \pat, 8, 1 @ #0x00000f00 + TilePixelShHP \pat, 4, 2 @ #0x000000f0 + TilePixelShHP \pat, 0, 3 @ #0x0000000f + TilePixelShHP \pat, 28, 4 @ #0xf0000000 + TilePixelShHP \pat, 24, 5 @ #0x0f000000 + TilePixelShHP \pat, 20, 6 @ #0x00f00000 + TilePixelShHP \pat, 16, 7 @ #0x000f0000 +.endm + +@ TileFlip (r1=pdest, r2=pixels8, r3=pal) r4: scratch, pat: register with helper pattern 0xf +.macro TileFlipShHP pat + TilePixelShHP \pat, 16, 0 @ #0x000f0000 + TilePixelShHP \pat, 20, 1 @ #0x00f00000 + TilePixelShHP \pat, 24, 2 @ #0x0f000000 + TilePixelShHP \pat, 28, 3 @ #0xf0000000 + TilePixelShHP \pat, 0, 4 @ #0x0000000f + TilePixelShHP \pat, 4, 5 @ #0x000000f0 + TilePixelShHP \pat, 8, 6 @ #0x00000f00 + TilePixelShHP \pat, 12, 7 @ #0x0000f000 +.endm + + +@ TileSingleSh (r1=pdest, r2=pixels8, r3=pal) r4,r7: scratch, r0=sx; r12: helper pattern 0xf +.macro TileSingleSh + tst r0, #1 @ not aligned? + mov r7, #0x00c000 + orr r7, r7, #0xc0 + ldrneb r4, [r1] + ldreqh r4, [r1] + orr r4, r4, r7 + strneb r4, [r1], #1 + streqh r4, [r1], #2 + ldrh r4, [r1] + orr r4, r4, r7 + strh r4, [r1], #2 + ldrh r4, [r1] + orr r4, r4, r7 + strh r4, [r1], #2 + ldrh r4, [r1] + orr r4, r4, r7 + strh r4, [r1], #2 + ldrneb r4, [r1] + orr r4, r4, r7 + strneb r4, [r1], #1 +.endm + +@ TileSingleHi (r1=pdest, r2=pixels8, r3=pal) r4,r7: scratch, r0=sx, r12: register with helper pattern 0xf +.macro TileSingleHi + tst r1, #1 @ not aligned? + mov r7, #0x008000 + orr r7, r7, #0x80 + ldrneb r4, [r1] + ldreqh r4, [r1] + bic r4, r4, r7, lsr #1 + orr r4, r4, r7 + strneb r4, [r1], #1 + streqh r4, [r1], #2 + ldrh r4, [r1] + bic r4, r4, r7, lsr #1 + orr r4, r4, r7 + strh r4, [r1], #2 + ldrh r4, [r1] + bic r4, r4, r7, lsr #1 + orr r4, r4, r7 + strh r4, [r1], #2 + ldrh r4, [r1] + bic r4, r4, r7, lsr #1 + orr r4, r4, r7 + strh r4, [r1], #2 + ldrneb r4, [r1] + bic r4, r4, r7, lsr #1 + orr r4, r4, r7 + strneb r4, [r1], #1 +.endm + +.macro TileDoShGenPixel shift ofs +.if \shift + ands r4, r12, r2, lsr #\shift +.else + ands r4, r12, r2 +.endif + beq 3f + cmp r4, #0xe + beq 2f + bgt 1f + orr r4, r3, r4 + strb r4, [r1,#\ofs] + b 3f +1: + ldrb r4, [r1,#\ofs] + orr r4, r4, #0xc0 + strb r4, [r1,#\ofs] + b 3f +2: + ldrb r4, [r1,#\ofs] + bic r4, r4, #0xc0 + orr r4, r4, #0x80 + strb r4, [r1,#\ofs] +3: +.endm + +@ TileFlipSh (r1=pdest, r2=pixels8, r3=pal) r4,r7: scratch, r0=sx, r12: register with helper pattern 0xf +.macro TileFlipSh + TileDoShGenPixel 16, 0 @ #0x000f0000 + TileDoShGenPixel 20, 1 @ #0x00f00000 + TileDoShGenPixel 24, 2 @ #0x0f000000 + TileDoShGenPixel 28, 3 @ #0xf0000000 + TileDoShGenPixel 0, 4 @ #0x0000000f + TileDoShGenPixel 4, 5 @ #0x000000f0 + TileDoShGenPixel 8, 6 @ #0x00000f00 + TileDoShGenPixel 12, 7 @ #0x0000f000 +.endm + +@ TileNormSh (r1=pdest, r2=pixels8, r3=pal) r4,r7: scratch, r0=sx, r12: register with helper pattern 0xf +.macro TileNormSh + TileDoShGenPixel 12, 0 @ #0x0000f000 + TileDoShGenPixel 8, 1 @ #0x00000f00 + TileDoShGenPixel 4, 2 @ #0x000000f0 + TileDoShGenPixel 0, 3 @ #0x0000000f + TileDoShGenPixel 28, 4 @ #0xf0000000 + TileDoShGenPixel 24, 5 @ #0x0f000000 + TileDoShGenPixel 20, 6 @ #0x00f00000 + TileDoShGenPixel 16, 7 @ #0x000f0000 +.endm + + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +@ struct TileStrip +@ { +@ int nametab; // 0x00 +@ int line; // 0x04 +@ int hscroll; // 0x08 +@ int xmask; // 0x0C +@ int *hc; // 0x10 (pointer to cache buffer) +@ int cells; // 0x14 +@ }; + +@ int DrawLayer(int plane, int *hcache, int maxcells, int sh) + +.global DrawLayer @ int plane, int *hcache, int maxcells, int sh + +DrawLayer: + stmfd sp!, {r4-r11,lr} + + ldr r11, =(Pico+0x22228) @ Pico.video + + mov r6, r1 @ hcache + orr r9, r2, r3, lsl #31 @ r9=maxcells|(sh<<31) + + ldrb r7, [r11, #16] @ ??hh??ww + + mov r1, r7, lsl #4 + orr r1, r1, #0x00ff + + and r10, r7, #3 + cmp r10, #1 + biclt r1, r1, #0xfc00 + biceq r1, r1, #0xfe00 + bicgt r1, r1, #0xff00 @ r1=ymask=(height<<8)|0xff; ...; // Y Mask in pixels + + add r10, r10, #5 + cmp r10, #7 + subge r10, r10, #1 @ r10=shift[width] (5,6,6,7) + + @ calculate xmask: + mov r8, #1 + mov r5, r8, lsl r10 + sub r5, r5, #1 @ r5=xmask + + @ Find name table: + tst r0, r0 + ldreqb r12, [r11, #2] + moveq r12, r12, lsl #10 + ldrneb r12, [r11, #4] + movne r12, r12, lsl #13 + and r12, r12, #(7<<13) @ r12=(ts->nametab<<1) (halfword compliant) + + ldr r2, =Scanline + ldr r2, [r2] + ldr lr, =(Pico+0x10000) @ lr=Pico.vram + + ldrh r8, [r11, #12] + mov r4, r8, lsr #8 @ pvid->reg[13] + mov r4, r4, lsl #10 @ htab=pvid->reg[13]<<9; (halfwords) + ldrb r7, [r11, #11] + tst r7, #2 + addne r4, r4, r2, lsl #2 @ htab+=Scanline<<1; // Offset by line + tst r7, #1 + biceq r4, r4, #0x1f @ htab&=~0xf; // Offset by tile + add r4, r4, r0, lsl #1 @ htab+=plane + bic r4, r4, #0x00ff0000 @ just in case + ldrh r3, [lr, r4] @ r3=hscroll + + tst r7, #4 + bne .DrawStrip_vsscroll + + @ Get vertical scroll value: + add r7, lr, #0x012000 + add r7, r7, #0x000180 @ r7=Pico.vsram (Pico+0x22180) + ldr r7, [r7] + + tst r8, #2 + tstne r8, #4 + bne .DrawStrip_interlace + + tst r0, r0 + movne r7, r7, lsr #16 + + @ Find the line in the name table + add r2, r2, r7 + and r2, r2, r1 + mov r4, r2, lsr #3 + add r10, r10, #1 @ shift[width]++ + add r12, r12, r4, lsl r10 @ nametab+=(ts.line>>3)<hscroll, r5=ts->xmask, r6=ts->hc, r9=ts->cells +@ mov r12,r1, lsl #1 @ r12=(ts->nametab<<1) (halfword compliant) + + and r10,r2, #7 + mov r10,r10, lsl #1 @ r10=ty=(ts->line&7)<<1; + orr r10,r10, r9, lsl #24 + + rsb r8, r3, #0 + mov r8, r8, lsr #3 @ r8=tilex=(-ts->hscroll)>>3 + + sub r1, r3, #1 + and r1, r1, #7 + add r4, r1, #1 @ r4=dx=((ts->hscroll-1)&7)+1 + + tst r9, #1<<31 + mov r3, #0 + orrne r10,r10, #1<<23 @ r10=(cells<<24|sh<<23|hi_not_empty<<22|ty) + movne r3, #0x40 @ default to shadowed pal on sh mode + + mvn r9, #0 @ r9=prevcode=-1 + + @ cache some stuff to avoid mem access +@ ldr r11,=HighCol + ldr r11,=DrawLineInt + ldr r11,[r11] + add r1, r11, r4 @ r1=pdest + mov r0, #0xf + + cmp r4, #8 + subeq r10,r10, #0x01000000 @ we will loop cells+1 times, so loop less when there is no scroll + beq .dsloop_enter + + @ do first iteration with clipping + and r7, r5, r8 + add r7, lr, r7, lsl #1 @ Pico.vram+((tilex&ts->xmask) as halfwords) + ldrh r7, [r7, r12] @ r7=code (int, but from unsigned, no sign extend) + + tst r7, #0x8000 + bne .DrawStrip_hiprio + + mov r9, r7 @ remember code + + movs r2, r9, lsl #20 @ if (code&0x1000) + mov r2, r2, lsl #1 + add r2, r2, r10, lsl #17 + mov r2, r2, lsr #17 + eorcs r2, r2, #0x0e @ if (code&0x1000) addr^=0xe; + + ldr r2, [lr, r2, lsl #1] @ pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + + bic r7, r3, #0x3f + and r3, r9, #0x6000 + add r3, r7, r3, lsr #9 @ r3=pal=((code&0x6000)>>9); + + tst r2, r2 + beq .dsloop @ tileline blank + + tst r9, #0x0800 + addne r4, r4, #8 + + ldr pc, [pc, r4, lsl #2] + nop + .word .ds_tn1_px1 @ should not happen + .word .ds_tn1_px1 + .word .ds_tn1_px2 + .word .ds_tn1_px3 + .word .ds_tn1_px4 + .word .ds_tn1_px5 + .word .ds_tn1_px6 + .word .ds_tn1_px7 + .word .dsloop @ should not happen + + .word .ds_tf1_px1 @ ... + .word .ds_tf1_px1 + .word .ds_tf1_px2 + .word .ds_tf1_px3 + .word .ds_tf1_px4 + .word .ds_tf1_px5 + .word .ds_tf1_px6 + .word .ds_tf1_px7 + .word .dsloop @ ... + + @ (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r0: helper pattern +.ds_tn1_px1: + TilePixel r0, 8, 1 @ #0x00000f00 +.ds_tn1_px2: + TilePixel r0, 4, 2 @ #0x000000f0 +.ds_tn1_px3: + TilePixel r0, 0, 3 @ #0x0000000f +.ds_tn1_px4: + TilePixel r0, 28, 4 @ #0xf0000000 +.ds_tn1_px5: + TilePixel r0, 24, 5 @ #0x0f000000 +.ds_tn1_px6: + TilePixel r0, 20, 6 @ #0x00f00000 +.ds_tn1_px7: + TilePixel r0, 16, 7 @ #0x000f0000 + b .dsloop + +.ds_tf1_px1: + TilePixel r0, 20, 1 @ #0x00f00000 +.ds_tf1_px2: + TilePixel r0, 24, 2 @ #0x0f000000 +.ds_tf1_px3: + TilePixel r0, 28, 3 @ #0xf0000000 +.ds_tf1_px4: + TilePixel r0, 0, 4 @ #0x0000000f +.ds_tf1_px5: + TilePixel r0, 4, 5 @ #0x000000f0 +.ds_tf1_px6: + TilePixel r0, 8, 6 @ #0x00000f00 +.ds_tf1_px7: + TilePixel r0, 12, 7 @ #0x0000f000 + + + @ r4 & r7 are scratch in this loop +.dsloop: @ 40-41 times + add r1, r1, #8 +.dsloop_nor1: + subs r10,r10, #0x01000000 + add r8, r8, #1 + bmi .dsloop_exit + +.dsloop_enter: + and r7, r5, r8 + add r7, lr, r7, lsl #1 @ Pico.vram+((tilex&ts->xmask) as halfwords) + ldrh r7, [r7, r12] @ r7=code (int, but from unsigned, no sign extend) + + tst r7, #0x8000 + bne .DrawStrip_hiprio + + cmp r7, r9 + beq .DrawStrip_samecode @ we know stuff about this tile already + + mov r9, r7 @ remember code + + movs r2, r9, lsl #20 @ if (code&0x1000) + mov r2, r2, lsl #1 +@ bic r7, r10,#0xff000000 +@ add r2, r7, r2, lsr #17 @ r2=addr=(code&0x7ff)<<4; addr+=ty + add r2, r2, r10, lsl #17 + mov r2, r2, lsr #17 + eorcs r2, r2, #0x0e @ if (code&0x1000) addr^=0xe; + + bic r7, r3, #0x3f + and r3, r9, #0x6000 + add r3, r7, r3, lsr #9 @ r3=pal=((code&0x6000)>>9); + + ldr r2, [lr, r2, lsl #1] @ pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + +.DrawStrip_samecode: + tst r2, r2 + beq .dsloop @ tileline blank + + cmp r2, r2, ror #4 + beq .DrawStrip_SingleColor @ tileline singlecolor + + tst r9, #0x0800 + beq .DrawStrip_TileNorm + + @ (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r0: helper pattern + TileFlip r0 + b .dsloop + +.DrawStrip_TileNorm: + TileNorm r0 + b .dsloop + +.DrawStrip_SingleColor: + and r4, r2, #0xf + orr r4, r3, r4 + orr r4, r4, r4, lsl #8 + tst r1, #1 @ not aligned? + strneb r4, [r1], #1 + streqh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strneb r4, [r1], #1 @ have a remaining unaligned pixel? + b .dsloop_nor1 @ we incremeted r1 ourselves + +.DrawStrip_hiprio: + tst r10, #0x00c00000 + beq .DrawStrip_hiprio_maybempt + sub r0, r1, r11 + orr r7, r7, r0, lsl #16 + orr r7, r7, r10, lsl #25 @ (ty<<25) + tst r7, #0x1000 + eorne r7, r7, #7<<26 @ if(code&0x1000) cval^=7<<26; + str r7, [r6], #4 @ cache hi priority tile + mov r0, #0xf + b .dsloop + +.DrawStrip_hiprio_maybempt: + cmp r7, r9 + beq .dsloop @ must've been empty, otherwise we wouldn't get here + mov r9, r7 @ remember code + movs r2, r9, lsl #20 @ if (code&0x1000) + mov r2, r2, lsl #1 + add r2, r2, r10, lsl #17 + mov r2, r2, lsr #17 + eorcs r2, r2, #0x0e @ if (code&0x1000) addr^=0xe; + ldr r2, [lr, r2, lsl #1] @ pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + tst r2, r2 + orrne r10, r10, #1<<22 + bne .DrawStrip_hiprio + b .dsloop + +.dsloop_exit: + mov r0, #0 + str r0, [r6] @ terminate the cache list + + ldmfd sp!, {r4-r11,lr} + bx lr + + +.DrawStrip_vsscroll: + @ shit, we have 2-cell column based vscroll + @ let the c code handle this (for now) + + @ int nametab; // 0x00 + @ int line; // 0x04 + @ int hscroll; // 0x08 + @ int xmask; // 0x0C + @ int *hc; // 0x10 (pointer to cache buffer) + @ int cells; // 0x14 + + sub sp, sp, #6*4 + orr r2, r1, r10, lsl #24 @ ts.line=ymask|(shift[width]<<24); // save some stuff instead of line + mov r1, r0 @ plane + mov r0, r12, lsr #1 @ halfwords + and r9, r9, #0xff + stmia sp, {r0,r2,r3,r5,r6,r9} + + mov r0, sp + bl DrawStripVSRam @ struct TileStrip *ts, int plane + + add sp, sp, #6*4 + ldmfd sp!, {r4-r11,lr} + bx lr + +@ interlace mode 2? Sonic 2? +.DrawStrip_interlace: + tst r0, r0 + moveq r7, r7, lsl #21 + movne r7, r7, lsl #5 + + @ Find the line in the name table + add r2, r7, r2, lsl #22 @ r2=(vscroll+(Scanline<<1))<<21 (11 bits); + orr r1, r1, #0x80000000 + and r2, r2, r1, ror #10 @ &((ymask<<1)|1)<<21; + mov r2, r2, lsr #21 + mov r4, r2, lsr #4 + mov r12, r12, lsr #1 @ halfwords + add r0, r12, r4, lsl r10 @ nametab+=(ts.line>>4)<>9); + + ldr r2, [lr, r2, lsl #1] @ pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + +.dtfc_samecode: + tst r8, r8 + bne .dtfc_shadow + + tst r2, r2 + beq .dtfc_loop + + cmp r2, r2, ror #4 + beq .dtfc_SingleColor @ tileline singlecolor + + tst r5, #0x0800 + beq .dtfc_TileNorm + + @ (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r12: helper pattern + TileFlip r12 + b .dtfc_loop + +.dtfc_TileNorm: + TileNorm r12 + b .dtfc_loop + +.dtfc_SingleColor: + and r4, r2, #0xf + orr r4, r3, r4 + orr r4, r4, r4, lsl #8 + tst r1, #1 @ not aligned? + strneb r4, [r1], #1 + streqh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strneb r4, [r1], #1 @ have a remaining unaligned pixel? + b .dtfc_loop + +.dtfc_shadow: + tst r2, r2 + beq .dtfc_shadow_blank + + cmp r2, r2, ror #4 + beq .dtfc_SingleColor @ tileline singlecolor + + tst r5, #0x0800 + beq .dtfc_TileNormShHP + + @ (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r12: helper pattern + TileFlipShHP r12 + b .dtfc_loop + +.dtfc_TileNormShHP: + TileNormShHP r12 + b .dtfc_loop + +.dtfc_shadow_blank: + ldrb r4, [r1] + tst r4, #0x80 + andeq r4, r4,#0x3f + streqb r4, [r1] + ldrb r4, [r1,#1] + tst r4, #0x80 + andeq r4, r4,#0x3f + streqb r4, [r1,#1] + ldrb r4, [r1,#2] + tst r4, #0x80 + andeq r4, r4,#0x3f + streqb r4, [r1,#2] + ldrb r4, [r1,#3] + tst r4, #0x80 + andeq r4, r4,#0x3f + streqb r4, [r1,#3] + ldrb r4, [r1,#4] + tst r4, #0x80 + andeq r4, r4,#0x3f + streqb r4, [r1,#4] + ldrb r4, [r1,#5] + tst r4, #0x80 + andeq r4, r4,#0x3f + streqb r4, [r1,#5] + ldrb r4, [r1,#6] + tst r4, #0x80 + andeq r4, r4,#0x3f + streqb r4, [r1,#6] + ldrb r4, [r1,#7] + tst r4, #0x80 + andeq r4, r4,#0x3f + streqb r4, [r1,#7] + b .dtfc_loop + +.pool + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + +.global DrawSpritesFromCache @ int *hc, int sh + +DrawSpritesFromCache: + stmfd sp!, {r4-r11,lr} + + @ cache some stuff to avoid mem access +@ ldr r11,=HighCol + ldr r11,=DrawLineInt + ldr r11,[r11] + ldr lr, =(Pico+0x10000) @ lr=Pico.vram + mov r6, r1, lsl #31 + orr r6, r6, #1<<30 + mov r12,#0xf + + mov r10, r0 + +.dsfc_loop: + ldr r9, [r10], #4 @ read code + tst r9, r9 + ldmeqfd sp!, {r4-r11,pc} + + mov r4, r9, lsl #28 + bic r6, r6, #7 + orr r6, r6, r4, lsr #30 + add r6, r6, #1 @ r6=s1cc???? ... ?????www (s=shadow/hilight, cc=pal, w=width) + + and r5, r9, #3 + add r5, r5, #1 @ r5=delta + tst r9, #0x10000 + rsbne r5, r5, #0 @ Flip X + mov r5, r5, lsl #4 + + mov r2, r9, lsr #17 + mov r8, r2, lsl #1 @ tile=((unsigned int)code>>17)<<1; + + and r3, r9, #0x30 @ r3=pal=(code&0x30); + + bic r6, r6, #3<<28 + orr r6, r6, r3, lsl #24 + + mov r0, r9, lsl #16 + mov r0, r0, asr #22 @ sx=(code<<16)>>22 + adds r0, r0, #0 @ set ZV + b .dsfc_inloop_enter + +@ scratch: r4, r7 +.dsfc_inloop: + sub r6, r6, #1 + tst r6, #7 + beq .dsfc_loop + adds r0, r0, #8 + add r8, r8, r5 + +.dsfc_inloop_enter: + ble .dsfc_inloop + cmp r0, #328 + bge .dsfc_loop + + mov r8, r8, lsl #17 + mov r8, r8, lsr #17 @ tile&=0x7fff; // Clip tile address + + ldr r2, [lr, r8, lsl #1] @ pack=*(unsigned int *)(Pico.vram+tile); // Get 8 pixels + tst r2, r2 + beq .dsfc_inloop + + add r1, r11, r0 @ r1=pdest + + cmp r12, r6, lsr #28 + beq .dsfc_shadow + + cmp r2, r2, ror #4 + beq .dsfc_SingleColor @ tileline singlecolor + + tst r9, #0x10000 + beq .dsfc_TileNorm + + @ TileFlip (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r12: helper pattern + TileFlip r12 + b .dsfc_inloop + +.dsfc_TileNorm: + TileNorm r12 + b .dsfc_inloop + +.dsfc_SingleColor: + tst r0, #1 @ not aligned? + and r4, r2, #0xf + orr r4, r3, r4 + orr r4, r4, r4, lsl #8 + strneb r4, [r1], #1 + streqh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strneb r4, [r1], #1 + b .dsfc_inloop + +.dsfc_shadow: + cmp r2, r2, ror #4 + beq .dsfc_singlec_sh + + tst r9, #0x10000 + beq .dsfc_TileNorm_sh + + @ (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r12: helper pattern + TileFlipSh + b .dsfc_inloop + +.dsfc_TileNorm_sh: + TileNormSh + b .dsfc_inloop + +.dsfc_singlec_sh: + cmp r2, #0xe0000000 + bcc .dsfc_SingleColor @ normal singlecolor tileline (carry inverted in ARM) + tst r2, #0x10000000 + bne .dsfc_sh_sh + TileSingleHi + b .dsfc_inloop + +.dsfc_sh_sh: + TileSingleSh + b .dsfc_inloop + +.pool + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +@ + 0 : hhhhvvvv ab--hhvv yyyyyyyy yyyyyyyy // a: offscreen h, b: offs. v, h: horiz. size +@ + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8 + +.global DrawSprite @ unsigned int *sprite, int **hc, int sh + +DrawSprite: + stmfd sp!, {r4-r9,r11,lr} + + ldr r3, [r0] @ sprite[0] + mov r6, r3, lsr #28 + sub r6, r6, #1 @ r6=width-1 (inc later) + mov r5, r3, lsr #24 + and r5, r5, #7 @ r5=height + + mov r4, r3, lsl #16 @ r4=sy<<16 (tmp) + + ldr r7, =Scanline + ldr r7, [r7] + sub r7, r7, r4, asr #16 @ r7=row=Scanline-sy + + tst r2, r2 + ldr r9, [r0, #4] + mov r2, r9, asr #16 @ r2=sx + bic r9, r9, #0xfe000000 + orrne r9, r9, #1<<31 @ r9=code|(sh<<31) + + tst r9, #0x1000 + movne r4, r5, lsl #3 + subne r4, r4, #1 + subne r7, r4, r7 @ if (code&0x1000) row=(height<<3)-1-row; // Flip Y + + mov r8, r9, lsl #21 + mov r8, r8, lsr #21 + add r8, r8, r7, lsr #3 @ tile+=row>>3; // Tile number increases going down + + tst r9, #0x0800 + mlane r8, r5, r6, r8 @ if (code&0x0800) { tile+=delta*(width-1); + rsbne r5, r5, #0 @ delta=-delta; } // r5=delta now + + mov r8, r8, lsl #4 + and r7, r7, #7 + add r8, r8, r7, lsl #1 @ tile+=(row&7)<<1; // Tile address + + tst r9, #0x8000 + bne .dspr_cache @ if(code&0x8000) // high priority - cache it + + @ cache some stuff to avoid mem access +@ ldr r11,=HighCol + ldr r11,=DrawLineInt + ldr r11,[r11] + ldr lr, =(Pico+0x10000) @ lr=Pico.vram + mov r12,#0xf + + mov r5, r5, lsl #4 @ delta<<=4; // Delta of address + and r4, r9, #0x6000 + orr r9, r9, r4, lsl #16 + orr r9, r9, #0x10000000 @ r9=scc1 ???? ... (s=shadow/hilight, cc=pal) + + tst r9, #1<<31 + mov r3, r4, lsr #9 @ r3=pal=((code>>9)&0x30); + orrne r3, r3, #0x40 @ shadow by default + + add r6, r6, #1 @ inc now + adds r0, r2, #0 @ mov sx to r0 and set ZV flags + b .dspr_loop_enter + +.dspr_loop: + subs r6, r6, #1 @ width-- + ldmeqfd sp!, {r4-r9,r11,pc}@ return + adds r0, r0, #8 @ sx+=8 + add r8, r8, r5 @ tile+=delta + +.dspr_loop_enter: + ble .dspr_loop @ sx <= 0 + cmp r0, #328 + ldmgefd sp!, {r4-r9,r11,pc}@ return + + mov r8, r8, lsl #17 + mov r8, r8, lsr #17 @ tile&=0x7fff; // Clip tile address + + ldr r2, [lr, r8, lsl #1] @ pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + tst r2, r2 + beq .dspr_loop + + add r1, r11, r0 @ r1=pdest + + cmp r12, r9, lsr #28 + beq .dspr_shadow + + cmp r2, r2, ror #4 + beq .dspr_SingleColor @ tileline singlecolor + + tst r9, #0x0800 + beq .dspr_TileNorm + + @ (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r12: helper pattern + TileFlip r12 + b .dspr_loop + +@ scratch: r4, r7 +.dspr_TileNorm: + TileNorm r12 + b .dspr_loop + +.dspr_SingleColor: + and r4, r2, #0xf + orr r4, r3, r4 + orr r4, r4, r4, lsl #8 + tst r0, #1 @ not aligned? + strneb r4, [r1], #1 + streqh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strh r4, [r1], #2 + strneb r4, [r1], #1 + b .dspr_loop + +.dspr_shadow: + cmp r2, r2, ror #4 + beq .dspr_singlec_sh + + tst r9, #0x0800 + beq .dspr_TileNorm_sh + + @ (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r12: helper pattern + TileFlipSh + b .dspr_loop + +.dspr_TileNorm_sh: + TileNormSh + b .dspr_loop + +.dspr_singlec_sh: + cmp r2, #0xe0000000 + bcc .dspr_SingleColor @ normal tileline + tst r2, #0x10000000 + bne .dspr_sh_sh + TileSingleHi + b .dspr_loop + +.dspr_sh_sh: + TileSingleSh + b .dspr_loop + + +.dspr_cache: + @ *(*hc)++ = (tile<<16)|((code&0x0800)<<5)|((sx<<6)&0x0000ffc0)|((code>>9)&0x30)|((sprite[0]>>24)&0xf); + mov r4, r8, lsl #16 @ tile + tst r9, #0x0800 + orrne r4, r4, #0x10000 @ code&0x0800 + mov r2, r2, lsl #22 + orr r4, r4, r2, lsr #16 @ (sx<<6)&0x0000ffc0 + and r2, r9, #0x6000 + orr r4, r4, r2, lsr #9 @ (code>>9)&0x30 + mov r2, r3, lsl #12 + orr r4, r4, r2, lsr #28 @ (sprite[0]>>24)&0xf + + ldr r2, [r1] + str r4, [r2], #4 + str r2, [r1] + + ldmfd sp!, {r4-r9,r11,lr} + bx lr + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +.global DrawWindow @ int tstart, int tend, int prio, int sh // int *hcache + +DrawWindow: + stmfd sp!, {r4-r11,lr} + + ldr r11, =(Pico+0x22228) @ Pico.video + ldrb r12, [r11, #3] @ pvid->reg[3] + mov r12, r12, lsl #10 + + ldr r10, =Scanline + ldr r10, [r10] + mov r5, r10, lsr #3 + and r10, r10, #7 + mov r10, r10, lsl #1 @ r10=ty + + ldr r4, [r11, #12] + tst r4, #1 @ 40 cell mode? + andne r12, r12, #0xf000 @ 0x3c<<10 + andeq r12, r12, #0xf800 + addne r12, r12, r5, lsl #7 + addeq r12, r12, r5, lsl #6 @ nametab + add r12, r12, r0, lsl #2 @ +starttile + + ldr lr, =(Pico+0x10000) @ lr=Pico.vram + + @ fetch the first code now + ldrh r7, [lr, r12] + + ldr r6, =rendstatus + ldrb r6, [r6] + ands r6, r6, #2 @ we care about bit 1 only + orr r6, r6, r2 + bne .dw_no_sameprio + + cmp r2, r7, lsr #15 + ldmnefd sp!, {r4-r11,pc} @ assume that whole window uses same priority + +.dw_no_sameprio: + orr r6, r6, r3, lsl #8 @ shadow mode + + sub r8, r1, r0 + mov r8, r8, lsl #1 @ cells + + mvn r9, #0 @ r9=prevcode=-1 + + @ cache some stuff to avoid mem access +@ ldr r11,=(HighCol+8) + ldr r11,=DrawLineInt + ldr r11,[r11] + add r11,r11, #8 + add r1, r11, r0, lsl #4 @ r1=pdest + mov r0, #0xf + b .dwloop_enter + + @ r4,r5 & r7 are scratch in this loop +.dwloop: + add r1, r1, #8 +.dwloop_nor1: + subs r8, r8, #1 + add r12, r12, #2 @ halfwords + beq .dwloop_end @ done + + ldrh r7, [lr, r12] @ r7=code (int, but from unsigned, no sign extend) + + eor r5, r6, r7, lsr #15 + tst r5, #1 + orrne r6, r6, #2 @ wrong pri + bne .dwloop + + cmp r7, r9 + beq .dw_samecode @ we know stuff about this tile already + +.dwloop_enter: + mov r9, r7 @ remember code + + movs r2, r9, lsl #20 @ if (code&0x1000) + mov r2, r2, lsl #1 + add r2, r10, r2, lsr #17 @ r2=addr=(code&0x7ff)<<4; addr+=ty + eorcs r2, r2, #0x0e @ if (code&0x1000) addr^=0xe; + + and r3, r9, #0x6000 + mov r3, r3, lsr #9 @ r3=pal=((code&0x6000)>>9); + + ldr r2, [lr, r2, lsl #1] @ pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + +.dw_samecode: + tst r6, #0x100 + bne .dw_shadow +.dw_shadow_done: + tst r2, r2 + beq .dwloop @ tileline blank + + cmp r2, r2, ror #4 + beq .dw_SingleColor @ tileline singlecolor + + tst r9, #0x0800 + beq .dw_TileNorm + + @ (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r0: helper pattern + TileFlip r0 + b .dwloop + +.dw_TileNorm: + TileNorm r0 + b .dwloop + +.dw_SingleColor: + and r4, r0, r2 @ #0x0000000f + orr r4, r3, r4 + orr r4, r4, r4, lsl #8 + orr r4, r4, r4, lsl #16 + mov r5, r4 + stmia r1!, {r4,r5} + b .dwloop_nor1 @ we incremeted r1 ourselves + +.dw_shadow: + tst r6, #1 @ hi pri? + orreq r3, r3, #0x40 + beq .dw_shadow_done + ldr r4, [r1] + tst r4, #0x00000080 + biceq r4, r4, #0x000000c0 + tst r4, #0x00008000 + biceq r4, r4, #0x0000c000 + tst r4, #0x00800000 + biceq r4, r4, #0x00c00000 + tst r4, #0x80000000 + biceq r4, r4, #0xc0000000 + str r4, [r1] + ldr r4, [r1,#4] + tst r4, #0x00000080 + biceq r4, r4, #0x000000c0 + tst r4, #0x00008000 + biceq r4, r4, #0x0000c000 + tst r4, #0x00800000 + biceq r4, r4, #0x00c00000 + tst r4, #0x80000000 + biceq r4, r4, #0xc0000000 + str r4, [r1,#4] + b .dw_shadow_done + +.dwloop_end: + ldr r0, =rendstatus + ldr r1, [r0] + and r6, r6, #2 + orr r1, r1, r6 + str r1, [r0] + + ldmfd sp!, {r4-r11,r12} + bx r12 + + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + +@ hilights 2 pixels in RGB444/BGR444 format +.macro TileDoShHi2Pixels444 reg + mov \reg, \reg, ror #12 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #28 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #28 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #24 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #28 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #28 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #12 +.endm + + +.global FinalizeLineBGR444 @ int sh + +FinalizeLineBGR444: + stmfd sp!, {r4-r6,lr} + mov r6, r0 + ldr r0, =DrawLineDest + ldr r0, [r0] + ldr lr, =(Pico+0x22228) @ Pico.video + sub r3, lr, #0x128 @ r3=Pico.cram + + ldrb r12, [lr, #12] + tst r12, #1 + movne r2, #320/4 @ len + moveq r2, #256/4 + addeq r0, r0, #32*2 + ldreq r4, =PicoOpt + ldreq r4, [r4] + tsteq r4, #0x100 + addeq r0, r0, #32*2 + + tst r6, r6 + beq .fl_noshBGR444 + + ldr r4, =HighPal + + ldrb r12, [lr, #-0x1a] @ 0x2220e ~ dirtyPal + tst r12, r12 + moveq r3, r4 + beq .fl_noshBGR444 + mov r12, #0 + strb r12, [lr, #-0x1a] + + mov lr, #0x40/8 + @ copy pal: +.fl_loopcpBGR444: + subs lr, lr, #1 + ldmia r3!, {r1,r5,r6,r12} + stmia r4!, {r1,r5,r6,r12} + bne .fl_loopcpBGR444 + + @ shadowed pixels: + mov r12, #0x0077 + orr r12,r12,#0x0700 + orr r12,r12,r12,lsl #16 + sub r3, r3, #0x40*2 + add r5, r4, #0x80*2 + mov lr, #0x40/4 +.fl_loopcpBGR444_sh: + subs lr, lr, #1 + ldmia r3!, {r1,r6} + and r1, r12, r1, lsr #1 + and r6, r12, r6, lsr #1 + stmia r4!, {r1,r6} + stmia r5!, {r1,r6} + bne .fl_loopcpBGR444_sh + + @ hilighted pixels: + sub r3, r3, #0x40*2 + mov lr, #0x40/2 +.fl_loopcpBGR444_hi: + ldr r1, [r3], #4 + TileDoShHi2Pixels444 r1 + str r1, [r4], #4 + subs lr, lr, #1 + bne .fl_loopcpBGR444_hi + + sub r3, r4, #0x40*3*2 + + +.fl_noshBGR444: +@ ldr r1, =(HighCol+8) + ldr r1, =DrawLineInt + ldr r1, [r1] + add r1, r1, #8 + mov lr, #0xff + mov lr, lr, lsl #1 + +.fl_loopBGR444: + subs r2, r2, #1 + + ldr r12, [r1], #4 + + and r4, lr, r12, lsl #1 + ldrh r4, [r3, r4] + and r5, lr, r12, lsr #7 + ldrh r5, [r3, r5] + orr r4, r4, r5, lsl #16 + + and r5, lr, r12, lsr #15 + ldrh r5, [r3, r5] + and r6, lr, r12, lsr #23 + ldrh r6, [r3, r6] + orr r5, r5, r6, lsl #16 + + stmia r0!, {r4,r5} + bne .fl_loopBGR444 + + + ldmfd sp!, {r4-r6,lr} + bx lr + + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + +@ hilights 2 pixels in RGB555/BGR555 format +.macro TileDoShHi2Pixels555 reg + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #27 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #26 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #27 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #27 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #26 + adds \reg, \reg, #0x40000000 + orrcs \reg, \reg, #0xf0000000 + mov \reg, \reg, ror #27 +.endm + + +@ Convert 0000bbb0 ggg0rrr0 +@ to rrrrrggg gggbbbbb + +@ r2,r3,r9 - scratch, lr = 0x001c001c, r8 = 0x00030003 +.macro convRGB565 reg + and r2, lr, \reg,lsl #1 + and r9, r8, \reg,lsr #2 + orr r2, r2, r9 @ r2=red + and r3, lr, \reg,lsr #7 + and r9, r8, \reg,lsr #10 + orr r3, r3, r9 @ r3=blue + and \reg, \reg, lr, lsl #3 + orr \reg, \reg, \reg,lsl #3 @ green + orr \reg, \reg, r2, lsl #11 @ add red back + orr \reg, \reg, r3 @ add blue back +.endm + +vidConvCpyRGB565: @ void *to, void *from, int pixels + stmfd sp!, {r4-r9,lr} + + mov r12, r2, lsr #3 @ repeats + mov lr, #0x001c0000 + orr lr, lr, #0x01c @ lr == pattern 0x001c001c + mov r8, #0x00030000 + orr r8, r8, #0x003 @ lr == pattern 0x001c001c + +.loopRGB565: + subs r12, r12, #1 + + ldmia r1!, {r4-r7} + convRGB565 r4 + str r4, [r0], #4 + convRGB565 r5 + str r5, [r0], #4 + convRGB565 r6 + str r6, [r0], #4 + convRGB565 r7 + str r7, [r0], #4 + + bgt .loopRGB565 + + ldmfd sp!, {r4-r9,lr} + bx lr + + + +.global FinalizeLineRGB555 @ int sh + +FinalizeLineRGB555: + stmfd sp!, {r4-r8,lr} + ldr r5, =(Pico+0x22228) @ Pico.video + ldr r4, =HighPal + mov r6, r0 + + ldrb r7, [r5, #-0x1a] @ 0x2220e ~ dirtyPal + tst r7, r7 + beq .fl_noconvRGB555 + mov r1, #0 + strb r1, [r5, #-0x1a] + sub r1, r5, #0x128 @ r1=Pico.cram + mov r0, r4 + mov r2, #0x40 + bl vidConvCpyRGB565 + +.fl_noconvRGB555: + ldr r0, =DrawLineDest + ldr r0, [r0] + + ldrb r12, [r5, #12] + tst r12, #1 + movne r2, #320/8 @ len + moveq r2, #256/8 + ldreq r3, =PicoOpt + ldreq r3, [r3] + tsteq r3, #0x100 + addeq r0, r0, #32*2 + + mov r3, r4 + tst r6, r6 + beq .fl_noshRGB555 + tst r7, r7 + beq .fl_noshRGB555 + + @ shadowed pixels: + mov r12, #0x008e + orr r12,r12,#0x7300 + orr r12,r12,r12,lsl #16 + add r4, r3, #0x40*2 + add r5, r3, #0xc0*2 + mov lr, #0x40/4 +.fl_loopcpRGB555_sh: + subs lr, lr, #1 + ldmia r3!, {r1,r6} + and r1, r12, r1, lsr #1 + and r6, r12, r6, lsr #1 + stmia r4!, {r1,r6} + stmia r5!, {r1,r6} + bne .fl_loopcpRGB555_sh + + @ hilighted pixels: + sub r3, r3, #0x40*2 + mov lr, #0x40/2 +.fl_loopcpRGB555_hi: + ldr r1, [r3], #4 + TileDoShHi2Pixels555 r1 + str r1, [r4], #4 + subs lr, lr, #1 + bne .fl_loopcpRGB555_hi + + sub r3, r3, #0x40*2 + + +.fl_noshRGB555: +@ ldr r1, =(HighCol+8) + ldr r1, =DrawLineInt + ldr r1, [r1] + add r1, r1, #8 + mov lr, #0xff + mov lr, lr, lsl #1 + +.fl_loopRGB555: + subs r2, r2, #1 + + ldr r12, [r1], #4 + ldr r7, [r1], #4 + + and r4, lr, r12, lsl #1 + ldrh r4, [r3, r4] + and r5, lr, r12, lsr #7 + ldrh r5, [r3, r5] + orr r4, r4, r5, lsl #16 + + and r5, lr, r12, lsr #15 + ldrh r5, [r3, r5] + and r6, lr, r12, lsr #23 + ldrh r6, [r3, r6] + orr r5, r5, r6, lsl #16 + + and r8, lr, r7, lsl #1 + ldrh r8, [r3, r8] + and r6, lr, r7, lsr #7 + ldrh r6, [r3, r6] + orr r8, r8, r6, lsl #16 + + and r12,lr, r7, lsr #15 + ldrh r12,[r3, r12] + and r6, lr, r7, lsr #23 + ldrh r6, [r3, r6] + orr r12,r12, r6, lsl #16 + + stmia r0!, {r4,r5,r8,r12} + bne .fl_loopRGB555 + + + ldmfd sp!, {r4-r8,lr} + bx lr + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +@ utility +.global blockcpy @ void *dst, void *src, size_t n + +blockcpy: + stmfd sp!, {r4,r5} + mov r2, r2, lsr #4 +blockcpy_loop: + subs r2, r2, #1 + ldmia r1!, {r3-r5,r12} + stmia r0!, {r3-r5,r12} + bne blockcpy_loop + ldmfd sp!, {r4,r5} + bx lr + + +.global blockcpy_or @ void *dst, void *src, size_t n, int pat + +blockcpy_or: + stmfd sp!, {r4-r6} + orr r3, r3, r3, lsl #8 + orr r3, r3, r3, lsl #16 + mov r2, r2, lsr #4 +blockcpy_loop_or: + subs r2, r2, #1 + ldmia r1!, {r4-r6,r12} + orr r4, r4, r3 + orr r5, r5, r3 + orr r6, r6, r3 + orr r12,r12,r3 + stmia r0!, {r4-r6,r12} + bne blockcpy_loop_or + ldmfd sp!, {r4-r6} + bx lr + diff --git a/Pico/Memory.c b/Pico/Memory.c new file mode 100644 index 00000000..d3b6beeb --- /dev/null +++ b/Pico/Memory.c @@ -0,0 +1,829 @@ +// This is part of Pico Library + +// (c) Copyright 2004 Dave, All rights reserved. +// (c) Copyright 2006 notaz, All rights reserved. +// Free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + + +//#define __debug_io + +#include "PicoInt.h" + +#include "sound/sound.h" +#include "sound/ym2612.h" +#include "sound/sn76496.h" + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; + +extern unsigned int lastSSRamWrite; // used by serial SRAM code + +#ifdef _ASM_MEMORY_C +u8 PicoRead8(u32 a); +u16 PicoRead16(u32 a); +void PicoWriteRomHW_SSF2(u32 a,u32 d); +void PicoWriteRomHW_in1 (u32 a,u32 d); +#endif + + +#if defined(EMU_C68K) && defined(EMU_M68K) +// cyclone debug mode +u32 lastread_a, lastread_d[16]={0,}, lastwrite_cyc_d[16]={0,}, lastwrite_mus_d[16]={0,}; +int lrp_cyc=0, lrp_mus=0, lwp_cyc=0, lwp_mus=0; +extern unsigned int ppop; +#endif + +#if defined(EMU_C68K) || defined(EMU_A68K) +static __inline int PicoMemBase(u32 pc) +{ + int membase=0; + + if (pc>16); +#endif + return ret; +} + + +int PicoInitPc(u32 pc) +{ + PicoCheckPc(pc); + return 0; +} + +#ifndef _ASM_MEMORY_C +void PicoMemReset() +{ +} +#endif + +// ----------------------------------------------------------------- + +#ifndef _ASM_MEMORY_C +// address must already be checked +static int SRAMRead(u32 a) +{ + u8 *d = SRam.data-SRam.start+a; + return (d[0]<<8)|d[1]; +} +#endif + +static int PadRead(int i) +{ + int pad=0,value=0,TH; + pad=~PicoPad[i]; // Get inverse of pad MXYZ SACB RLDU + TH=Pico.ioports[i+1]&0x40; + + if(PicoOpt & 0x20) { // 6 button gamepad enabled + int phase = Pico.m.padTHPhase[i]; + + if(phase == 2 && !TH) { + value=(pad&0xc0)>>2; // ?0SA 0000 + goto end; + } else if(phase == 3 && TH) { + value=(pad&0x30)|((pad>>8)&0xf); // ?1CB MXYZ + goto end; + } else if(phase == 3 && !TH) { + value=((pad&0xc0)>>2)|0x0f; // ?0SA 1111 + goto end; + } + } + + if(TH) value=(pad&0x3f); // ?1CB RLDU + else value=((pad&0xc0)>>2)|(pad&3); // ?0SA 00DU + + end: + + // orr the bits, which are set as output + value |= Pico.ioports[i+1]&Pico.ioports[i+4]; + + return value; // will mirror later +} + +u8 z80Read8(u32 a) +{ + if(Pico.m.z80Run&1) return 0; + + a&=0x1fff; + + if(!(PicoOpt&4)) { + // Z80 disabled, do some faking + static u8 zerosent = 0; + if(a == Pico.m.z80_lastaddr) { // probably polling something + u8 d = Pico.m.z80_fakeval; + if((d & 0xf) == 0xf && !zerosent) { + d = 0; zerosent = 1; + } else { + Pico.m.z80_fakeval++; + zerosent = 0; + } + return d; + } else { + Pico.m.z80_fakeval = 0; + } + } + + Pico.m.z80_lastaddr = (u16) a; + return Pico.zram[a]; +} + + +// for nonstandard reads +#ifndef _ASM_MEMORY_C +static +#endif +u32 UnusualRead16(u32 a, int realsize) +{ + u32 d=0; + + dprintf("strange r%i: %06x @%06x", realsize, a&0xffffff, SekPc); + + // for games with simple protection devices, discovered by Haze + // some dumb detection is used, but that should be enough to make things work + if ((a>>22) == 1 && Pico.romsize >= 512*1024) { + if (*(int *)(Pico.rom+0x123e4) == 0x00550c39 && *(int *)(Pico.rom+0x123e8) == 0x00000040) { // Super Bubble Bobble (Unl) [!] + if (a == 0x400000) { d=0x55<<8; goto end; } + else if (a == 0x400002) { d=0x0f<<8; goto end; } + } + else if (*(int *)(Pico.rom+0x008c4) == 0x66240055 && *(int *)(Pico.rom+0x008c8) == 0x00404df9) { // Smart Mouse (Unl) + if (a == 0x400000) { d=0x55<<8; goto end; } + else if (a == 0x400002) { d=0x0f<<8; goto end; } + else if (a == 0x400004) { d=0xaa<<8; goto end; } + else if (a == 0x400006) { d=0xf0<<8; goto end; } + } + else if (*(int *)(Pico.rom+0x00404) == 0x00a90600 && *(int *)(Pico.rom+0x00408) == 0x6708b013) { // King of Fighters '98, The (Unl) [!] + if (a == 0x480000 || a == 0x4800e0 || a == 0x4824a0 || a == 0x488880) { d=0xaa<<8; goto end; } + else if (a == 0x4a8820) { d=0x0a<<8; goto end; } + // there is also a read @ 0x4F8820 which needs 0, but that is returned in default case + } + else if (*(int *)(Pico.rom+0x01b24) == 0x004013f9 && *(int *)(Pico.rom+0x01b28) == 0x00ff0000) { // Mahjong Lover (Unl) [!] + if (a == 0x400000) { d=0x90<<8; goto end; } + else if (a == 0x401000) { d=0xd3<<8; goto end; } // this one doesn't seem to be needed, the code does 2 comparisons and only then + // checks the result, which is of the above one. Left it just in case. + } + else if (*(int *)(Pico.rom+0x05254) == 0x0c3962d0 && *(int *)(Pico.rom+0x05258) == 0x00400055) { // Elf Wor (Unl) + if (a == 0x400000) { d=0x55<<8; goto end; } + else if (a == 0x400004) { d=0xc9<<8; goto end; } // this check is done if the above one fails + else if (a == 0x400002) { d=0x0f<<8; goto end; } + else if (a == 0x400006) { d=0x18<<8; goto end; } // similar to above + } + // our default behaviour is to return whatever was last written a 0x400000-0x7fffff range (used by Squirrel King (R) [!]) + // Lion King II, The (Unl) [!] writes @ 400000 and wants to get that val @ 400002 and wites another val + // @ 400004 which is expected @ 400006, so we really remember 2 values here + d = Pico.m.prot_bytes[(a>>2)&1]<<8; + } + else if (a == 0xa13000 && Pico.romsize >= 1024*1024) { + if (*(int *)(Pico.rom+0xc8af0) == 0x30133013 && *(int *)(Pico.rom+0xc8af4) == 0x000f0240) { // Rockman X3 (Unl) [!] + d=0x0c; goto end; + } + else if (*(int *)(Pico.rom+0x28888) == 0x07fc0000 && *(int *)(Pico.rom+0x2888c) == 0x4eb94e75) { // Bug's Life, A (Unl) [!] + d=0x28; goto end; // does the check from RAM + } + else if (*(int *)(Pico.rom+0xc8778) == 0x30133013 && *(int *)(Pico.rom+0xc877c) == 0x000f0240) { // Super Mario Bros. (Unl) [!] + d=0x0c; goto end; // seems to be the same code as in Rockman X3 (Unl) [!] + } + else if (*(int *)(Pico.rom+0xf20ec) == 0x30143013 && *(int *)(Pico.rom+0xf20f0) == 0x000f0200) { // Super Mario 2 1998 (Unl) [!] + d=0x0a; goto end; + } + } + else if (a == 0xa13002) { // Pocket Monsters (Unl) + d=0x01; goto end; + } + else if (a == 0xa1303E) { // Pocket Monsters (Unl) + d=0x1f; goto end; + } + else if (a == 0x30fe02) { + // Virtua Racing - just for fun + // this seems to be some flag that SVP is ready or something similar + d=1; goto end; + } + +end: + dprintf("ret = %04x", d); + return d; +} + +#ifndef _ASM_MEMORY_C +static +#endif +u32 OtherRead16(u32 a, int realsize) +{ + u32 d=0; + + if ((a&0xff0000)==0xa00000) { + if ((a&0x4000)==0x0000) { d=z80Read8(a); d|=d<<8; goto end; } // Z80 ram (not byteswaped) + if ((a&0x6000)==0x4000) { if(PicoOpt&1) d=YM2612Read(); else d=Pico.m.rotate++&3; goto end; } // 0x4000-0x5fff, Fudge if disabled + d=0xffff; goto end; + } + if ((a&0xffffe0)==0xa10000) { // I/O ports + a=(a>>1)&0xf; + switch(a) { + case 0: d=Pico.m.hardware; break; // Hardware value (Version register) + case 1: d=PadRead(0); d|=Pico.ioports[1]&0x80; break; + case 2: d=PadRead(1); d|=Pico.ioports[2]&0x80; break; + default: d=Pico.ioports[a]; break; // IO ports can be used as RAM + } + d|=d<<8; + goto end; + } + // |=0x80 for Shadow of the Beast & Super Offroad; rotate fakes next fetched instruction for Time Killers + if (a==0xa11100) { d=((Pico.m.z80Run&1)<<8)|0x8000|Pico.m.rotate++; goto end; } + +#ifndef _ASM_MEMORY_C + if ((a&0xe700e0)==0xc00000) { d=PicoVideoRead(a); goto end; } +#endif + + d = UnusualRead16(a, realsize); + +end: + return d; +} + +//extern UINT32 mz80GetRegisterValue(void *, UINT32); + +static void OtherWrite8(u32 a,u32 d,int realsize) +{ + if ((a&0xe700f9)==0xc00011||(a&0xff7ff9)==0xa07f11) { if(PicoOpt&2) SN76496Write(d); return; } // PSG Sound + if ((a&0xff4000)==0xa00000) { if(!(Pico.m.z80Run&1)) Pico.zram[a&0x1fff]=(u8)d; return; } // Z80 ram + if ((a&0xff6000)==0xa04000) { if(PicoOpt&1) emustatus|=YM2612Write(a&3, d); return; } // FM Sound + if ((a&0xffffe0)==0xa10000) { // I/O ports + a=(a>>1)&0xf; + // 6 button gamepad: if TH went from 0 to 1, gamepad changes state + if(PicoOpt&0x20) { + if(a==1) { + Pico.m.padDelay[0] = 0; + if(!(Pico.ioports[1]&0x40) && (d&0x40)) Pico.m.padTHPhase[0]++; + } + else if(a==2) { + Pico.m.padDelay[1] = 0; + if(!(Pico.ioports[2]&0x40) && (d&0x40)) Pico.m.padTHPhase[1]++; + } + } + Pico.ioports[a]=(u8)d; // IO ports can be used as RAM + return; + } + if (a==0xa11100) { + extern int z80startCycle, z80stopCycle; + //int lineCycles=(488-SekCyclesLeft)&0x1ff; + d&=1; d^=1; + if(!d) { + // hack: detect a nasty situation where Z80 was enabled and disabled in the same 68k timeslice (Golden Axe III) + if((PicoOpt&4) && Pico.m.z80Run==1) z80_run(20); + z80stopCycle = SekCyclesDone(); + //z80ExtraCycles += (lineCycles>>1)-(lineCycles>>5); // only meaningful in PicoFrameHints() + } else { + z80startCycle = SekCyclesDone(); + //if(Pico.m.scanline != -1) + //z80ExtraCycles -= (lineCycles>>1)-(lineCycles>>5)+16; + } + //dprintf("set_zrun: %i [%i|%i] zPC=%04x @%06x", d, Pico.m.scanline, SekCyclesDone(), mz80GetRegisterValue(NULL, 0), SekPc); + Pico.m.z80Run=(u8)d; return; + } + if (a==0xa11200) { if(!(d&1)) z80_reset(); return; } + + if ((a&0xff7f00)==0xa06000) // Z80 BANK register + { + Pico.m.z80_bank68k>>=1; + Pico.m.z80_bank68k|=(d&1)<<8; + Pico.m.z80_bank68k&=0x1ff; // 9 bits and filled in the new top one + return; + } + + if ((a&0xe700e0)==0xc00000) { PicoVideoWrite(a,(u16)(d|(d<<8))); return; } // Byte access gets mirrored + + // sram + //if(a==0x200000) dprintf("cc : %02x @ %06x [%i|%i]", d, SekPc, SekCyclesDoneT(), SekCyclesDone()); + //if(a==0x200001) dprintf("w8 : %02x @ %06x [%i]", d, SekPc, SekCyclesDoneT()); + if(a >= SRam.start && a <= SRam.end) { + unsigned int sreg = Pico.m.sram_reg; + if(!(sreg & 0x10)) { + // not detected SRAM + if((a&~1)==0x200000) { + Pico.m.sram_reg|=4; // this should be a game with EEPROM (like NBA Jam) + SRam.start=0x200000; SRam.end=SRam.start+1; + } + Pico.m.sram_reg|=0x10; + } + if(sreg & 4) { // EEPROM write + if(SekCyclesDoneT()-lastSSRamWrite < 46) { + // just update pending state + SRAMUpdPending(a, d); + } else { + SRAMWriteEEPROM(sreg>>6); // execute pending + SRAMUpdPending(a, d); + lastSSRamWrite = SekCyclesDoneT(); + } + } else if(!(sreg & 2)) { + u8 *pm=(u8 *)(SRam.data-SRam.start+a); + if(*pm != (u8)d) { + SRam.changed = 1; + *pm=(u8)d; + } + } + return; + } + +#ifdef _ASM_MEMORY_C + // special ROM hardware (currently only banking and sram reg supported) + if((a&0xfffff1) == 0xA130F1) { + PicoWriteRomHW_SSF2(a, d); // SSF2 or SRAM + return; + } +#else + // sram access register + if(a == 0xA130F1) { + Pico.m.sram_reg = (u8)(d&3); + return; + } +#endif + dprintf("strange w%i: %06x, %08x @%06x", realsize, a&0xffffff, d, SekPc); + + if(a >= 0xA13004 && a < 0xA13040) { + // dumb 12-in-1 or 4-in-1 banking support + int len; + a &= 0x3f; a <<= 16; + len = Pico.romsize - a; + if (len <= 0) return; // invalid/missing bank + if (len > 0x200000) len = 0x200000; // 2 megs + memcpy(Pico.rom, Pico.rom+a, len); // code which does this is in RAM so this is safe. + return; + } + + // for games with simple protection devices, discovered by Haze + else if ((a>>22) == 1) + Pico.m.prot_bytes[(a>>2)&1] = (u8)d; +} + +static void OtherWrite16(u32 a,u32 d) +{ + if ((a&0xe700e0)==0xc00000) { PicoVideoWrite(a,(u16)d); return; } + if ((a&0xff4000)==0xa00000) { if(!(Pico.m.z80Run&1)) Pico.zram[a&0x1fff]=(u8)(d>>8); return; } // Z80 ram (MSB only) + + if ((a&0xffffe0)==0xa10000) { // I/O ports + a=(a>>1)&0xf; + // 6 button gamepad: if TH went from 0 to 1, gamepad changes state + if(PicoOpt&0x20) { + if(a==1) { + Pico.m.padDelay[0] = 0; + if(!(Pico.ioports[1]&0x40) && (d&0x40)) Pico.m.padTHPhase[0]++; + } + else if(a==2) { + Pico.m.padDelay[1] = 0; + if(!(Pico.ioports[2]&0x40) && (d&0x40)) Pico.m.padTHPhase[1]++; + } + } + Pico.ioports[a]=(u8)d; // IO ports can be used as RAM + return; + } + if (a==0xa11100) { OtherWrite8(a, d>>8, 16); return; } + if (a==0xa11200) { if(!(d&0x100)) z80_reset(); return; } + + OtherWrite8(a, d>>8, 16); + OtherWrite8(a+1,d&0xff, 16); +} + +// ----------------------------------------------------------------- +// Read Rom and read Ram + +#ifndef _ASM_MEMORY_C +u8 CPU_CALL PicoRead8(u32 a) +{ + u32 d=0; + + if ((a&0xe00000)==0xe00000) { d = *(u8 *)(Pico.ram+((a^1)&0xffff)); goto end; } // Ram + + a&=0xffffff; + +#if !(defined(EMU_C68K) && defined(EMU_M68K)) + // sram + if(a >= SRam.start && a <= SRam.end) { + unsigned int sreg = Pico.m.sram_reg; + if(!(sreg & 0x10) && (sreg & 1) && a > 0x200001) { // not yet detected SRAM + Pico.m.sram_reg|=0x10; // should be normal SRAM + } + if(sreg & 4) { // EEPROM read + d = SRAMReadEEPROM(); + goto end; + } else if(sreg & 1) { + d = *(u8 *)(SRam.data-SRam.start+a); + goto end; + } + } +#endif + + if (a>=8; + + end: + + //if ((a&0xe0ffff)==0xe0AE57+0x69c) + // dprintf("r8 : %06x, %02x @%06x", a&0xffffff, (u8)d, SekPc); + //if ((a&0xe0ffff)==0xe0a9ba+0x69c) + // dprintf("r8 : %06x, %02x @%06x", a&0xffffff, d, SekPc); + + //if(a==0x200001) dprintf("r8 : %02x @ %06x [%i]", d, SekPc, SekCyclesDoneT()); + //dprintf("r8 : %06x, %02x @%06x [%03i]", a&0xffffff, (u8)d, SekPc, Pico.m.scanline); +#ifdef __debug_io + dprintf("r8 : %06x, %02x @%06x", a&0xffffff, (u8)d, SekPc); +#endif +#if defined(EMU_C68K) && defined(EMU_M68K) + if(a>=Pico.romsize&&(ppop&0x3f)!=0x3a&&(ppop&0x3f)!=0x3b) { + lastread_a = a; + lastread_d[lrp_cyc++&15] = (u8)d; + } +#endif + return (u8)d; +} + +u16 CPU_CALL PicoRead16(u32 a) +{ + u16 d=0; + + if ((a&0xe00000)==0xe00000) { d=*(u16 *)(Pico.ram+(a&0xfffe)); goto end; } // Ram + + a&=0xfffffe; + +#if !(defined(EMU_C68K) && defined(EMU_M68K)) + // sram + if(a >= SRam.start && a <= SRam.end && (Pico.m.sram_reg & 1)) { + d = (u16) SRAMRead(a); + goto end; + } +#endif + + if (a=Pico.romsize&&(ppop&0x3f)!=0x3a&&(ppop&0x3f)!=0x3b) { + lastread_a = a; + lastread_d[lrp_cyc++&15] = d; + } +#endif + return d; +} + +u32 CPU_CALL PicoRead32(u32 a) +{ + u32 d=0; + + if ((a&0xe00000)==0xe00000) { u16 *pm=(u16 *)(Pico.ram+(a&0xfffe)); d = (pm[0]<<16)|pm[1]; goto end; } // Ram + + a&=0xfffffe; + + // sram + if(a >= SRam.start && a <= SRam.end && (Pico.m.sram_reg & 1)) { + d = (SRAMRead(a)<<16)|SRAMRead(a+2); + goto end; + } + + if (a=Pico.romsize&&(ppop&0x3f)!=0x3a&&(ppop&0x3f)!=0x3b) { + lastread_a = a; + lastread_d[lrp_cyc++&15] = d; + } +#endif + return d; +} +#endif + +// ----------------------------------------------------------------- +// Write Ram + +static void CPU_CALL PicoWrite8(u32 a,u8 d) +{ +#ifdef __debug_io + dprintf("w8 : %06x, %02x @%06x", a&0xffffff, d, SekPc); +#endif +#if defined(EMU_C68K) && defined(EMU_M68K) + lastwrite_cyc_d[lwp_cyc++&15] = d; +#endif + //if ((a&0xe0ffff)==0xe0a9ba+0x69c) + // dprintf("w8 : %06x, %02x @%06x", a&0xffffff, d, SekPc); + + + if ((a&0xe00000)==0xe00000) { u8 *pm=(u8 *)(Pico.ram+((a^1)&0xffff)); pm[0]=d; return; } // Ram + + a&=0xffffff; + OtherWrite8(a,d,8); +} + +static void CPU_CALL PicoWrite16(u32 a,u16 d) +{ +#ifdef __debug_io + dprintf("w16: %06x, %04x", a&0xffffff, d); +#endif +#if defined(EMU_C68K) && defined(EMU_M68K) + lastwrite_cyc_d[lwp_cyc++&15] = d; +#endif + //if ((a&0xe0ffff)==0xe0AF0E+0x69c||(a&0xe0ffff)==0xe0A9A8+0x69c||(a&0xe0ffff)==0xe0A9AA+0x69c||(a&0xe0ffff)==0xe0A9AC+0x69c) + // dprintf("w16: %06x, %04x @%06x", a&0xffffff, d, SekPc); + + if ((a&0xe00000)==0xe00000) { *(u16 *)(Pico.ram+(a&0xfffe))=d; return; } // Ram + + a&=0xfffffe; + OtherWrite16(a,d); +} + +static void CPU_CALL PicoWrite32(u32 a,u32 d) +{ +#ifdef __debug_io + dprintf("w32: %06x, %08x", a&0xffffff, d); +#endif +#if defined(EMU_C68K) && defined(EMU_M68K) + lastwrite_cyc_d[lwp_cyc++&15] = d; +#endif + + if ((a&0xe00000)==0xe00000) + { + // Ram: + u16 *pm=(u16 *)(Pico.ram+(a&0xfffe)); + pm[0]=(u16)(d>>16); pm[1]=(u16)d; + return; + } + + a&=0xfffffe; + OtherWrite16(a, (u16)(d>>16)); + OtherWrite16(a+2,(u16)d); +} + + +// ----------------------------------------------------------------- +int PicoMemInit() +{ +#ifdef EMU_C68K + // Setup memory callbacks: + PicoCpu.checkpc=PicoCheckPc; + PicoCpu.fetch8 =PicoCpu.read8 =PicoRead8; + PicoCpu.fetch16=PicoCpu.read16=PicoRead16; + PicoCpu.fetch32=PicoCpu.read32=PicoRead32; + PicoCpu.write8 =PicoWrite8; + PicoCpu.write16=PicoWrite16; + PicoCpu.write32=PicoWrite32; +#endif + return 0; +} + +#ifdef EMU_A68K +struct A68KInter +{ + u32 unknown; + u8 (__fastcall *Read8) (u32 a); + u16 (__fastcall *Read16)(u32 a); + u32 (__fastcall *Read32)(u32 a); + void (__fastcall *Write8) (u32 a,u8 d); + void (__fastcall *Write16) (u32 a,u16 d); + void (__fastcall *Write32) (u32 a,u32 d); + void (__fastcall *ChangePc)(u32 a); + u8 (__fastcall *PcRel8) (u32 a); + u16 (__fastcall *PcRel16)(u32 a); + u32 (__fastcall *PcRel32)(u32 a); + u16 (__fastcall *Dir16)(u32 a); + u32 (__fastcall *Dir32)(u32 a); +}; + +struct A68KInter a68k_memory_intf= +{ + 0, + PicoRead8, + PicoRead16, + PicoRead32, + PicoWrite8, + PicoWrite16, + PicoWrite32, + PicoCheckPc, + PicoRead8, + PicoRead16, + PicoRead32, + PicoRead16, // unused + PicoRead32, // unused +}; +#endif + +#ifdef EMU_M68K +unsigned int m68k_read_pcrelative_CD8 (unsigned int a); +unsigned int m68k_read_pcrelative_CD16(unsigned int a); +unsigned int m68k_read_pcrelative_CD32(unsigned int a); + +// these are allowed to access RAM +unsigned int m68k_read_pcrelative_8 (unsigned int a) { + a&=0xffffff; + if(PicoMCD&1) return m68k_read_pcrelative_CD8(a); + if(a>13)==2) // 0x4000-0x5fff (Charles MacDonald) + { + if(PicoOpt&1) ret = (u8) YM2612Read(); + goto end; + } + + if (a>=0x8000) + { + u32 addr68k; + addr68k=Pico.m.z80_bank68k<<15; + addr68k+=a&0x7fff; + + ret = (u8) PicoRead8(addr68k); + //dprintf("z80->68k w8 : %06x, %02x", addr68k, ret); + goto end; + } + + // should not be needed || dprintf("z80_read RAM"); + if (a<0x4000) { ret = (u8) Pico.zram[a&0x1fff]; goto end; } + +end: + return ret; +} + +unsigned short z80_read16(unsigned short a) +{ + //dprintf("z80_read16"); + + return (u16) ( (u16)z80_read(a) | ((u16)z80_read((u16)(a+1))<<8) ); +} + +void z80_write(unsigned char data, unsigned short a) +{ + //if (a<0x4000) + // dprintf("z80 w8 : %06x, %02x @%04x", a, data, mz80GetRegisterValue(NULL, 0)); + + if ((a>>13)==2) // 0x4000-0x5fff (Charles MacDonald) + { + if(PicoOpt&1) emustatus|=YM2612Write(a, data); + return; + } + + if ((a&0xfff9)==0x7f11) // 7f11 7f13 7f15 7f17 + { + if(PicoOpt&2) SN76496Write(data); + return; + } + + if ((a>>8)==0x60) + { + Pico.m.z80_bank68k>>=1; + Pico.m.z80_bank68k|=(data&1)<<8; + Pico.m.z80_bank68k&=0x1ff; // 9 bits and filled in the new top one + return; + } + + if (a>=0x8000) + { + u32 addr68k; + addr68k=Pico.m.z80_bank68k<<15; + addr68k+=a&0x7fff; + PicoWrite8(addr68k, data); + //dprintf("z80->68k w8 : %06x, %02x", addr68k, data); + return; + } + + // should not be needed, drZ80 knows how to access RAM itself || dprintf("z80_write RAM @ %08x", lr); + if (a<0x4000) { Pico.zram[a&0x1fff]=data; return; } +} + +void z80_write16(unsigned short data, unsigned short a) +{ + //dprintf("z80_write16"); + + z80_write((unsigned char) data,a); + z80_write((unsigned char)(data>>8),(u16)(a+1)); +} + diff --git a/Pico/Memory.s b/Pico/Memory.s new file mode 100644 index 00000000..51778c4a --- /dev/null +++ b/Pico/Memory.s @@ -0,0 +1,704 @@ +@ memory handlers with banking support for SSF II - The New Challengers +@ mostly based on Gens code + +@ (c) Copyright 2006, notaz +@ All Rights Reserved + + + +.text + +@ default jump tables + +m_read8_def_table: + .long m_read8_rom0 @ 0x000000 - 0x07FFFF + .long m_read8_rom1 @ 0x080000 - 0x0FFFFF + .long m_read8_rom2 @ 0x100000 - 0x17FFFF + .long m_read8_rom3 @ 0x180000 - 0x1FFFFF + .long m_read8_rom4 @ 0x200000 - 0x27FFFF + .long m_read8_rom5 @ 0x280000 - 0x2FFFFF + .long m_read8_rom6 @ 0x300000 - 0x37FFFF + .long m_read8_rom7 @ 0x380000 - 0x3FFFFF + .long m_read8_rom8 @ 0x400000 - 0x47FFFF + .long m_read8_rom9 @ 0x480000 - 0x4FFFFF + .long m_read8_romA @ 0x500000 - 0x57FFFF + .long m_read8_romB @ 0x580000 - 0x5FFFFF + .long m_read8_romC @ 0x600000 - 0x67FFFF + .long m_read8_romD @ 0x680000 - 0x6FFFFF + .long m_read8_romE @ 0x700000 - 0x77FFFF + .long m_read8_romF @ 0x780000 - 0x7FFFFF + .long m_read_null @ 0x800000 - 0x87FFFF + .long m_read_null @ 0x880000 - 0x8FFFFF + .long m_read_null @ 0x900000 - 0x97FFFF + .long m_read_null @ 0x980000 - 0x9FFFFF + .long m_read8_misc @ 0xA00000 - 0xA7FFFF + .long m_read_null @ 0xA80000 - 0xAFFFFF + .long m_read_null @ 0xB00000 - 0xB7FFFF + .long m_read_null @ 0xB80000 - 0xBFFFFF + .long m_read8_vdp @ 0xC00000 - 0xC7FFFF + .long m_read8_vdp @ 0xC80000 - 0xCFFFFF + .long m_read_null @ 0xD00000 - 0xD7FFFF + .long m_read_null @ 0xD80000 - 0xDFFFFF + .long m_read8_ram @ 0xE00000 - 0xE7FFFF + .long m_read8_ram @ 0xE80000 - 0xEFFFFF + .long m_read8_ram @ 0xF00000 - 0xF7FFFF + .long m_read8_ram @ 0xF80000 - 0xFFFFFF + +m_read16_def_table: + .long m_read16_rom0 @ 0x000000 - 0x07FFFF + .long m_read16_rom1 @ 0x080000 - 0x0FFFFF + .long m_read16_rom2 @ 0x100000 - 0x17FFFF + .long m_read16_rom3 @ 0x180000 - 0x1FFFFF + .long m_read16_rom4 @ 0x200000 - 0x27FFFF + .long m_read16_rom5 @ 0x280000 - 0x2FFFFF + .long m_read16_rom6 @ 0x300000 - 0x37FFFF + .long m_read16_rom7 @ 0x380000 - 0x3FFFFF + .long m_read16_rom8 @ 0x400000 - 0x47FFFF + .long m_read16_rom9 @ 0x480000 - 0x4FFFFF + .long m_read16_romA @ 0x500000 - 0x57FFFF + .long m_read16_romB @ 0x580000 - 0x5FFFFF + .long m_read16_romC @ 0x600000 - 0x67FFFF + .long m_read16_romD @ 0x680000 - 0x6FFFFF + .long m_read16_romE @ 0x700000 - 0x77FFFF + .long m_read16_romF @ 0x780000 - 0x7FFFFF + .long m_read_null @ 0x800000 - 0x87FFFF + .long m_read_null @ 0x880000 - 0x8FFFFF + .long m_read_null @ 0x900000 - 0x97FFFF + .long m_read_null @ 0x980000 - 0x9FFFFF + .long m_read16_misc @ 0xA00000 - 0xA7FFFF + .long m_read_null @ 0xA80000 - 0xAFFFFF + .long m_read_null @ 0xB00000 - 0xB7FFFF + .long m_read_null @ 0xB80000 - 0xBFFFFF + .long m_read16_vdp @ 0xC00000 - 0xC7FFFF + .long m_read_null @ 0xC80000 - 0xCFFFFF + .long m_read_null @ 0xD00000 - 0xD7FFFF + .long m_read_null @ 0xD80000 - 0xDFFFFF + .long m_read16_ram @ 0xE00000 - 0xE7FFFF + .long m_read16_ram @ 0xE80000 - 0xEFFFFF + .long m_read16_ram @ 0xF00000 - 0xF7FFFF + .long m_read16_ram @ 0xF80000 - 0xFFFFFF + +m_read32_def_table: + .long m_read32_rom0 @ 0x000000 - 0x07FFFF + .long m_read32_rom1 @ 0x080000 - 0x0FFFFF + .long m_read32_rom2 @ 0x100000 - 0x17FFFF + .long m_read32_rom3 @ 0x180000 - 0x1FFFFF + .long m_read32_rom4 @ 0x200000 - 0x27FFFF + .long m_read32_rom5 @ 0x280000 - 0x2FFFFF + .long m_read32_rom6 @ 0x300000 - 0x37FFFF + .long m_read32_rom7 @ 0x380000 - 0x3FFFFF + .long m_read32_rom8 @ 0x400000 - 0x47FFFF + .long m_read32_rom9 @ 0x480000 - 0x4FFFFF + .long m_read32_romA @ 0x500000 - 0x57FFFF + .long m_read32_romB @ 0x580000 - 0x5FFFFF + .long m_read32_romC @ 0x600000 - 0x67FFFF + .long m_read32_romD @ 0x680000 - 0x6FFFFF + .long m_read32_romE @ 0x700000 - 0x77FFFF + .long m_read32_romF @ 0x780000 - 0x7FFFFF + .long m_read_null @ 0x800000 - 0x87FFFF + .long m_read_null @ 0x880000 - 0x8FFFFF + .long m_read_null @ 0x900000 - 0x97FFFF + .long m_read_null @ 0x980000 - 0x9FFFFF + .long m_read32_misc @ 0xA00000 - 0xA7FFFF + .long m_read_null @ 0xA80000 - 0xAFFFFF + .long m_read_null @ 0xB00000 - 0xB7FFFF + .long m_read_null @ 0xB80000 - 0xBFFFFF + .long m_read32_vdp @ 0xC00000 - 0xC7FFFF + .long m_read_null @ 0xC80000 - 0xCFFFFF + .long m_read_null @ 0xD00000 - 0xD7FFFF + .long m_read_null @ 0xD80000 - 0xDFFFFF + .long m_read32_ram @ 0xE00000 - 0xE7FFFF + .long m_read32_ram @ 0xE80000 - 0xEFFFFF + .long m_read32_ram @ 0xF00000 - 0xF7FFFF + .long m_read32_ram @ 0xF80000 - 0xFFFFFF + + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +.bss +@.section .bss, "brw" +@.data + +@ used tables +m_read8_table: + .skip 32*4 + +m_read16_table: + .skip 32*4 + +m_read32_table: + .skip 32*4 + + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +.text + +.global PicoMemReset +.global PicoRead8 +.global PicoRead16 +.global PicoRead32 +.global PicoWriteRomHW_SSF2 + + +PicoMemReset: + ldr r12,=(Pico+0x22204) + ldr r12,[r12] @ romsize + add r12,r12,#0x80000 + sub r12,r12,#1 + mov r12,r12,lsr #19 + + ldr r0, =m_read8_table + ldr r1, =m_read8_def_table + mov r2, #32 +1: + ldr r3, [r1], #4 + str r3, [r0], #4 + subs r2, r2, #1 + bne 1b + + ldr r0, =m_read16_table + ldr r1, =m_read16_def_table + mov r2, #32 +1: + subs r2, r2, #1 + ldr r3, [r1], #4 + str r3, [r0], #4 + bne 1b + + ldr r0, =m_read32_table + ldr r1, =m_read32_def_table + mov r2, #32 +1: + subs r2, r2, #1 + ldr r3, [r1], #4 + str r3, [r0], #4 + bne 1b + + @ update memhandlers according to ROM size + ldr r1, =m_read8_above_rom + ldr r0, =m_read8_table + mov r2, #16 +1: + sub r2, r2, #1 + cmp r2, r12 + blt 2f + cmp r2, #4 + beq 1b @ do not touch the SRAM area + str r1, [r0, r2, lsl #2] + b 1b +2: + ldr r1, =m_read16_above_rom + ldr r0, =m_read16_table + mov r2, #16 +1: + sub r2, r2, #1 + cmp r2, r12 + blt 2f + cmp r2, #4 + beq 1b + str r1, [r0, r2, lsl #2] + b 1b +2: + ldr r1, =m_read32_above_rom + ldr r0, =m_read32_table + mov r2, #16 +1: + sub r2, r2, #1 + cmp r2, r12 + blt 2f + cmp r2, #4 + beq 1b + str r1, [r0, r2, lsl #2] + b 1b +2: + bx lr + +.pool + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +PicoRead8: @ u32 a + ldr r2, =m_read8_table + bic r0, r0, #0xff000000 + and r1, r0, #0x00f80000 + ldr pc, [r2, r1, lsr #17] + +PicoRead16: @ u32 a + ldr r2, =m_read16_table + bic r0, r0, #0xff000000 + and r1, r0, #0x00f80000 + ldr pc, [r2, r1, lsr #17] + +PicoRead32: @ u32 a + ldr r2, =m_read32_table + bic r0, r0, #0xff000000 + and r1, r0, #0x00f80000 + ldr pc, [r2, r1, lsr #17] + +.pool + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +m_read_null: + mov r0, #0 + bx lr + + +.macro m_read8_rom sect + ldr r1, =(Pico+0x22200) + bic r0, r0, #0xf80000 + ldr r1, [r1] +.if \sect + orr r0, r0, #0x080000*\sect +.endif + eor r0, r0, #1 + ldrb r0, [r1, r0] + bx lr +.endm + + +m_read8_rom0: @ 0x000000 - 0x07ffff + m_read8_rom 0 + +m_read8_rom1: @ 0x080000 - 0x0fffff + m_read8_rom 1 + +m_read8_rom2: @ 0x100000 - 0x17ffff + m_read8_rom 2 + +m_read8_rom3: @ 0x180000 - 0x1fffff + m_read8_rom 3 + +m_read8_rom4: @ 0x200000 - 0x27ffff, SRAM area + ldr r2, =(SRam) + ldr r3, =(Pico+0x22200) + ldr r1, [r2, #8] @ SRam.end + bic r0, r0, #0xf80000 + orr r0, r0, #0x200000 + cmp r0, r1 + bgt m_read8_nosram + ldr r1, [r2, #4] @ SRam.start (1ci) + cmp r0, r1 + blt m_read8_nosram + ldrb r1, [r3, #0x11] @ Pico.m.sram_reg (1ci) + sub r12,r0, #0x200000 + tst r1, #0x10 + bne m_read8_detected + cmp r12,#1 + ble m_read8_detected + tst r1, #1 + orrne r1, r1, #0x10 + strneb r1, [r3, #0x11] +m_read8_detected: + tst r1, #4 @ EEPROM read? + ldrne r0, =SRAMReadEEPROM @ (1ci if ne) + bxne r0 +m_read8_noteeprom: + tst r1, #1 + beq m_read8_nosram + ldr r3, [r2] @ SRam.data + ldr r2, [r2, #4] @ SRam.start (1ci) + sub r3, r3, r2 + ldrb r0, [r3, r0] + bx lr +m_read8_nosram: + ldr r1, [r3, #4] @ 1ci + cmp r0, r1 + movgt r0, #0 + bxgt lr @ bad location + ldr r1, [r3] + eor r0, r0, #1 + ldrb r0, [r1, r0] + bx lr + +m_read8_rom5: @ 0x280000 - 0x2fffff + m_read8_rom 5 + +m_read8_rom6: @ 0x300000 - 0x37ffff + m_read8_rom 6 + +m_read8_rom7: @ 0x380000 - 0x3fffff + m_read8_rom 7 + +m_read8_rom8: @ 0x400000 - 0x47ffff + m_read8_rom 8 + +m_read8_rom9: @ 0x480000 - 0x4fffff + m_read8_rom 9 + +@ is any ROM using that much? +m_read8_romA: @ 0x500000 - 0x57ffff + m_read8_rom 0xA + +m_read8_romB: @ 0x580000 - 0x5fffff + m_read8_rom 0xB + +m_read8_romC: @ 0x600000 - 0x67ffff + m_read8_rom 0xC + +m_read8_romD: @ 0x680000 - 0x6fffff + m_read8_rom 0xD + +m_read8_romE: @ 0x700000 - 0x77ffff + m_read8_rom 0xE + +m_read8_romF: @ 0x780000 - 0x7fffff + m_read8_rom 0xF + +m_read8_misc: + bic r2, r0, #0x00ff + bic r2, r2, #0xbf00 + cmp r2, #0xa00000 @ Z80 RAM? + ldreq r2, =z80Read8 + bxeq r2 + stmfd sp!,{r0,lr} + bic r0, r0, #1 + mov r1, #8 + bl OtherRead16 + ldmfd sp!,{r1,lr} + tst r1, #1 + moveq r0, r0, lsr #8 + bx lr + +m_read8_vdp: + tst r0, #0x70000 + tsteq r0, #0x000e0 + bxne lr @ invalid read + stmfd sp!,{r0,lr} + bic r0, r0, #1 + bl PicoVideoRead + ldmfd sp!,{r1,lr} + tst r1, #1 + moveq r0, r0, lsr #8 + bx lr + +m_read8_ram: + ldr r1, =Pico + bic r0, r0, #0xff0000 + eor r0, r0, #1 + ldrb r0, [r1, r0] + bx lr + +m_read8_above_rom: + stmfd sp!,{r0,lr} + bic r0, r0, #1 + mov r1, #8 + bl UnusualRead16 + ldmfd sp!,{r1,lr} + tst r1, #1 + moveq r0, r0, lsr #8 + bx lr + +.pool + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +.macro m_read16_rom sect + ldr r1, =(Pico+0x22200) + bic r0, r0, #0xf80000 + ldr r1, [r1] + bic r0, r0, #1 +.if \sect + orr r0, r0, #0x080000*\sect +.endif + ldrh r0, [r1, r0] + bx lr +.endm + + +m_read16_rom0: @ 0x000000 - 0x07ffff + m_read16_rom 0 + +m_read16_rom1: @ 0x080000 - 0x0fffff + m_read16_rom 1 + +m_read16_rom2: @ 0x100000 - 0x17ffff + m_read16_rom 2 + +m_read16_rom3: @ 0x180000 - 0x1fffff + m_read16_rom 3 + +m_read16_rom4: @ 0x200000 - 0x27ffff, SRAM area (NBA Live 95) + ldr r2, =(SRam) + ldr r3, =(Pico+0x22200) + ldr r1, [r2, #8] @ SRam.end + bic r0, r0, #0xf80000 + bic r0, r0, #1 + orr r0, r0, #0x200000 + cmp r0, r1 + bgt m_read16_nosram + ldrb r1, [r3, #0x11] @ Pico.m.sram_reg (2ci) + tst r1, #1 + beq m_read16_nosram + ldr r1, [r2, #4] @ SRam.start (1ci) + cmp r0, r1 + blt m_read16_nosram + ldr r2, [r2] @ SRam.data (1ci) + sub r2, r2, r1 + ldrh r0, [r2, r0] @ 2ci + and r1, r0, #0xff + mov r0, r0, lsr #8 + orr r0, r0, r1, lsl #8 + bx lr +m_read16_nosram: + ldr r1, [r3, #4] @ 1ci + cmp r0, r1 + movgt r0, #0 + bxgt lr @ bad location + ldr r1, [r3] @ 1ci + ldrh r0, [r1, r0] + bx lr + +m_read16_rom5: @ 0x280000 - 0x2fffff + m_read16_rom 5 + +m_read16_rom6: @ 0x300000 - 0x37ffff + m_read16_rom 6 + +m_read16_rom7: @ 0x380000 - 0x3fffff + m_read16_rom 7 + +m_read16_rom8: @ 0x400000 - 0x47ffff + m_read16_rom 8 + +m_read16_rom9: @ 0x480000 - 0x4fffff + m_read16_rom 9 + +@ is any ROM using that much? +m_read16_romA: @ 0x500000 - 0x57ffff + m_read16_rom 0xA + +m_read16_romB: @ 0x580000 - 0x5fffff + m_read16_rom 0xB + +m_read16_romC: @ 0x600000 - 0x67ffff + m_read16_rom 0xC + +m_read16_romD: @ 0x680000 - 0x6fffff + m_read16_rom 0xD + +m_read16_romE: @ 0x700000 - 0x77ffff + m_read16_rom 0xE + +m_read16_romF: @ 0x780000 - 0x7fffff + m_read16_rom 0xF + +m_read16_misc: + mov r1, #16 + ldr r2, =OtherRead16 + bic r0, r0, #1 + bx r2 + +m_read16_vdp: + tst r0, #0x70000 + tsteq r0, #0x000e0 + bxne lr @ invalid read + ldr r1, =PicoVideoRead + bic r0, r0, #1 + bx r1 + +m_read16_ram: + ldr r1, =Pico + bic r0, r0, #0xff0000 + bic r0, r0, #1 + ldrh r0, [r1, r0] + bx lr + +m_read16_above_rom: + mov r1, #16 + ldr r2, =UnusualRead16 + bic r0, r0, #1 + bx r2 + +.pool + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +.macro m_read32_rom sect + ldr r1, =(Pico+0x22200) + bic r0, r0, #0xf80000 + ldr r1, [r1] + bic r0, r0, #1 +.if \sect + orr r0, r0, #0x080000*\sect +.endif + ldrh r0, [r1, r0]! + ldrh r1, [r1, #2] @ 1ci + orr r0, r1, r0, lsl #16 + bx lr +.endm + + +m_read32_rom0: @ 0x000000 - 0x07ffff + m_read32_rom 0 + +m_read32_rom1: @ 0x080000 - 0x0fffff + m_read32_rom 1 + +m_read32_rom2: @ 0x100000 - 0x17ffff + m_read32_rom 2 + +m_read32_rom3: @ 0x180000 - 0x1fffff + m_read32_rom 3 + +m_read32_rom4: @ 0x200000 - 0x27ffff, SRAM area (does any game do long reads?) + ldr r2, =(SRam) + ldr r3, =(Pico+0x22200) + ldr r1, [r2, #8] @ SRam.end + bic r0, r0, #0xf80000 + bic r0, r0, #1 + orr r0, r0, #0x200000 + cmp r0, r1 + bgt m_read32_nosram + ldrb r1, [r3, #0x11] @ Pico.m.sram_reg (2ci) + tst r1, #1 + beq m_read32_nosram + ldr r1, [r2, #4] @ SRam.start (1ci) + cmp r0, r1 + blt m_read32_nosram + ldr r2, [r2] @ SRam.data (1ci) + sub r2, r2, r1 + ldrh r0, [r2, r0]! @ (1ci) + ldrh r1, [r2, #2] + orr r0, r0, r0, lsl #16 + mov r0, r0, ror #8 + mov r0, r0, lsl #16 + orr r0, r0, r1, lsr #8 + and r1, r1, #0xff + orr r0, r0, r1, lsl #8 + bx lr +m_read32_nosram: + ldr r1, [r3, #4] @ (1ci) + cmp r0, r1 + movgt r0, #0 + bxgt lr @ bad location + ldr r1, [r3] @ (1ci) + ldrh r0, [r1, r0]! + ldrh r1, [r1, #2] @ (2ci) + orr r0, r1, r0, lsl #16 + bx lr + +m_read32_rom5: @ 0x280000 - 0x2fffff + m_read32_rom 5 + +m_read32_rom6: @ 0x300000 - 0x37ffff + m_read32_rom 6 + +m_read32_rom7: @ 0x380000 - 0x3fffff + m_read32_rom 7 + +m_read32_rom8: @ 0x400000 - 0x47ffff + m_read32_rom 8 + +m_read32_rom9: @ 0x480000 - 0x4fffff + m_read32_rom 9 + +@ is any ROM using that much? +m_read32_romA: @ 0x500000 - 0x57ffff + m_read32_rom 0xA + +m_read32_romB: @ 0x580000 - 0x5fffff + m_read32_rom 0xB + +m_read32_romC: @ 0x600000 - 0x67ffff + m_read32_rom 0xC + +m_read32_romD: @ 0x680000 - 0x6fffff + m_read32_rom 0xD + +m_read32_romE: @ 0x700000 - 0x77ffff + m_read32_rom 0xE + +m_read32_romF: @ 0x780000 - 0x7fffff + m_read32_rom 0xF + +m_read32_misc: + bic r0, r0, #1 + stmfd sp!,{r0,lr} + mov r1, #32 + bl OtherRead16 + mov r1, r0 + ldmfd sp!,{r0} + stmfd sp!,{r1} + add r0, r0, #2 + mov r1, #32 + bl OtherRead16 + ldmfd sp!,{r1,lr} + orr r0, r0, r1, lsl #16 + bx lr + +m_read32_vdp: + tst r0, #0x70000 + tsteq r0, #0x000e0 + bxne lr @ invalid read + bic r0, r0, #1 + stmfd sp!,{r0,lr} + bl PicoVideoRead + mov r1, r0 + ldmfd sp!,{r0} + stmfd sp!,{r1} + add r0, r0, #2 + bl PicoVideoRead + ldmfd sp!,{r1,lr} + orr r0, r0, r1, lsl #16 + bx lr + +m_read32_ram: + ldr r1, =Pico + bic r0, r0, #0xff0000 + bic r0, r0, #1 + ldrh r0, [r1, r0]! + ldrh r1, [r1, #2] @ 2ci + orr r0, r1, r0, lsl #16 + bx lr + +m_read32_above_rom: + bic r0, r0, #1 + stmfd sp!,{r0,lr} + mov r1, #32 + bl UnusualRead16 + mov r1, r0 + ldmfd sp!,{r0} + stmfd sp!,{r1} + add r0, r0, #2 + mov r1, #32 + bl UnusualRead16 + ldmfd sp!,{r1,lr} + orr r0, r0, r1, lsl #16 + bx lr + +.pool + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +PicoWriteRomHW_SSF2: @ u32 a, u32 d + and r0, r0, #0xe + movs r0, r0, lsr #1 + bne pwr_banking + + @ sram register + ldr r2, =(Pico+0x22211) @ Pico.m.sram_reg + and r1, r1, #3 + strb r1, [r2] + bx lr + +pwr_banking: + and r1, r1, #0x1f + + ldr r3, =m_read8_def_table + ldr r2, =m_read8_table + ldr r12, [r3, r1, lsl #2] + str r12, [r2, r0, lsl #2] + + ldr r3, =m_read16_def_table + ldr r2, =m_read16_table + ldr r12, [r3, r1, lsl #2] + str r12, [r2, r0, lsl #2] + + ldr r3, =m_read32_def_table + ldr r2, =m_read32_table + ldr r12, [r3, r1, lsl #2] + str r12, [r2, r0, lsl #2] + + bx lr diff --git a/Pico/Misc.c b/Pico/Misc.c new file mode 100644 index 00000000..887e90cc --- /dev/null +++ b/Pico/Misc.c @@ -0,0 +1,305 @@ +// This is part of Pico Library + +// (c) Copyright 2006 notaz, All rights reserved. +// Free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + + +#include "PicoInt.h" + +// H-counter table for hvcounter reads in 40col mode +// based on Gens code +const unsigned char hcounts_40[] = { +0x07,0x07,0x08,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d, +0x0e,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x10,0x11,0x11,0x12,0x12,0x13,0x13,0x13,0x14, +0x14,0x15,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x18,0x19,0x19,0x1a,0x1a,0x1b, +0x1b,0x1b,0x1c,0x1c,0x1d,0x1d,0x1d,0x1e,0x1e,0x1f,0x1f,0x20,0x20,0x20,0x21,0x21, +0x22,0x22,0x23,0x23,0x23,0x24,0x24,0x25,0x25,0x25,0x26,0x26,0x27,0x27,0x28,0x28, +0x28,0x29,0x29,0x2a,0x2a,0x2a,0x2b,0x2b,0x2c,0x2c,0x2d,0x2d,0x2d,0x2e,0x2e,0x2f, +0x2f,0x30,0x30,0x30,0x31,0x31,0x32,0x32,0x32,0x33,0x33,0x34,0x34,0x35,0x35,0x35, +0x36,0x36,0x37,0x37,0x38,0x38,0x38,0x39,0x39,0x3a,0x3a,0x3a,0x3b,0x3b,0x3c,0x3c, +0x3d,0x3d,0x3d,0x3e,0x3e,0x3f,0x3f,0x3f,0x40,0x40,0x41,0x41,0x42,0x42,0x42,0x43, +0x43,0x44,0x44,0x45,0x45,0x45,0x46,0x46,0x47,0x47,0x47,0x48,0x48,0x49,0x49,0x4a, +0x4a,0x4a,0x4b,0x4b,0x4c,0x4c,0x4d,0x4d,0x4d,0x4e,0x4e,0x4f,0x4f,0x4f,0x50,0x50, +0x51,0x51,0x52,0x52,0x52,0x53,0x53,0x54,0x54,0x55,0x55,0x55,0x56,0x56,0x57,0x57, +0x57,0x58,0x58,0x59,0x59,0x5a,0x5a,0x5a,0x5b,0x5b,0x5c,0x5c,0x5c,0x5d,0x5d,0x5e, +0x5e,0x5f,0x5f,0x5f,0x60,0x60,0x61,0x61,0x62,0x62,0x62,0x63,0x63,0x64,0x64,0x64, +0x65,0x65,0x66,0x66,0x67,0x67,0x67,0x68,0x68,0x69,0x69,0x6a,0x6a,0x6a,0x6b,0x6b, +0x6c,0x6c,0x6c,0x6d,0x6d,0x6e,0x6e,0x6f,0x6f,0x6f,0x70,0x70,0x71,0x71,0x71,0x72, +0x72,0x73,0x73,0x74,0x74,0x74,0x75,0x75,0x76,0x76,0x77,0x77,0x77,0x78,0x78,0x79, +0x79,0x79,0x7a,0x7a,0x7b,0x7b,0x7c,0x7c,0x7c,0x7d,0x7d,0x7e,0x7e,0x7f,0x7f,0x7f, +0x80,0x80,0x81,0x81,0x81,0x82,0x82,0x83,0x83,0x84,0x84,0x84,0x85,0x85,0x86,0x86, +0x86,0x87,0x87,0x88,0x88,0x89,0x89,0x89,0x8a,0x8a,0x8b,0x8b,0x8c,0x8c,0x8c,0x8d, +0x8d,0x8e,0x8e,0x8e,0x8f,0x8f,0x90,0x90,0x91,0x91,0x91,0x92,0x92,0x93,0x93,0x94, +0x94,0x94,0x95,0x95,0x96,0x96,0x96,0x97,0x97,0x98,0x98,0x99,0x99,0x99,0x9a,0x9a, +0x9b,0x9b,0x9b,0x9c,0x9c,0x9d,0x9d,0x9e,0x9e,0x9e,0x9f,0x9f,0xa0,0xa0,0xa1,0xa1, +0xa1,0xa2,0xa2,0xa3,0xa3,0xa3,0xa4,0xa4,0xa5,0xa5,0xa6,0xa6,0xa6,0xa7,0xa7,0xa8, +0xa8,0xa9,0xa9,0xa9,0xaa,0xaa,0xab,0xab,0xab,0xac,0xac,0xad,0xad,0xae,0xae,0xae, +0xaf,0xaf,0xb0,0xb0, +0xe4,0xe4,0xe4,0xe5,0xe5,0xe6,0xe6,0xe6,0xe7,0xe7,0xe8,0xe8,0xe9,0xe9,0xe9,0xea, +0xea,0xeb,0xeb,0xeb,0xec,0xec,0xed,0xed,0xee,0xee,0xee,0xef,0xef,0xf0,0xf0,0xf1, +0xf1,0xf1,0xf2,0xf2,0xf3,0xf3,0xf3,0xf4,0xf4,0xf5,0xf5,0xf6,0xf6,0xf6,0xf7,0xf7, +0xf8,0xf8,0xf9,0xf9,0xf9,0xfa,0xfa,0xfb,0xfb,0xfb,0xfc,0xfc,0xfd,0xfd,0xfe,0xfe, +0xfe,0xff,0xff,0x00,0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x03,0x04,0x04,0x05, +0x05,0x06,0x06,0x06, +0x07,0x07,0x08,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d, +0x0e,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x10, +}; + +// H-counter table for hvcounter reads in 32col mode +const unsigned char hcounts_32[] = { +0x05,0x05,0x05,0x06,0x06,0x07,0x07,0x07,0x08,0x08,0x08,0x09,0x09,0x09,0x0a,0x0a, +0x0a,0x0b,0x0b,0x0b,0x0c,0x0c,0x0c,0x0d,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f,0x0f,0x10, +0x10,0x10,0x11,0x11,0x11,0x12,0x12,0x12,0x13,0x13,0x13,0x14,0x14,0x14,0x15,0x15, +0x15,0x16,0x16,0x17,0x17,0x17,0x18,0x18,0x18,0x19,0x19,0x19,0x1a,0x1a,0x1a,0x1b, +0x1b,0x1b,0x1c,0x1c,0x1c,0x1d,0x1d,0x1d,0x1e,0x1e,0x1f,0x1f,0x1f,0x20,0x20,0x20, +0x21,0x21,0x21,0x22,0x22,0x22,0x23,0x23,0x23,0x24,0x24,0x24,0x25,0x25,0x26,0x26, +0x26,0x27,0x27,0x27,0x28,0x28,0x28,0x29,0x29,0x29,0x2a,0x2a,0x2a,0x2b,0x2b,0x2b, +0x2c,0x2c,0x2c,0x2d,0x2d,0x2e,0x2e,0x2e,0x2f,0x2f,0x2f,0x30,0x30,0x30,0x31,0x31, +0x31,0x32,0x32,0x32,0x33,0x33,0x33,0x34,0x34,0x34,0x35,0x35,0x36,0x36,0x36,0x37, +0x37,0x37,0x38,0x38,0x38,0x39,0x39,0x39,0x3a,0x3a,0x3a,0x3b,0x3b,0x3b,0x3c,0x3c, +0x3d,0x3d,0x3d,0x3e,0x3e,0x3e,0x3f,0x3f,0x3f,0x40,0x40,0x40,0x41,0x41,0x41,0x42, +0x42,0x42,0x43,0x43,0x43,0x44,0x44,0x45,0x45,0x45,0x46,0x46,0x46,0x47,0x47,0x47, +0x48,0x48,0x48,0x49,0x49,0x49,0x4a,0x4a,0x4a,0x4b,0x4b,0x4b,0x4c,0x4c,0x4d,0x4d, +0x4d,0x4e,0x4e,0x4e,0x4f,0x4f,0x4f,0x50,0x50,0x50,0x51,0x51,0x51,0x52,0x52,0x52, +0x53,0x53,0x53,0x54,0x54,0x55,0x55,0x55,0x56,0x56,0x56,0x57,0x57,0x57,0x58,0x58, +0x58,0x59,0x59,0x59,0x5a,0x5a,0x5a,0x5b,0x5b,0x5c,0x5c,0x5c,0x5d,0x5d,0x5d,0x5e, +0x5e,0x5e,0x5f,0x5f,0x5f,0x60,0x60,0x60,0x61,0x61,0x61,0x62,0x62,0x62,0x63,0x63, +0x64,0x64,0x64,0x65,0x65,0x65,0x66,0x66,0x66,0x67,0x67,0x67,0x68,0x68,0x68,0x69, +0x69,0x69,0x6a,0x6a,0x6a,0x6b,0x6b,0x6c,0x6c,0x6c,0x6d,0x6d,0x6d,0x6e,0x6e,0x6e, +0x6f,0x6f,0x6f,0x70,0x70,0x70,0x71,0x71,0x71,0x72,0x72,0x72,0x73,0x73,0x74,0x74, +0x74,0x75,0x75,0x75,0x76,0x76,0x76,0x77,0x77,0x77,0x78,0x78,0x78,0x79,0x79,0x79, +0x7a,0x7a,0x7b,0x7b,0x7b,0x7c,0x7c,0x7c,0x7d,0x7d,0x7d,0x7e,0x7e,0x7e,0x7f,0x7f, +0x7f,0x80,0x80,0x80,0x81,0x81,0x81,0x82,0x82,0x83,0x83,0x83,0x84,0x84,0x84,0x85, +0x85,0x85,0x86,0x86,0x86,0x87,0x87,0x87,0x88,0x88,0x88,0x89,0x89,0x89,0x8a,0x8a, +0x8b,0x8b,0x8b,0x8c,0x8c,0x8c,0x8d,0x8d,0x8d,0x8e,0x8e,0x8e,0x8f,0x8f,0x8f,0x90, +0x90,0x90,0x91,0x91, +0xe8,0xe8,0xe8,0xe9,0xe9,0xe9,0xea,0xea,0xea,0xeb,0xeb,0xeb,0xec,0xec,0xec,0xed, +0xed,0xed,0xee,0xee,0xee,0xef,0xef,0xf0,0xf0,0xf0,0xf1,0xf1,0xf1,0xf2,0xf2,0xf2, +0xf3,0xf3,0xf3,0xf4,0xf4,0xf4,0xf5,0xf5,0xf5,0xf6,0xf6,0xf6,0xf7,0xf7,0xf8,0xf8, +0xf8,0xf9,0xf9,0xf9,0xfa,0xfa,0xfa,0xfb,0xfb,0xfb,0xfc,0xfc,0xfc,0xfd,0xfd,0xfd, +0xfe,0xfe,0xfe,0xff,0xff,0x00,0x00,0x00,0x01,0x01,0x01,0x02,0x02,0x02,0x03,0x03, +0x03,0x04,0x04,0x04, +0x05,0x05,0x05,0x06,0x06,0x07,0x07,0x07,0x08,0x08,0x08,0x09,0x09,0x09,0x0a,0x0a, +0x0a,0x0b,0x0b,0x0b,0x0c,0x0c,0x0c,0x0d, +}; + +// vcounter values for PicoFrameSimple +const unsigned short vcounts[] = { + 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, + 16, 17, 17, 18, 18, 19, 19, 20, 21, 21, 22, 22, 23, 23, 24, 24, + 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 31, 31, 32, 32, 33, + 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, 39, 39, 40, 40, 41, + 42, 42, 43, 43, 44, 44, 45, 45, 46, 46, 47, 47, 48, 48, 49, 49, + 50, 50, 51, 52, 52, 53, 53, 54, 54, 55, 55, 56, 56, 57, 57, 58, + 58, 59, 59, 60, 60, 61, 62, 62, 63, 63, 64, 64, 65, 65, 66, 66, + 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 73, 73, 74, 74, 75, + 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, 82, 83, 83, + 84, 84, 85, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90, 90, 91, 91, + 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 97, 98, 98, 99, 99,100, +100,101,101,102,102,103,104,104,105,105,106,106,107,107,108,108, +109,109,110,110,111,111,112,112,113,114,114,115,115,116,116,117, +117,118,118,119,119,120,120,121,121,122,122,123,124,124,125,125, +126,126,127,127,128,128,129,129,130,130,131,131,132,132,133,133, +134,135,135,136,136,137,137,138,138,139,139,140,140,141,141,142, +142,143,143,144,145,145,146,146,147,147,148,148,149,149,150,150, +151,151,152,152,153,153,154,155,155,156,156,157,157,158,158,159, +159,160,160,161,161,162,162,163,163,164,164,165,166,166,167,167, +168,168,169,169,170,170,171,171,172,172,173,173,174,174,175,176, +176,177,177,178,178,179,179,180,180,181,181,182,182,183,183,184, +184,185,186,186,187,187,188,188,189,189,190,190,191,191,192,192, +193,193,194,194,195,195,196,197,197,198,198,199,199,200,200,201, +201,202,202,203,203,204,204,205,205,206,207,207,208,208,209,209, +210,210,211,211,212,212,213,213,214,214,215,215,216,217,217,218, +218,219,219,220,220,221,221,222,222,223,223,224,224,225,225,226, +226,227,228,228,229,229,230,230,231,231,232,232,233,233,234,234, +235,235,236,236,237,238,238,239,239,240,240,241,241,242,242,243, +243,244,244,245,245,246,246,247,248,248,249,249,250,250,251,251, +252,252,253,253,254,254,255,255,256,256,257,257,258,259,259,260, +260,261,261,262,262,263,263,264,264,265,265,266,266,267,267,268, +269,269,270,270,271,271,272,272,273,273,274,274,275,275,276,276, +277,277,278,279,279,280,280,281,281,282,282,283,283,284,284,285, +285,286,286,287,287,288,288,289,290,290,291,291,292,292,293,293, +294,294,295,295,296,296,297,297,298,298,299,300,300,301,301,302, +302,303,303,304,304,305,305,306,306,307,307,308,308,309,310,310, +311,311,311,311, +}; + + +// rarely used EEPROM SRAM code +// known games which use this: +// Wonder Boy in Monster World, Megaman - The Wily Wars (X24C01, 128 bytes) +// NFL Quarterback Club*, Frank Thomas Big Hurt Baseball (X24C04?) +// College Slam, Blockbuster World Video Game Championship II, NBA Jam (X24C04?) +// HardBall '95 + +// the above sports games use addr 0x200000 for SCL line (handled in Memory.c) + +unsigned int lastSSRamWrite = 0xffff0000; + +// sram_reg: LAtd sela (L=pending SCL, A=pending SDA, t=type(1==uses 0x200000 for SCL and 2K bytes), +// d=SRAM was detected (header or by access), s=started, e=save is EEPROM, l=old SCL, a=old SDA) +void SRAMWriteEEPROM(unsigned int d) // ???? ??la (l=SCL, a=SDA) +{ + unsigned int sreg = Pico.m.sram_reg, saddr = Pico.m.sram_addr, scyc = Pico.m.sram_cycle, ssa = Pico.m.sram_slave; + + //dprintf("[%02x]", d); + sreg |= saddr&0xc000; // we store word count in add reg: dw?a aaaa ... (d=word count detected, w=words(0==use 2 words, else 1)) + saddr&=0x1fff; + + if(sreg & d & 2) { + // SCL was and is still high.. + if((sreg & 1) && !(d&1)) { + // ..and SDA went low, means it's a start command, so clear internal addr reg and clock counter + //dprintf("-start-"); + if(!(sreg&0x8000) && scyc >= 9) { + if(scyc != 28) sreg |= 0x4000; // 1 word + //dprintf("detected word count: %i", scyc==28 ? 2 : 1); + sreg |= 0x8000; + } + //saddr = 0; + scyc = 0; + sreg |= 8; + } else if(!(sreg & 1) && (d&1)) { + // SDA went high == stop command + //dprintf("-stop-"); + sreg &= ~8; + } + } + else if((sreg & 8) && !(sreg & 2) && (d&2)) { + // we are started and SCL went high - next cycle + scyc++; // pre-increment + if(sreg & 0x20) { + // X24C02+ + if((ssa&1) && scyc == 18) { + scyc = 9; + saddr++; // next address in read mode + if(sreg&0x4000) saddr&=0xff; else saddr&=0x1fff; // mask + } + else if((sreg&0x4000) && scyc == 27) scyc = 18; + else if(scyc == 36) scyc = 27; + } else { + // X24C01 + if(scyc == 18) { + scyc = 9; // wrap + if(saddr&1) { saddr+=2; saddr&=0xff; } // next addr in read mode + } + } + //dprintf("scyc: %i", scyc); + } + else if((sreg & 8) && (sreg & 2) && !(d&2)) { + // we are started and SCL went low (falling edge) + if(sreg & 0x20) { + // X24C02+ + if(scyc == 9 || scyc == 18 || scyc == 27); // ACK cycles + else if( (!(sreg&0x4000) && scyc > 27) || ((sreg&0x4000) && scyc > 18) ) { + if(!(ssa&1)) { + // data write + unsigned char *pm=SRam.data+saddr; + *pm <<= 1; *pm |= d&1; + if(scyc == 26 || scyc == 35) { + saddr=(saddr&~0xf)|((saddr+1)&0xf); // only 4 (?) lowest bits are incremented + //dprintf("w done: %02x; addr inc: %x", *pm, saddr); + } + SRam.changed = 1; + } + } else if(scyc > 9) { + if(!(ssa&1)) { + // we latch another addr bit + saddr<<=1; + if(sreg&0x4000) saddr&=0xff; else saddr&=0x1fff; // mask + saddr|=d&1; + //if(scyc==17||scyc==26) dprintf("addr reg done: %x", saddr); + } + } else { + // slave address + ssa<<=1; ssa|=d&1; + //if(scyc==8) dprintf("slave done: %x", ssa); + } + } else { + // X24C01 + if(scyc == 9); // ACK cycle, do nothing + else if(scyc > 9) { + if(!(saddr&1)) { + // data write + unsigned char *pm=SRam.data+(saddr>>1); + *pm <<= 1; *pm |= d&1; + if(scyc == 17) { + saddr=(saddr&0xf9)|((saddr+2)&6); // only 2 lowest bits are incremented + //dprintf("addr inc: %x", saddr>>1); + } + SRam.changed = 1; + } + } else { + // we latch another addr bit + saddr<<=1; saddr|=d&1; saddr&=0xff; + //if(scyc==8) dprintf("addr done: %x", saddr>>1); + } + } + } + + sreg &= ~3; sreg |= d&3; // remember SCL and SDA + Pico.m.sram_reg = (unsigned char) sreg; + Pico.m.sram_addr = (unsigned short)(saddr|(sreg&0xc000)); + Pico.m.sram_cycle= (unsigned char) scyc; + Pico.m.sram_slave= (unsigned char) ssa; +} + +unsigned int SRAMReadEEPROM() +{ + unsigned int shift, d=0; + unsigned int sreg, saddr, scyc, ssa; + + // flush last pending write + SRAMWriteEEPROM(Pico.m.sram_reg>>6); + + sreg = Pico.m.sram_reg; saddr = Pico.m.sram_addr&0x1fff; scyc = Pico.m.sram_cycle; ssa = Pico.m.sram_slave; +// if(!(sreg & 2) && (sreg&0x80)) scyc++; // take care of raising edge now to compensate lag + + if(SekCyclesDoneT()-lastSSRamWrite < 46) { + // data was just written, there was no time to respond (used by sports games) + d = (sreg>>6)&1; + } else if((sreg & 8) && scyc > 9 && scyc != 18 && scyc != 27) { + // started and first command word received + shift = 17-scyc; + if(sreg & 0x20) { + // X24C02+ + if(ssa&1) { + //dprintf("read: addr %02x, cycle %i, reg %02x", saddr, scyc, sreg); + d = (SRam.data[saddr]>>shift)&1; + } + } else { + // X24C01 + if(saddr&1) { + d = (SRam.data[saddr>>1]>>shift)&1; + } + } + } + //else dprintf("r ack"); + + return d; +} + +void SRAMUpdPending(unsigned int a, unsigned int d) +{ + unsigned int sreg = Pico.m.sram_reg; + + if(!(a&1)) sreg|=0x20; + + if(sreg&0x20) { // address through 0x200000 + if(!(a&1)) { + sreg&=~0x80; + sreg|=d<<7; + } else { + sreg&=~0x40; + sreg|=(d<<6)&0x40; + } + } else { + sreg&=~0xc0; + sreg|=d<<6; + } + + Pico.m.sram_reg = (unsigned char) sreg; +} diff --git a/Pico/Pico.c b/Pico/Pico.c new file mode 100644 index 00000000..750ffc5f --- /dev/null +++ b/Pico/Pico.c @@ -0,0 +1,661 @@ +// This is part of Pico Library + +// (c) Copyright 2004 Dave, All rights reserved. +// (c) Copyright 2006 notaz, All rights reserved. +// Free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + + +#include "PicoInt.h" +#include "sound/sound.h" +#include "sound/ym2612.h" + +int PicoVer=0x0080; +struct Pico Pico; +int PicoOpt=0; // disable everything by default +int PicoSkipFrame=0; // skip rendering frame? +int PicoRegionOverride = 0; // override the region detection 0: Auto, 1: Japan NTSC, 2: Japan PAL, 4: US, 8: Europe +int emustatus = 0; +void (*PicoWriteSound)(void) = 0; // called once per frame at the best time to send sound buffer (PsndOut) to hardware + +struct PicoSRAM SRam; +int z80startCycle = 0, z80stopCycle = 0; // in 68k cycles +//int z80ExtraCycles = 0; +int PicoPad[2]; // Joypads, format is SACB RLDU +int PicoMCD = 0; // mega CD status + +// to be called once on emu init +int PicoInit(void) +{ + // Blank space for state: + memset(&Pico,0,sizeof(Pico)); + memset(&PicoPad,0,sizeof(PicoPad)); + + // Init CPUs: + SekInit(); + z80_init(); // init even if we aren't going to use it + + // Setup memory callbacks: + PicoMemInit(); + + PicoInitMCD(); + + // notaz: sram + SRam.data=0; + SRam.resize=1; + + return 0; +} + +// to be called once on emu exit +void PicoExit(void) +{ + PicoExitMCD(); + z80_exit(); + + // notaz: sram + if(SRam.data) free(SRam.data); SRam.data=0; +} + +int PicoReset(int hard) +{ + unsigned int region=0; + int support=0,hw=0,i=0; + unsigned char pal=0; + + if (Pico.romsize<=0) return 1; + + PicoMemReset(); + SekReset(); + SekCycleCntT=0; + z80_reset(); + + // reset VDP state, VRAM and PicoMisc + //memset(&Pico.video,0,sizeof(Pico.video)); + //memset(&Pico.vram,0,sizeof(Pico.vram)); + memset(&Pico.m,0,sizeof(Pico.m)); + Pico.video.pending_ints=0; + emustatus = 0; + + if(hard) { + // clear all memory of the emulated machine + memset(&Pico.ram,0,(unsigned int)&Pico.rom-(unsigned int)&Pico.ram); + } + + // default VDP register values (based on Fusion) + Pico.video.reg[0] = Pico.video.reg[1] = 0x04; + Pico.video.reg[0xc] = 0x81; + Pico.video.reg[0xf] = 0x02; + Pico.m.dirtyPal = 1; + + if(PicoRegionOverride) + { + support = PicoRegionOverride; + } + else + { + // Read cartridge region data: + region=PicoRead32(0x1f0); + + for (i=0;i<4;i++) + { + int c=0; + + c=region>>(i<<3); c&=0xff; + if (c<=' ') continue; + + if (c=='J') support|=1; + else if (c=='U') support|=4; + else if (c=='E') support|=8; + else + { + // New style code: + char s[2]={0,0}; + s[0]=(char)c; + support|=strtol(s,NULL,16); + } + } + } + + // Try to pick the best hardware value for English/50hz: + if (support&8) { hw=0xc0; pal=1; } // Europe + else if (support&4) hw=0x80; // USA + else if (support&2) { hw=0x40; pal=1; } // Japan PAL + else if (support&1) hw=0x00; // Japan NTSC + else hw=0x80; // USA + + Pico.m.hardware=(unsigned char)(hw|0x20); // No disk attached + Pico.m.pal=pal; + Pico.video.status = 0x3408 | pal; // always set bits | vblank | pal + + sound_reset(); // pal must be known here + + if (PicoMCD & 1) { + PicoResetMCD(hard); + SRam.data = 0; + return 0; + } + + + // notaz: sram + if(SRam.resize) { + int sram_size = 0; + if(SRam.data) free(SRam.data); SRam.data=0; + Pico.m.sram_reg = 0; + + if(*(Pico.rom+0x1B1) == 'R' && *(Pico.rom+0x1B0) == 'A') { + if(*(Pico.rom+0x1B2) & 0x40) { + // EEPROM SRAM + // what kind of EEPROMs are actually used? X24C02? X24C04? (X24C01 has only 128), but we will support up to 8K + SRam.start = PicoRead32(0x1B4) & ~1; // zero address is used for clock by some games + SRam.end = PicoRead32(0x1B8); + sram_size = 0x2000; + Pico.m.sram_reg = 4; + } else { + // normal SRAM + SRam.start = PicoRead32(0x1B4) & 0xFFFF00; + SRam.end = PicoRead32(0x1B8) | 1; + sram_size = SRam.end - SRam.start + 1; + } + Pico.m.sram_reg |= 0x10; // SRAM was detected + } + if(sram_size <= 0) { + // some games may have bad headers, like S&K and Sonic3 + SRam.start = 0x200000; + SRam.end = 0x203FFF; + sram_size = 0x004000; + } + + // enable sram access by default if it doesn't overlap with ROM + if(Pico.romsize <= SRam.start) Pico.m.sram_reg |= 1; + SRam.reg_back = Pico.m.sram_reg; + + if(sram_size) { + SRam.data = (unsigned char *) calloc(sram_size, 1); + if(!SRam.data) return 1; + } + SRam.resize=0; + // Dino Dini's Soccer malfunctions if SRAM is not filled with 0xff + if (strncmp((char *)Pico.rom+0x150, "IDOND NI'I", 10) == 0) + memset(SRam.data, 0xff, sram_size); + } + + Pico.m.sram_reg = SRam.reg_back; // restore sram_reg + SRam.changed = 0; + + return 0; +} + +static __inline void SekRun(int cyc) +{ + int cyc_do; + SekCycleAim+=cyc; + if((cyc_do=SekCycleAim-SekCycleCnt) < 0) return; +#if defined(EMU_C68K) && defined(EMU_M68K) + // this means we do run-compare Cyclone vs Musashi + SekCycleCnt+=CM_compareRun(cyc_do); +#elif defined(EMU_C68K) + PicoCpu.cycles=cyc_do; + CycloneRun(&PicoCpu); + SekCycleCnt+=cyc_do-PicoCpu.cycles; +#elif defined(EMU_A68K) + m68k_ICount=cyc_do; + M68000_RUN(); + SekCycleCnt+=cyc_do-m68k_ICount; +#elif defined(EMU_M68K) + SekCycleCnt+=m68k_execute(cyc_do); +#endif +} + +static __inline void SekStep(void) +{ + // this is required for timing sensitive stuff to work + int realaim=SekCycleAim; SekCycleAim=SekCycleCnt+1; +#if defined(EMU_C68K) && defined(EMU_M68K) + // this means we do run-compare Cyclone vs Musashi + SekCycleCnt+=CM_compareRun(1); +#elif defined(EMU_C68K) + PicoCpu.cycles=1; + CycloneRun(&PicoCpu); + SekCycleCnt+=1-PicoCpu.cycles; +#elif defined(EMU_A68K) + m68k_ICount=1; + M68000_RUN(); + SekCycleCnt+=1-m68k_ICount; +#elif defined(EMU_M68K) + SekCycleCnt+=m68k_execute(1); +#endif + SekCycleAim=realaim; +} + +static int CheckIdle(void) +{ +#if 1 + unsigned char state[0x88]; + + memset(state,0,sizeof(state)); + + // See if the state is the same after 2 steps: + SekState(state); SekStep(); SekStep(); SekState(state+0x44); + if (memcmp(state,state+0x44,0x44)==0) return 1; +#else + unsigned char state[0x44]; + static unsigned char oldstate[0x44]; + + SekState(state); + if(memcmp(state,oldstate,0x40)==0) return 1; + memcpy(oldstate, state, 0x40); +#endif + + return 0; +} + +// to be called on 224 or line_sample scanlines only +static __inline void getSamples(int y) +{ + if(y == 224) { + //dprintf("sta%i: %i [%i]", (emustatus & 2), emustatus, y); + if(emustatus & 2) + sound_render(PsndLen/2, PsndLen-PsndLen/2); + else sound_render(0, PsndLen); + if (emustatus&1) emustatus|=2; else emustatus&=~2; + if (PicoWriteSound) PicoWriteSound(); + // clear sound buffer + memset(PsndOut, 0, (PicoOpt & 8) ? (PsndLen<<2) : (PsndLen<<1)); + } + else if(emustatus & 3) { + emustatus|= 2; + emustatus&=~1; + sound_render(0, PsndLen/2); + } +} + +//extern UINT32 mz80GetRegisterValue(void *, UINT32); + +// Accurate but slower frame which does hints +static int PicoFrameHints(void) +{ + struct PicoVideo *pv=&Pico.video; + int total_z80=0,lines,y,lines_vis = 224,z80CycleAim = 0,line_sample; + const int cycles_68k=488,cycles_z80=228; // both PAL and NTSC compile to same values + int skip=PicoSkipFrame || (PicoOpt&0x10); + int hint; // Hint counter + + if(Pico.m.pal) { // + //cycles_68k = (int) ((double) OSC_PAL / 7 / 50 / 312 + 0.4); // should compile to a constant (488) + //cycles_z80 = (int) ((double) OSC_PAL / 15 / 50 / 312 + 0.4); // 228 + lines = 312; // Steve Snake says there are 313 lines, but this seems to also work well + line_sample = 68; + if(pv->reg[1]&8) lines_vis = 240; + } else { + //cycles_68k = (int) ((double) OSC_NTSC / 7 / 60 / 262 + 0.4); // 488 + //cycles_z80 = (int) ((double) OSC_NTSC / 15 / 60 / 262 + 0.4); // 228 + lines = 262; + line_sample = 93; + } + + SekCyclesReset(); + //z80ExtraCycles = 0; + + if(PicoOpt&4) + z80CycleAim = 0; +// z80_resetCycles(); + + pv->status&=~0x88; // clear V-Int, come out of vblank + + hint=pv->reg[10]; // Load H-Int counter + //dprintf("-hint: %i", hint); + + for (y=0;y 25) Pico.m.padTHPhase[0]=0; + if(Pico.m.padDelay[1]++ > 25) Pico.m.padTHPhase[1]=0; + } + + // H-Interrupts: + if(y <= lines_vis && --hint < 0) // y <= lines_vis: Comix Zone, Golden Axe + { + //dprintf("rhint:old @ %06x", SekPc); + hint=pv->reg[10]; // Reload H-Int counter + pv->pending_ints|=0x10; + if (pv->reg[0]&0x10) SekInterrupt(4); + //dprintf("rhint: %i @ %06x [%i|%i]", hint, SekPc, y, SekCycleCnt); + //dprintf("hint_routine: %x", (*(unsigned short*)(Pico.ram+0x0B84)<<16)|*(unsigned short*)(Pico.ram+0x0B86)); + } + + // V-Interrupt: + if (y == lines_vis) + { + //dprintf("vint: @ %06x [%i|%i]", SekPc, y, SekCycleCnt); + pv->status|=0x88; // V-Int happened, go into vblank + SekRun(128); SekCycleAim-=128; // there must be a gap between H and V ints, also after vblank bit set (Mazin Saga, Bram Stoker's Dracula) + /*if(Pico.m.z80Run && (PicoOpt&4)) { + z80CycleAim+=cycles_z80/2; + total_z80+=z80_run(z80CycleAim-total_z80); + z80CycleAim-=cycles_z80/2; + }*/ + pv->pending_ints|=0x20; + if(pv->reg[1]&0x20) SekInterrupt(6); + if(Pico.m.z80Run && (PicoOpt&4)) // ? + z80_int(); + //dprintf("zint: [%i|%i] zPC=%04x", Pico.m.scanline, SekCyclesDone(), mz80GetRegisterValue(NULL, 0)); + } + + // decide if we draw this line +#if CAN_HANDLE_240_LINES + if(!skip && ((!(pv->reg[1]&8) && y<224) || ((pv->reg[1]&8) && y<240)) ) +#else + if(!skip && y<224) +#endif + PicoLine(y); + + if(PicoOpt&1) + sound_timers_and_dac(y); + + // get samples from sound chips + if(y == 32 && PsndOut) + emustatus &= ~1; + else if((y == 224 || y == line_sample) && PsndOut) + getSamples(y); + + // Run scanline: + SekRun(cycles_68k); + if((PicoOpt&4) && Pico.m.z80Run) { + Pico.m.z80Run|=2; + z80CycleAim+=cycles_z80; + total_z80+=z80_run(z80CycleAim-total_z80); + } + } + + // draw a frame just after vblank in alternative render mode + if(!PicoSkipFrame && (PicoOpt&0x10)) + PicoFrameFull(); + + return 0; +} + +// helper z80 runner +static void PicoRunZ80Simple(int line_from, int line_to) +{ + int line_from_r=line_from, line_to_r=line_to, line = line_from; + int line_sample = Pico.m.pal ? 68 : 93; + extern const unsigned short vcounts[]; + + if(!(PicoOpt&4) || Pico.m.z80Run == 0) { line_from_r = line_to_r; line_to_r = 0; } + + if(z80startCycle != 0) { + line_from_r = vcounts[z80startCycle>>8]+1; + z80startCycle = 0; + } + if(z80stopCycle != 0) { + line_to_r = vcounts[z80stopCycle>>8]+1; + z80stopCycle = 0; + } + + if(PicoOpt&1) { + // we have ym2612 enabled, so we have to run Z80 in lines, so we could update DAC and timers + for(; line < line_to; line++) { + sound_timers_and_dac(line); + if((line == 224 || line == line_sample) && PsndOut) getSamples(line); + if(line == 32 && PsndOut) emustatus &= ~1; + if(line >= line_from_r && line < line_to_r) + z80_run(228); + } + } else if(line_to_r-line_from_r > 0) { + z80_run(228*(line_to_r-line_from_r)); + // samples will be taken by caller + } +} + +// Simple frame without H-Ints +static int PicoFrameSimple(void) +{ + struct PicoVideo *pv=&Pico.video; + int y=0,line=0,lines=0,lines_step=0,sects; + int cycles_68k_vblock,cycles_68k_block; + + if(Pico.m.pal) { + // M68k cycles/frame: 152009.78 + if(pv->reg[1]&8) { // 240 lines + cycles_68k_block = (int) ((double) OSC_PAL / 7 / 50 / 312 * 15 + 0.4); // 16 sects, 16*15=240, 7308 + cycles_68k_vblock = (int) ((double) OSC_PAL / 7 / 50 / 312 * 24 + 0.4); // 3 sects, 3*24=72, 35163? + lines_step = 15; + } else { + cycles_68k_block = (int) ((double) OSC_PAL / 7 / 50 / 312 * 14 + 0.4); // 16*14=224 + cycles_68k_vblock = (int) ((double) OSC_PAL / 7 / 50 / 312 * 22 + 0.4); // 4 sects, 4*22=88 + lines_step = 14; + } + } else { + // M68k cycles/frame: 127840.71 + cycles_68k_block = (int) ((double) OSC_NTSC / 7 / 60 / 262 * 14 + 0.4); // 16*14=224, 6831 + cycles_68k_vblock = (int) ((double) OSC_NTSC / 7 / 60 / 262 * 19 + 0.4); // 2 sects, 2*19=38, 18544 + lines_step = 14; + } + + Pico.m.scanline=-1; + + SekCyclesReset(); + + if(PicoOpt&4) + z80_resetCycles(); + + // 6 button pad: let's just say it timed out now + Pico.m.padTHPhase[0]=Pico.m.padTHPhase[1]=0; + + // ---- Active Scan ---- + pv->status&=~88; // clear V-Int, come out of vblank + + // Run in sections: + for(sects=16; sects; sects--) + { + if (CheckIdle()) break; + + lines += lines_step; + SekRun(cycles_68k_block); + + PicoRunZ80Simple(line, lines); + line=lines; + } + + // run Z80 for remaining sections + if(sects) { + int c = sects*cycles_68k_block; + + lines += sects*lines_step; + PicoRunZ80Simple(line, lines); + // this is for approriate line counter, etc + SekCycleCnt += c; + SekCycleAim += c; + } + + // here we render sound if ym2612 is disabled + if(!(PicoOpt&1) && PsndOut) { + sound_render(0, PsndLen); + if(PicoWriteSound) PicoWriteSound(); + // clear sound buffer + memset(PsndOut, 0, (PicoOpt & 8) ? (PsndLen<<2) : (PsndLen<<1)); + } + + // render screen + if(!PicoSkipFrame) { + if(!(PicoOpt&0x10)) + // Draw the screen +#if CAN_HANDLE_240_LINES + if(pv->reg[1]&8) { + for (y=0;y<240;y++) PicoLine(y); + } else { + for (y=0;y<224;y++) PicoLine(y); + } +#else + for (y=0;y<224;y++) PicoLine(y); +#endif + else PicoFrameFull(); + } + + // ---- V-Blanking period ---- + // fix line counts + if(Pico.m.pal) { + if(pv->reg[1]&8) { // 240 lines + lines = line = 240; + sects = 3; + lines_step = 24; + } else { + lines = line = 224; + sects = 4; + lines_step = 22; + } + } else { + lines = line = 224; + sects = 2; + lines_step = 19; + } + + //dprintf("vint: @ %06x [%i]", SekPc, SekCycleCnt); + pv->pending_ints|=0x20; + if (pv->reg[1]&0x20) SekInterrupt(6); // Set IRQ + pv->status|=0x88; // V-Int happened / go into vblank + if(Pico.m.z80Run && (PicoOpt&4)) // ? + z80_int(); + + while(sects) { + lines += lines_step; + + SekRun(cycles_68k_vblock); + + PicoRunZ80Simple(line, lines); + line=lines; + + sects--; + if(sects && CheckIdle()) break; + } + + // run Z80 for remaining sections + if(sects) { + lines += sects*lines_step; + PicoRunZ80Simple(line, lines); + } + + return 0; +} + +int PicoFrame(void) +{ + int acc; + + if (PicoMCD & 1) { + PicoFrameMCD(); + return 0; + } + + // be accurate if we are asked for this + if(PicoOpt&0x40) acc=1; + // don't be accurate in alternative render mode, as hint effects will not be rendered anyway + else if(PicoOpt&0x10) acc = 0; + else acc=Pico.video.reg[0]&0x10; // be accurate if hints are used + + //if(Pico.video.reg[12]&0x2) Pico.video.status ^= 0x10; // change odd bit in interlace mode + + if(!(PicoOpt&0x10)) + PicoFrameStart(); + + if(acc) + PicoFrameHints(); + else PicoFrameSimple(); + + return 0; +} + +static int DefaultCram(int cram) +{ + int high=0x0841; + // Convert 0000bbbb ggggrrrr + // to rrrr1ggg g10bbbb1 + high|=(cram&0x00f)<<12; // Red + high|=(cram&0x0f0)<< 3; // Green + high|=(cram&0xf00)>> 7; // Blue + return high; +} + +// Function to convert Megadrive Cram into a native colour: +int (*PicoCram)(int cram)=DefaultCram; + +#if defined(__DEBUG_PRINT) || defined(WIN32) +// tmp debug: dump some stuff +#define bit(r, x) ((r>>x)&1) +void z80_debug(char *dstr); +char *debugString() +{ +#if 1 + static char dstr[1024]; + unsigned char *reg=Pico.video.reg, r; + + // dump some info + sprintf(dstr, "mode set 1: %02x\n", (r=reg[0])); + sprintf(dstr, "%sdisplay_disable: %i, M3: %i, palette: %i, ?, hints: %i\n\n", dstr, bit(r,0), bit(r,1), bit(r,2), bit(r,4)); + sprintf(dstr, "%smode set 2: %02x\n", dstr, (r=reg[1])); + sprintf(dstr, "%sSMS/genesis: %i, pal: %i, dma: %i, vints: %i, disp: %i, TMS9918: %i\n\n",dstr, bit(r,2), bit(r,3), bit(r,4), bit(r,5), bit(r,6), bit(r,7)); + sprintf(dstr, "%smode set 3: %02x\n", dstr, (r=reg[0xB])); + sprintf(dstr, "%sLSCR: %i, HSCR: %i, 2cell vscroll: %i, IE2: %i\n\n", dstr, bit(r,0), bit(r,1), bit(r,2), bit(r,3)); + sprintf(dstr, "%smode set 4: %02x\n", dstr, (r=reg[0xC])); + sprintf(dstr, "%sinterlace: %i%i; cells: %i; shadow: %i\n\n", dstr, bit(r,2), bit(r,1), (r&0x80) ? 40 : 32, bit(r,3)); + sprintf(dstr, "%sscroll size: w: %i; h: %i\n\n", dstr, reg[0x10]&3, (reg[0x10]&0x30)>>4); + sprintf(dstr, "%sSRAM: det: %i; eeprom: %i\n", dstr, bit(Pico.m.sram_reg, 4), bit(Pico.m.sram_reg, 2)); + sprintf(dstr, "%sCPU state: PC: %06x cycles: %i\n", dstr, SekPc, SekCyclesDoneT()); +#ifdef EMU_C68K + for(r=0; r < 8; r++) + sprintf(dstr, "%sd%i=%08x, a%i=%08x\n", dstr, r, PicoCpu.d[r], r, PicoCpu.a[r]); +#endif + z80_debug(dstr); + +#else + struct PicoVideo *pvid=&Pico.video; + int table=0; + int i,u,n,link=0; + static char dstr[1024*8]; + dstr[0] = 0; + + table=pvid->reg[5]&0x7f; + if (pvid->reg[12]&1) table&=0x7e; // Lowest bit 0 in 40-cell mode + table<<=8; // Get sprite table address/2 + + for (i=u=n=0; u < 80 && n < 20; u++) + { + unsigned int *sprite; + int code, code2, sx, sy, height; + + sprite=(unsigned int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite + + // get sprite info + code = sprite[0]; + + // check if it is on this line + sy = (code&0x1ff);//-0x80; + height = ((code>>24)&3)+1; + + // masking sprite? + code2 = sprite[1]; + sx = (code2>>16)&0x1ff; + + dprintf("#%02i x: %03i y: %03i %ix%i", u, sx, sy, ((code>>26)&3)+1, height); + + link=(code>>16)&0x7f; + if(!link) break; // End of sprites + } +#endif + +#if 0 + { + FILE *f = fopen("zram", "wb"); + fwrite(Pico.zram, 1, 0x2000, f); + fclose(f); + } +#endif + + return dstr; +} +#endif diff --git a/Pico/Pico.h b/Pico/Pico.h new file mode 100644 index 00000000..f1b3b091 --- /dev/null +++ b/Pico/Pico.h @@ -0,0 +1,96 @@ + +// -------------------- Pico Library -------------------- + +// Pico Library - Header File + +// (c) Copyright 2004 Dave, All rights reserved. +// (c) Copyright 2006 notaz, All rights reserved. +// Free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + +#ifndef PICO_H +#define PICO_H + +// port-specific compile-time settings +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Pico.c +// PicoOpt bits LSb->MSb: +// enable_ym2612&dac, enable_sn76496, enable_z80, stereo_sound, +// alt_renderer, 6button_gamepad, accurate_timing, accurate_sprites, +// draw_no_32col_border, external_ym2612 +extern int PicoOpt; +extern int PicoVer; +extern int PicoSkipFrame; // skip rendering frame, but still do sound (if enabled) and emulation stuff +extern int PicoRegionOverride; // override the region detection 0: auto, 1: Japan NTSC, 2: Japan PAL, 4: US, 8: Europe +int PicoInit(void); +void PicoExit(void); +int PicoReset(int hard); +int PicoFrame(void); +extern int PicoPad[2]; // Joypads, format is MXYZ SACB RLDU +extern int (*PicoCram)(int cram); // Callback to convert colour ram 0000bbb0 ggg0rrr0 +extern void (*PicoWriteSound)(void); // called once per frame at the best time to send sound buffer (PsndOut) to hardware + +int PicoFrameMCD(void); + +// Area.c +typedef size_t (arearw)(void *p, size_t _size, size_t _n, void *file); +// Save or load the state from PmovFile: +int PmovState(int PmovAction, void *PmovFile); // &1=for reading &2=for writing &4=volatile &8=non-volatile +extern arearw *areaRead; // read and write function pointers for +extern arearw *areaWrite; // gzip save state ability + +// Cart.c +int PicoCartLoad(FILE *f,unsigned char **prom,unsigned int *psize); +int PicoCartInsert(unsigned char *rom,unsigned int romsize); +// notaz +int CartLoadZip(const char *fname, unsigned char **prom, unsigned int *psize); +void Byteswap(unsigned char *data,int len); +// anotherguest +int PicoUnloadCart(unsigned char* romdata); + +// Draw.c +void PicoDrawSetColorFormat(int which); // 0=BGR444, 1=RGB555, 2=8bit(HighPal pal) +extern void *DrawLineDest; +extern int (*PicoScan)(unsigned int num, void *data); +// internals +extern unsigned short HighPal[0x100]; +extern int rendstatus; +// utility +#ifdef _ASM_DRAW_C +void *blockcpy(void *dst, const void *src, size_t n); +#else +#define blockcpy memcpy +#endif + +// Draw2.c +// stuff below is optional +extern unsigned short *PicoCramHigh; // pointer to CRAM buff (0x40 shorts), converted to native device color (works only with 16bit for now) +extern void (*PicoPrepareCram)(); // prepares PicoCramHigh for renderer to use + +// sound.c +extern int PsndRate,PsndLen; +extern short *PsndOut; +void sound_reset(); +void sound_rerate(); +void z80_pack(unsigned char *data); +void z80_unpack(unsigned char *data); +void z80_reset(); + +// Utils.c +extern int PicuAnd; +int PicuQuick(unsigned short *dest,unsigned short *src); +int PicuShrink(unsigned short *dest,int destLen,unsigned short *src,int srcLen); +int PicuShrinkReverse(unsigned short *dest,int destLen,unsigned short *src,int srcLen); +int PicuMerge(unsigned short *dest,int destLen,unsigned short *src,int srcLen); + +#ifdef __cplusplus +} // End of extern "C" +#endif + +#endif // PICO_H diff --git a/Pico/PicoInt.h b/Pico/PicoInt.h new file mode 100644 index 00000000..7d91df7b --- /dev/null +++ b/Pico/PicoInt.h @@ -0,0 +1,240 @@ +// Pico Library - Header File + +// (c) Copyright 2004 Dave, All rights reserved. +// (c) Copyright 2006 notaz, All rights reserved. +// Free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + + +#include +#include +#include +#include "Pico.h" + + +// to select core, define EMU_C68K, EMU_M68K or EMU_A68K in your makefile + +#ifdef __cplusplus +extern "C" { +#endif + + +// ----------------------- 68000 CPU ----------------------- +#ifdef EMU_C68K +#include "../cpu/Cyclone/Cyclone.h" +extern struct Cyclone PicoCpu; +#define SekCyclesLeft PicoCpu.cycles // cycles left for this run +#define SekSetCyclesLeft(c) PicoCpu.cycles=c +#define SekPc (PicoCpu.pc-PicoCpu.membase) +#endif + +#ifdef EMU_A68K +void __cdecl M68000_RUN(); +// The format of the data in a68k.asm (at the _M68000_regs location) +struct A68KContext +{ + unsigned int d[8],a[8]; + unsigned int isp,srh,ccr,xc,pc,irq,sr; + int (*IrqCallback) (int nIrq); + unsigned int ppc; + void *pResetCallback; + unsigned int sfc,dfc,usp,vbr; + unsigned int AsmBank,CpuVersion; +}; +struct A68KContext M68000_regs; +extern int m68k_ICount; +#define SekCyclesLeft m68k_ICount +#define SekSetCyclesLeft(c) m68k_ICount=c +#define SekPc M68000_regs.pc +#endif + +#ifdef EMU_M68K +#include "../cpu/musashi/m68kcpu.h" +extern m68ki_cpu_core PicoM68kCPU; // MD's CPU +extern m68ki_cpu_core PicoS68kCPU; // Mega CD's CPU +#ifndef SekCyclesLeft +#define SekCyclesLeft m68k_cycles_remaining() +#define SekSetCyclesLeft(c) SET_CYCLES(c) +#define SekPc m68k_get_reg(&PicoM68kCPU, M68K_REG_PC) +#define SekPcS68k m68k_get_reg(&PicoS68kCPU, M68K_REG_PC) +#endif +#endif + +extern int SekCycleCnt; // cycles done in this frame +extern int SekCycleAim; // cycle aim +extern unsigned int SekCycleCntT; // total cycle counter, updated once per frame + +#define SekCyclesReset() {SekCycleCntT+=SekCycleCnt;SekCycleCnt=SekCycleAim=0;} +#define SekCyclesBurn(c) SekCycleCnt+=c +#define SekCyclesDone() (SekCycleAim-SekCyclesLeft) // nuber of cycles done in this frame (can be checked anywhere) +#define SekCyclesDoneT() (SekCycleCntT+SekCyclesDone()) // total nuber of cycles done for this rom + +#define SekEndRun(after) { \ + SekCycleCnt -= SekCyclesLeft - after; \ + if(SekCycleCnt < 0) SekCycleCnt = 0; \ + SekSetCyclesLeft(after); \ +} + +extern int SekCycleCntS68k; +extern int SekCycleAimS68k; + +#define SekCyclesResetS68k() {SekCycleCntS68k=SekCycleAimS68k=0;} + +// does not work as expected +//extern int z80ExtraCycles; // extra z80 cycles, used when z80 is [en|dis]abled + +extern int PicoMCD; + +// --------------------------------------------------------- + +// main oscillator clock which controls timing +#define OSC_NTSC 53693100 +#define OSC_PAL 53203424 // not accurate + +struct PicoVideo +{ + unsigned char reg[0x20]; + unsigned int command; // 32-bit Command + unsigned char pending; // 1 if waiting for second half of 32-bit command + unsigned char type; // Command type (v/c/vsram read/write) + unsigned short addr; // Read/Write address + int status; // Status bits + unsigned char pending_ints; // pending interrupts: ??VH???? + unsigned char pad[0x13]; +}; + +struct PicoMisc +{ + unsigned char rotate; + unsigned char z80Run; + unsigned char padTHPhase[2]; // phase of gamepad TH switches + short scanline; // 0 to 261||311; -1 in fast mode + char dirtyPal; // Is the palette dirty (1 - change @ this frame, 2 - some time before) + unsigned char hardware; // Hardware value for country + unsigned char pal; // 1=PAL 0=NTSC + unsigned char sram_reg; // SRAM mode register. bit0: allow read? bit1: deny write? bit2: EEPROM? + unsigned short z80_bank68k; + unsigned short z80_lastaddr; // this is for Z80 faking + unsigned char z80_fakeval; + unsigned char pad0; + unsigned char padDelay[2]; // gamepad phase time outs, so we count a delay + unsigned short sram_addr; // EEPROM address register + unsigned char sram_cycle; // EEPROM SRAM cycle number + unsigned char sram_slave; // EEPROM slave word for X24C02 and better SRAMs + unsigned char prot_bytes[2]; // simple protection fakeing + unsigned char pad1[8]; +}; + +// some assembly stuff depend on these, do not touch! +struct Pico +{ + unsigned char ram[0x10000]; // 0x00000 scratch ram + unsigned short vram[0x8000]; // 0x10000 + unsigned char zram[0x2000]; // 0x20000 Z80 ram + unsigned char ioports[0x10]; + unsigned int pad[0x3c]; // unused + unsigned short cram[0x40]; // 0x22100 + unsigned short vsram[0x40]; // 0x22180 + + unsigned char *rom; // 0x22200 + unsigned int romsize; // 0x22204 + + struct PicoMisc m; + struct PicoVideo video; +}; + +// sram +struct PicoSRAM +{ + unsigned char *data; // actual data + unsigned int start; // start address in 68k address space + unsigned int end; + unsigned char resize; // 1=SRAM size changed and needs to be reallocated on PicoReset + unsigned char reg_back; // copy of Pico.m.sram_reg to set after reset + unsigned char changed; + unsigned char pad; +}; + +// MCD +#include "cd/cd_sys.h" +#include "cd/LC89510.h" + +typedef struct +{ + unsigned char bios[0x20000]; + union { + unsigned char prg_ram[0x80000]; + unsigned char prg_ram_b[4][0x20000]; + }; + unsigned char word_ram[0x40000]; + unsigned char s68k_regs[0x200]; + unsigned char m68k_regs[0x10]; + CDD cdd; + CDC cdc; + _scd scd; +} mcd_state; + +#define Pico_mcd ((mcd_state *)Pico.rom) + + +// Draw.c +int PicoLine(int scan); +void PicoFrameStart(); + +// Draw2.c +void PicoFrameFull(); + +// Memory.c +int PicoInitPc(unsigned int pc); +unsigned int CPU_CALL PicoRead32(unsigned int a); +int PicoMemInit(); +void PicoMemReset(); +void PicoDasm(int start,int len); +unsigned char z80_read(unsigned short a); +unsigned short z80_read16(unsigned short a); +void z80_write(unsigned char data, unsigned short a); +void z80_write16(unsigned short data, unsigned short a); + +// cd/Memory.c +unsigned char PicoReadCD8 (unsigned int a); +unsigned short PicoReadCD16(unsigned int a); +unsigned int PicoReadCD32(unsigned int a); +void PicoWriteCD8 (unsigned int a, unsigned char d); +void PicoWriteCD16(unsigned int a, unsigned short d); +void PicoWriteCD32(unsigned int a, unsigned int d); + +// Pico.c +extern struct Pico Pico; +extern struct PicoSRAM SRam; +extern int emustatus; + +// cd/Pico.c +int PicoInitMCD(void); +void PicoExitMCD(void); +int PicoResetMCD(int hard); + +// Sek.c +int SekInit(void); +int SekReset(void); +int SekInterrupt(int irq); +void SekState(unsigned char *data); + +// cd/Sek.c +int SekInitS68k(void); +int SekResetS68k(void); +int SekInterruptS68k(int irq); + +// VideoPort.c +void PicoVideoWrite(unsigned int a,unsigned short d); +unsigned int PicoVideoRead(unsigned int a); + +// Misc.c +void SRAMWriteEEPROM(unsigned int d); +unsigned int SRAMReadEEPROM(); +void SRAMUpdPending(unsigned int a, unsigned int d); + + +#ifdef __cplusplus +} // End of extern "C" +#endif diff --git a/Pico/Sek.c b/Pico/Sek.c new file mode 100644 index 00000000..df98d9d3 --- /dev/null +++ b/Pico/Sek.c @@ -0,0 +1,192 @@ +// This is part of Pico Library + +// (c) Copyright 2004 Dave, All rights reserved. +// (c) Copyright 2006 notaz, All rights reserved. +// Free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + + +#include "PicoInt.h" + + +int SekCycleCnt=0; // cycles done in this frame +int SekCycleAim=0; // cycle aim +unsigned int SekCycleCntT=0; + +#ifdef EMU_C68K +// ---------------------- Cyclone 68000 ---------------------- +struct Cyclone PicoCpu; +#endif + +#ifdef EMU_M68K +// ---------------------- MUSASHI 68000 ---------------------- +m68ki_cpu_core PicoM68kCPU; // MD's CPU +#endif + +#ifdef EMU_A68K +// ---------------------- A68K ---------------------- + +void __cdecl M68000_RESET(); +int m68k_ICount=0; +unsigned int mem_amask=0xffffff; // 24-bit bus +unsigned int mame_debug=0,cur_mrhard=0,m68k_illegal_opcode=0,illegal_op=0,illegal_pc=0,opcode_entry=0; // filler + +static int IrqCallback(int i) { i; return -1; } +static int DoReset() { return 0; } +static int (*ResetCallback)()=DoReset; + +#pragma warning (disable:4152) +#endif + + + +// interrupt acknowledgment +#ifdef EMU_C68K +static void SekIntAck(int level) +{ + // try to emulate VDP's reaction to 68000 int ack + if (level == 4) Pico.video.pending_ints = 0; + else if(level == 6) Pico.video.pending_ints &= ~0x20; + PicoCpu.irq = 0; +} + +static void SekResetAck() +{ +#if defined(__DEBUG_PRINT) || defined(WIN32) + dprintf("Reset encountered @ %06x", SekPc); +#endif +} + +static int SekUnrecognizedOpcode() +{ + unsigned int pc, op; + pc = SekPc; + op = PicoCpu.read16(pc); +#if defined(__DEBUG_PRINT) || defined(WIN32) + dprintf("Unrecognized Opcode %04x @ %06x", op, pc); +#endif + // see if we are not executing trash + if (pc < 0x200 || (pc > Pico.romsize+4 && (pc&0xe00000)!=0xe00000)) { + PicoCpu.cycles = 0; + PicoCpu.stopped = 1; + return 1; + } + //exit(1); + return 0; +} +#endif + + +#ifdef EMU_M68K +static int SekIntAckM68K(int level) +{ + if (level == 4) { Pico.video.pending_ints = 0; } // dprintf("hack: [%i|%i]", Pico.m.scanline, SekCyclesDone()); } + else if(level == 6) { Pico.video.pending_ints &= ~0x20; } // dprintf("vack: [%i|%i]", Pico.m.scanline, SekCyclesDone()); } + CPU_INT_LEVEL = 0; + return M68K_INT_ACK_AUTOVECTOR; +} +#endif + + + +int SekInit() +{ +#ifdef EMU_C68K + CycloneInit(); + memset(&PicoCpu,0,sizeof(PicoCpu)); + PicoCpu.IrqCallback=SekIntAck; + PicoCpu.ResetCallback=SekResetAck; + PicoCpu.UnrecognizedCallback=SekUnrecognizedOpcode; +#endif +#ifdef EMU_A68K + memset(&M68000_regs,0,sizeof(M68000_regs)); + M68000_regs.IrqCallback=IrqCallback; + M68000_regs.pResetCallback=ResetCallback; + M68000_RESET(); // Init cpu emulator +#endif +#ifdef EMU_M68K + { + void *oldcontext = m68ki_cpu_p; + m68k_set_context(&PicoM68kCPU); + m68k_set_cpu_type(M68K_CPU_TYPE_68000); + m68k_init(); + m68k_set_int_ack_callback(SekIntAckM68K); + m68k_pulse_reset(); // Init cpu emulator + m68k_set_context(oldcontext); + } +#endif + + return 0; +} + +// Reset the 68000: +int SekReset() +{ + if (Pico.rom==NULL) return 1; + +#ifdef EMU_C68K + PicoCpu.stopped=0; + PicoCpu.osp=0; + PicoCpu.srh =0x27; // Supervisor mode + PicoCpu.flags=4; // Z set + PicoCpu.irq=0; + PicoCpu.a[7]=PicoCpu.read32(0); // Stack Pointer + PicoCpu.membase=0; + PicoCpu.pc=PicoCpu.checkpc(PicoCpu.read32(4)); // Program Counter +#endif +#ifdef EMU_A68K + // Reset CPU: fetch SP and PC + M68000_regs.srh=0x27; // Supervisor mode + M68000_regs.a[7]=PicoRead32(0); + M68000_regs.pc =PicoRead32(4); + PicoInitPc(M68000_regs.pc); +#endif +#ifdef EMU_M68K + { + void *oldcontext = m68ki_cpu_p; + m68k_set_context(&PicoM68kCPU); + m68k_pulse_reset(); + m68k_set_context(oldcontext); + } +#endif + + return 0; +} + + +int SekInterrupt(int irq) +{ +#ifdef EMU_C68K + PicoCpu.irq=irq; +#endif +#ifdef EMU_A68K + M68000_regs.irq=irq; // raise irq (gets lowered after taken) +#endif +#ifdef EMU_M68K + { + void *oldcontext = m68ki_cpu_p; + m68k_set_context(&PicoM68kCPU); + m68k_set_irq(irq); // raise irq (gets lowered after taken or must be done in ack) + m68k_set_context(oldcontext); + } +#endif + return 0; +} + +//int SekPc() { return PicoCpu.pc-PicoCpu.membase; } +//int SekPc() { return M68000_regs.pc; } +//int SekPc() { return m68k_get_reg(NULL, M68K_REG_PC); } + +void SekState(unsigned char *data) +{ +#ifdef EMU_C68K + memcpy(data,PicoCpu.d,0x44); +#elif defined(EMU_A68K) + memcpy(data, M68000_regs.d, 0x40); + memcpy(data+0x40,&M68000_regs.pc,0x04); +#elif defined(EMU_M68K) + memcpy(data, PicoM68kCPU.dar,0x40); + memcpy(data+0x40,&PicoM68kCPU.pc, 0x04); +#endif +} diff --git a/Pico/Utils.c b/Pico/Utils.c new file mode 100644 index 00000000..22bd3ace --- /dev/null +++ b/Pico/Utils.c @@ -0,0 +1,108 @@ +// This is part of Pico Library + +// (c) Copyright 2004 Dave, All rights reserved. +// (c) Copyright 2006 notaz, All rights reserved. +// Free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + + +#include "PicoInt.h" + +int PicuAnd=0xf7de; + +// Quick low-quality conversion of 320 to 176: +int PicuQuick(unsigned short *dest,unsigned short *src) +{ + unsigned short *end=NULL; + + src+=13; end=src+290; + dest++; + + do + { + *dest++=*src++; + *dest++=*src; src+=2; + *dest++=*src; src+=2; + *dest++=*src++; + *dest++=*src; src+=2; + *dest++=*src; src+=2; + } + while (src>=1; bias+=destLen; } + *dest++=(unsigned short)pa; + + pa=*src++; bias-=sub; + if (bias<0) { pa+=*src++; pa>>=1; bias+=destLen; } + *dest++=(unsigned short)pa; + } + while (dest>=1; bias+=destLen; } + *(--dest)=(unsigned short)pa; + + pa=*src++; bias-=sub; + if (bias<0) { pa+=*src++; pa>>=1; bias+=destLen; } + *(--dest)=(unsigned short)pa; + } + while (dest>end); + + return 0; +} + +int PicuMerge(unsigned short *dest,int destLen,unsigned short *src,int srcLen) +{ + unsigned short *end=NULL; + int bias=0,pa=0,mask=PicuAnd,sub=0; + + end=dest+destLen; + sub=srcLen-destLen; + + do + { + pa=*src++; bias-=sub; + if (bias<0) { pa+=*src++; pa>>=1; bias+=destLen; } + pa&=mask; pa+=(*dest)&mask; pa>>=1; + *dest++=(unsigned short)pa; + + pa=*src++; bias-=sub; + if (bias<0) { pa+=*src++; pa>>=1; bias+=destLen; } + pa&=mask; pa+=(*dest)&mask; pa>>=1; + *dest++=(unsigned short)pa; + } + while (dest>8)); // If address is odd, bytes are swapped (which game needs this?) + Pico.vram [(a>>1)&0x7fff]=d; + rendstatus|=0x10; break; + case 3: Pico.m.dirtyPal = 1; + //dprintf("w[%i] @ %04x, inc=%i [%i|%i]", Pico.video.type, a, Pico.video.reg[0xf], Pico.m.scanline, SekCyclesDone()); + Pico.cram [(a>>1)&0x003f]=d; break; // wraps (Desert Strike) + case 5: Pico.vsram[(a>>1)&0x003f]=d; break; + } + + //dprintf("w[%i] @ %04x, inc=%i [%i|%i]", Pico.video.type, a, Pico.video.reg[0xf], Pico.m.scanline, SekCyclesDone()); + AutoIncrement(); +} + +static unsigned int VideoRead() +{ + unsigned int a=0,d=0; + + a=Pico.video.addr; a>>=1; + + switch (Pico.video.type) + { + case 0: d=Pico.vram [a&0x7fff]; break; + case 8: d=Pico.cram [a&0x003f]; break; + case 4: d=Pico.vsram[a&0x003f]; break; + } + + AutoIncrement(); + return d; +} + +// calculate the number of cycles 68k->VDP dma operation would take +static int DmaSlowBurn(int len) +{ + // test: Legend of Galahad, Time Killers + int burn,maxlen,line=Pico.m.scanline; + + if(line == -1) line=vcounts[SekCyclesDone()>>8]; + maxlen=(224-line)*18; + if(len <= maxlen) + burn = len*(((488<<8)/18))>>8; + else { + burn = maxlen*(((488<<8)/18))>>8; + burn += (len-maxlen)*(((488<<8)/180))>>8; + } + + return burn; +} + +static int GetDmaLength() +{ + struct PicoVideo *pvid=&Pico.video; + int len=0; + // 16-bit words to transfer: + len =pvid->reg[0x13]; + len|=pvid->reg[0x14]<<8; + // Charles MacDonald: + if(!len) len = 0xffff; + return len; +} + +static void DmaSlow(int len) +{ + u16 *pd=0, *pdend, *r; + unsigned int a=Pico.video.addr, a2, d; + unsigned char inc=Pico.video.reg[0xf]; + unsigned int source, burn; + + source =Pico.video.reg[0x15]<<1; + source|=Pico.video.reg[0x16]<<9; + source|=Pico.video.reg[0x17]<<17; + + //dprintf("DmaSlow[%i] %06x->%04x len %i inc=%i blank %i [%i|%i]", Pico.video.type, source, a, len, inc, + // (Pico.video.status&8)||!(Pico.video.reg[1]&0x40), Pico.m.scanline, SekCyclesDone()); + + if ((source&0xe00000)==0xe00000) { pd=(u16 *)(Pico.ram+(source&0xfffe)); pdend=(u16 *)(Pico.ram+0x10000); } // Ram + else if(source>8); // very approximate + if(!(Pico.video.status&8)) burn+=burn>>1; // a hack for Legend of Galahad + } else burn = DmaSlowBurn(len); + SekCyclesBurn(burn); + if(!(Pico.video.status&8)) + SekEndRun(0); + //dprintf("DmaSlow burn: %i @ %06x", burn, SekPc); + + switch (Pico.video.type) + { + case 1: // vram + r = Pico.vram; + for(; len; len--) + { + d=*pd++; + if(a&1) d=(d<<8)|(d>>8); + r[a>>1] = (u16)d; // will drop the upper bits + // AutoIncrement + a=(u16)(a+inc); + // didn't src overlap? + if(pd >= pdend) pd-=0x8000; // should be good for RAM, bad for ROM + } + rendstatus|=0x10; + break; + + case 3: // cram + //dprintf("DmaSlow[%i] %06x->%04x len %i inc=%i blank %i [%i|%i]", Pico.video.type, source, a, len, inc, + // (Pico.video.status&8)||!(Pico.video.reg[1]&0x40), Pico.m.scanline, SekCyclesDone()); + Pico.m.dirtyPal = 1; + r = Pico.cram; + for(a2=a&0x7f; len; len--) + { + r[a2>>1] = (u16)*pd++;; // bit 0 is ignored + // AutoIncrement + a2+=inc; + // didn't src overlap? + if(pd >= pdend) pd-=0x8000; + // good dest? + if(a2 >= 0x80) break; // Todds Adventures in Slime World / Andre Agassi tennis + } + a=(a&0xff00)|a2; + break; + + case 5: // vsram[a&0x003f]=d; + r = Pico.vsram; + for(a2=a&0x7f; len; len--) + { + r[a2>>1] = (u16)*pd++; + // AutoIncrement + a2+=inc; + // didn't src overlap? + if(pd >= pdend) pd-=0x8000; + // good dest? + if(a2 >= 0x80) break; + } + a=(a&0xff00)|a2; + break; + } + // remember addr + Pico.video.addr=(u16)a; +} + +static void DmaCopy(int len) +{ + u16 a=Pico.video.addr; + unsigned char *vr = (unsigned char *) Pico.vram; + unsigned char *vrs; + unsigned char inc=Pico.video.reg[0xf]; + int source; + //dprintf("DmaCopy len %i [%i|%i]", len, Pico.m.scanline, SekCyclesDone()); + + source =Pico.video.reg[0x15]; + source|=Pico.video.reg[0x16]<<8; + vrs=vr+source; + + if(source+len > 0x10000) len=0x10000-source; // clip?? + + for(;len;len--) + { + vr[a] = *vrs++; + // AutoIncrement + a=(u16)(a+inc); + } + // remember addr + Pico.video.addr=a; + rendstatus|=0x10; +} + +// check: Contra, Megaman +// note: this is still inaccurate +static void DmaFill(int data) +{ + int len; + unsigned short a=Pico.video.addr; + unsigned char *vr=(unsigned char *) Pico.vram; + unsigned char high = (unsigned char) (data >> 8); + unsigned char inc=Pico.video.reg[0xf]; + + len=GetDmaLength(); + //dprintf("DmaFill len %i inc %i [%i|%i]", len, inc, Pico.m.scanline, SekCyclesDone()); + + // from Charles MacDonald's genvdp.txt: + // Write lower byte to address specified + vr[a] = (unsigned char) data; + a=(u16)(a+inc); + + if(!inc) len=1; + + for(;len;len--) { + // Write upper byte to adjacent address + // (here we are byteswapped, so address is already 'adjacent') + vr[a] = high; + + // Increment address register + a=(u16)(a+inc); + } + // remember addr + Pico.video.addr=a; + // update length + Pico.video.reg[0x13] = Pico.video.reg[0x14] = 0; // Dino Dini's Soccer (E) (by Haze) + + rendstatus|=0x10; +} + +static void CommandDma() +{ + struct PicoVideo *pvid=&Pico.video; + int len=0,method=0; + + if ((pvid->reg[1]&0x10)==0) return; // DMA not enabled + + len=GetDmaLength(); + + method=pvid->reg[0x17]>>6; + if (method< 2) DmaSlow(len); // 68000 to VDP + if (method==3) DmaCopy(len); // VRAM Copy +} + +static void CommandChange() +{ + struct PicoVideo *pvid=&Pico.video; + unsigned int cmd=0,addr=0; + + cmd=pvid->command; + + // Get type of transfer 0xc0000030 (v/c/vsram read/write) + pvid->type=(unsigned char)(((cmd>>2)&0xc)|(cmd>>30)); + + // Get address 0x3fff0003 + addr =(cmd>>16)&0x3fff; + addr|=(cmd<<14)&0xc000; + pvid->addr=(unsigned short)addr; + //dprintf("addr set: %04x", addr); + + // Check for dma: + if (cmd&0x80) CommandDma(); +} + +void PicoVideoWrite(unsigned int a,unsigned short d) +{ + struct PicoVideo *pvid=&Pico.video; + + a&=0x1c; + + if (a==0x00) // Data port 0 or 2 + { + if (pvid->pending) CommandChange(); + pvid->pending=0; + + // If a DMA fill has been set up, do it + if ((pvid->command&0x80) && (pvid->reg[1]&0x10) && (pvid->reg[0x17]>>6)==2) + { + DmaFill(d); + } + else + { + VideoWrite(d); + } + return; + } + + if (a==0x04) // Control (command) port 4 or 6 + { + //dprintf("vdp cw(%04x), p=%i @ %06x [%i]", d, pvid->pending, SekPc, SekCyclesDone()); + if(pvid->pending) + { + // Low word of command: + pvid->command&=0xffff0000; + pvid->command|=d; + pvid->pending=0; + CommandChange(); + } else { + if((d&0xc000)==0x8000) + { + // Register write: + int num=(d>>8)&0x1f; + //if(num==00) dprintf("hint_onoff: %i->%i [%i|%i] pend=%i @ %06x", (pvid->reg[0]&0x10)>>4, (d&0x10)>>4, Pico.m.scanline, SekCyclesDone(), (pvid->pending_ints&0x10)>>4, SekPc); + //if(num==01) dprintf("vint_onoff: %i->%i [%i|%i] pend=%i @ %06x", (pvid->reg[1]&0x20)>>5, (d&0x20)>>5, Pico.m.scanline, SekCyclesDone(), (pvid->pending_ints&0x20)>>5, SekPc); + //if(num==01) dprintf("set_blank: %i @ %06x [%i|%i]", !((d&0x40)>>6), SekPc, Pico.m.scanline, SekCyclesDone()); + //if(num==05) dprintf("spr_set: %i @ %06x [%i|%i]", (unsigned char)d, SekPc, Pico.m.scanline, SekCyclesDone()); + //if(num==10) dprintf("hint_set: %i @ %06x [%i|%i]", (unsigned char)d, SekPc, Pico.m.scanline, SekCyclesDone()); + pvid->reg[num]=(unsigned char)d; +#if !(defined(EMU_C68K) && defined(EMU_M68K)) // not debugging Cyclone + // update IRQ level (Lemmings, Wiz 'n' Liz intro, ... ) + // may break if done improperly: + // International Superstar Soccer Deluxe (crash), Street Racer (logos), Burning Force (gfx), Fatal Rewind (hang), Sesame Street Counting Cafe + if(num < 2) { +#ifdef EMU_C68K + // hack: make sure we do not touch the irq line if Cyclone is just about to take the IRQ + if (PicoCpu.irq <= (PicoCpu.srh&7)) { +#endif + int lines, pints; + lines = (pvid->reg[1] & 0x20) | (pvid->reg[0] & 0x10); + pints = (pvid->pending_ints&lines); + if(pints & 0x20) SekInterrupt(6); + else if(pints & 0x10) SekInterrupt(4); + else SekInterrupt(0); +#ifdef EMU_C68K + // adjust cycles for Cyclone so it would take the int "in time" + if(PicoCpu.irq) { + SekEndRun(24); + } + } +#endif + } + else +#endif + if(num == 5) rendstatus|=1; + else if(num == 0xc) Pico.m.dirtyPal = 2; // renderers should update their palettes if sh/hi mode is changed + pvid->type=0; // register writes clear command (else no Sega logo in Golden Axe II) + } else { + // High word of command: + pvid->command&=0x0000ffff; + pvid->command|=d<<16; + pvid->pending=1; + } + } + } +} + +unsigned int PicoVideoRead(unsigned int a) +{ + unsigned int d=0; + + a&=0x1c; + + if (a==0x00) // data port + { + d=VideoRead(); + goto end; + } + + if (a==0x04) // control port + { + //dprintf("sr_read @ %06x [%i|%i]", SekPc, Pico.m.scanline, SekCyclesDone()); + d=Pico.video.status; + if(PicoOpt&0x10) d|=0x0020; // sprite collision (Shadow of the Beast) + if(Pico.m.rotate++&8) d|=0x0100; else d|=0x0200; // Toggle fifo full empty (who uses that stuff?) + if(!(Pico.video.reg[1]&0x40)) d|=0x0008; // set V-Blank if display is disabled + if(SekCyclesLeft < 84+4) d|=0x0004; // H-Blank (Sonic3 vs) + + Pico.video.pending=0; // ctrl port reads clear write-pending flag (Charles MacDonald) + + goto end; + } + + // H-counter info (based on Generator): + // frame: + // | <- hblank? -> | + // start <416> hint <36> hdisplay <38> end // CPU cycles + // |---------...---------|------------|-------------| + // 0 B6 E4 FF // 40 cells + // 0 93 E8 FF // 32 cells + + // Gens (?) v-render + // start hint hdisplay <404> | + // |---------------------|--------------------------| + // E4 (hc[0x43]==0) 07 B1 // 40 + // E8 (hc[0x45]==0) 05 91 // 32 + + // check: Sonic 3D Blast bonus, Cannon Fodder, Chase HQ II, 3 Ninjas kick back, Road Rash 3, Skitchin', Wheel of Fortune + if ((a&0x1c)==0x08) + { + unsigned int hc; + + if(Pico.m.scanline != -1) { + int lineCycles=(488-SekCyclesLeft)&0x1ff; + d=Pico.m.scanline; // V-Counter + + if(Pico.video.reg[12]&1) + hc=hcounts_40[lineCycles]; + else hc=hcounts_32[lineCycles]; + + if(lineCycles > 488-12) d++; // Wheel of Fortune + } else { + // get approximate V-Counter + d=vcounts[SekCyclesDone()>>8]; + hc = Pico.m.rotate&0xff; + } + + if(Pico.m.pal) { + if(d >= 0x103) d-=56; // based on Gens + } else { + if(d >= 0xEB) d-=6; + } + + if((Pico.video.reg[12]&6) == 6) { + // interlace mode 2 (Combat Cars (UE) [!]) + d <<= 1; + if (d&0xf00) d|= 1; + } + + //dprintf("hv: %02x %02x (%i) @ %06x", hc, d, SekCyclesDone(), SekPc); + d&=0xff; d<<=8; + d|=hc; + goto end; + } + +end: + + return d; +} diff --git a/Pico/_cyclone_debug.c b/Pico/_cyclone_debug.c new file mode 100644 index 00000000..b47fccdd --- /dev/null +++ b/Pico/_cyclone_debug.c @@ -0,0 +1,130 @@ +#include "PicoInt.h" + +typedef unsigned char u8; + +static unsigned int pppc, ops=0; +extern unsigned int lastread_a, lastread_d[16], lastwrite_cyc_d[16], lastwrite_mus_d[16]; +extern int lrp_cyc, lrp_mus, lwp_cyc, lwp_mus; +unsigned int old_regs[16], old_sr, ppop; + +//static +void dumpPCandExit() +{ + char buff[128]; + int i; + + m68k_disassemble(buff, pppc, M68K_CPU_TYPE_68000); + dprintf("PC: %06x: %04x: %s", pppc, ppop, buff); + for(i=0; i < 8; i++) + dprintf("d%i=%08x, a%i=%08x | d%i=%08x, a%i=%08x", i, PicoCpu.d[i], i, PicoCpu.a[i], i, old_regs[i], i, old_regs[i+8]); + dprintf("SR: %04x | %04x (??s? 0iii 000x nzvc)", CycloneGetSr(&PicoCpu), old_sr); + dprintf("last_read: %08x @ %06x", lastread_d[--lrp_cyc&15], lastread_a); + dprintf("ops done: %i", ops); + exit(1); +} + +int CM_compareRun(int cyc) +{ + char *str; + int cyc_done=0, cyc_cyclone, cyc_musashi, err=0; + unsigned int i, mu_sr; + + lrp_cyc = lrp_mus = 0; + + while(cyc > cyc_done) { + pppc = SekPc; + ppop = m68k_read_disassembler_16(pppc); + memcpy(old_regs, PicoCpu.d, 4*16); + old_sr = CycloneGetSr(&PicoCpu); + + PicoCpu.cycles=1; + CycloneRun(&PicoCpu); + cyc_cyclone=1-PicoCpu.cycles; + cyc_musashi=m68k_execute(1); + + if(cyc_cyclone != cyc_musashi) { + dprintf("cycles: %i vs %i", cyc_cyclone, cyc_musashi); + err=1; + } + + if(lrp_cyc != lrp_mus) { + dprintf("lrp: %i vs %i", lrp_cyc&15, lrp_mus&15); + err=1; + } + + if(lwp_cyc != lwp_mus) { + dprintf("lwp: %i vs %i", lwp_cyc&15, lwp_mus&15); + err=1; + } + + for(i=0; i < 16; i++) { + if(lastwrite_cyc_d[i] != lastwrite_mus_d[i]) { + dprintf("lastwrite: [%i]= %08x vs %08x", i, lastwrite_cyc_d[i], lastwrite_mus_d[i]); + err=1; + break; + } + } + + // compare PC + if( SekPc != (m68ki_cpu.pc&0xffffff) ) { + dprintf("PC: %06x vs %06x", SekPc, m68ki_cpu.pc&0xffffff); + err=1; + } + +#if 0 + if( SekPc > Pico.romsize || SekPc < 0x200 ) { + dprintf("PC out of bounds: %06x", SekPc); + err=1; + } +#endif + + // compare regs + for(i=0; i < 16; i++) { + if(PicoCpu.d[i] != m68ki_cpu.dar[i]) { + str = (i < 8) ? "d" : "a"; + dprintf("reg: %s%i: %08x vs %08x", str, i&7, PicoCpu.d[i], m68ki_cpu.dar[i]); + err=1; + break; + } + } + + // SR + if((CycloneGetSr(&PicoCpu)) != (mu_sr = m68k_get_reg(NULL, M68K_REG_SR))) { + dprintf("SR: %04x vs %04x (??s? 0iii 000x nzvc)", CycloneGetSr(&PicoCpu), mu_sr); + err=1; + } + + // IRQl + if(PicoCpu.irq != (m68ki_cpu.int_level>>8)) { + dprintf("IRQ: %i vs %i", PicoCpu.irq, (m68ki_cpu.int_level>>8)); + err=1; + } + + // OSP/USP + if(PicoCpu.osp != m68ki_cpu.sp[((mu_sr>>11)&4)^4]) { + dprintf("OSP: %06x vs %06x", PicoCpu.osp, m68ki_cpu.sp[0]); + err=1; + } + + // stopped + if((PicoCpu.stopped && !m68ki_cpu.stopped) || (!PicoCpu.stopped && m68ki_cpu.stopped)) { + dprintf("stopped: %i vs %i", PicoCpu.stopped, m68ki_cpu.stopped); + err=1; + } + + if(err) dumpPCandExit(); + +#if 0 + m68k_set_reg(M68K_REG_SR, ((mu_sr-1)&~0x2000)|(mu_sr&0x2000)); // broken + CycloneSetSr(&PicoCpu, ((mu_sr-1)&~0x2000)|(mu_sr&0x2000)); + PicoCpu.stopped = m68ki_cpu.stopped = 0; + if(SekPc > 0x400 && (PicoCpu.a[7] < 0xff0000 || PicoCpu.a[7] > 0xffffff)) + PicoCpu.a[7] = m68ki_cpu.dar[15] = 0xff8000; +#endif + + cyc_done += cyc_cyclone; + ops++; + } + + return cyc_done; +} diff --git a/Pico/cd/LC89510.c b/Pico/cd/LC89510.c new file mode 100644 index 00000000..2b6079de --- /dev/null +++ b/Pico/cd/LC89510.c @@ -0,0 +1,658 @@ +#if 0 +#include +#include +#include "misc.h" +#include "lc89510.h" +#include "cd_aspi.h" +#include "Star_68k.h" +#include "mem_S68k.h" +#include "pcm.h" +#endif + +#include "../PicoInt.h" + +#define cdprintf printf +//#define cdprintf(x...) + + +#define CDC_DMA_SPEED 256 + +int CDC_Decode_Reg_Read; +static int Status_CDC; // internal status + + +static void CDD_Reset(void) +{ + // Reseting CDD + + memset(Pico_mcd->s68k_regs+0x34, 0, 2*2); // CDD.Fader, CDD.Control + Pico_mcd->cdd.Status = 0; + Pico_mcd->cdd.Minute = 0; + Pico_mcd->cdd.Seconde = 0; + Pico_mcd->cdd.Frame = 0; + Pico_mcd->cdd.Ext = 0; + + // clear receive status and transfer command + memset(Pico_mcd->s68k_regs+0x38, 0, 20); + Pico_mcd->s68k_regs[0x38+9] = 0xF; // Default checksum +} + + +static void CDC_Reset(void) +{ + // Reseting CDC + + memset(Pico_mcd->cdc.Buffer, 0, (16 * 1024 * 2) + 2352); + + CDC_Update_Header(); + + Pico_mcd->cdc.COMIN = 0; + Pico_mcd->cdc.IFSTAT = 0xFF; + Pico_mcd->cdc.DAC.N = 0; + Pico_mcd->cdc.DBC.N = 0; + Pico_mcd->cdc.HEAD.N = 0x01000000; + Pico_mcd->cdc.PT.N = 0; + Pico_mcd->cdc.WA.N = 2352 * 2; + Pico_mcd->cdc.STAT.N = 0x00000080; + Pico_mcd->cdc.SBOUT = 0; + Pico_mcd->cdc.IFCTRL = 0; + Pico_mcd->cdc.CTRL.N = 0; + + CDC_Decode_Reg_Read = 0; + Status_CDC = 0; +} + + +void LC89510_Reset(void) +{ + CDD_Reset(); + CDC_Reset(); + + Pico_mcd->cdc.Host_Data = 0; + Pico_mcd->cdc.DMA_Adr = 0; + Pico_mcd->cdc.Stop_Watch = 0; +} + +#if 0 // TODO +void Update_CDC_TRansfer(void) +{ + unsigned int i, dep, lenght, add_dest; + unsigned char *dest; + + if ((Status_CDC & 0x08) == 0) return; + + switch(Pico_mcd->s68k_regs[4] & 7) + { + case 0x0200: // MAIN CPU + case 0x0300: // SUB CPU + Pico_mcd->s68k_regs[4] |= 0x40; // Data ready in host port + return; + + case 0x0400: // PCM RAM + dest = (unsigned char *) Ram_PCM; + dep = ((Pico_mcd->cdc.DMA_Adr & 0x03FF) << 2) + PCM_Chip.Bank; + add_dest = 2; + break; + + case 0x0500: // PRG RAM + dest = (unsigned char *) Ram_Prg; + dep = (Pico_mcd->cdc.DMA_Adr & 0xFFFF) << 3; + add_dest = 2; +// cdprintf("DMA transfer PRG RAM : adr = %.8X ", dep); + break; + + case 0x0700: // WORD RAM + if (Ram_Word_State >= 2) + { + dest = (unsigned char *) Ram_Word_1M; + add_dest = 2; + if (Ram_Word_State & 1) dep = ((Pico_mcd->cdc.DMA_Adr & 0x3FFF) << 3); + else dep = ((Pico_mcd->cdc.DMA_Adr & 0x3FFF) << 3) + 0x20000; + } + else + { + dest = (unsigned char *) Ram_Word_2M; + dep = ((Pico_mcd->cdc.DMA_Adr & 0x7FFF) << 3); + add_dest = 2; + } + break; + + default: + return; + } + + if (Pico_mcd->cdc.DBC.N <= (CDC_DMA_SPEED * 2)) + { + lenght = (Pico_mcd->cdc.DBC.N + 1) >> 1; + Status_CDC &= ~0x08; // Last transfer + Pico_mcd->s68k_regs[4] |= 0x80; // End data transfer + Pico_mcd->s68k_regs[4] &= ~0x40; // no more data ready + Pico_mcd->cdc.IFSTAT |= 0x08; // No more data transfer in progress + + if (Pico_mcd->cdc.IFCTRL & 0x40) // DTEIEN = Data Trasnfer End Interrupt Enable ? + { + Pico_mcd->cdc.IFSTAT &= ~0x40; + + if (Int_Mask_S68K & 0x20) sub68k_interrupt(5, -1); + + cdprintf("CDC - DTE interrupt\n"); + } + } + else lenght = CDC_DMA_SPEED; + +// cdprintf("DMA lenght = %.4X\n", lenght); + + + if ((Pico_mcd->s68k_regs[4] & 7) == 4) // PCM DMA + { + __asm + { + mov ecx, lenght + mov edi, dest + lea esi, Pico_mcd->cdc.Buffer + add edi, dep + add esi, Pico_mcd->cdc.DAC.N + mov ebx, add_dest + + Loop_DMA_PCM: + mov ax, [esi] + add esi, 2 + mov [edi], ax + add edi, ebx + dec ecx + jnz Loop_DMA_PCM + } + + lenght <<= 1; + Pico_mcd->cdc.DMA_Adr += lenght >> 2; + } + else // OTHER DMA + { + __asm + { + mov ecx, lenght + mov edi, dest + lea esi, Pico_mcd->cdc.Buffer + add edi, dep + add esi, Pico_mcd->cdc.DAC.N + mov ebx, add_dest + + Loop_DMA: + mov ax, [esi] + add esi, 2 + rol ax, 8 + mov [edi], ax + add edi, ebx + dec ecx + jnz Loop_DMA + } + + lenght <<= 1; + Pico_mcd->cdc.DMA_Adr += lenght >> 3; + } + + Pico_mcd->cdc.DAC.N = (Pico_mcd->cdc.DAC.N + lenght) & 0xFFFF; + if (Status_CDC & 0x08) Pico_mcd->cdc.DBC.N -= lenght; + else Pico_mcd->cdc.DBC.N = 0; +} +#endif + + +unsigned short Read_CDC_Host(int is_sub) +{ + int addr; + + if (!(Status_CDC & 0x08)) + { + // Transfer data disabled + return 0; + } + + if ((is_sub && (Pico_mcd->s68k_regs[4] & 7) != 3) || + (!is_sub && (Pico_mcd->s68k_regs[4] & 7) != 2)) + { + // Wrong setting + return 0; + } + + Pico_mcd->cdc.DBC.N -= 2; + + if (Pico_mcd->cdc.DBC.N <= 0) + { + Pico_mcd->cdc.DBC.N = 0; + Status_CDC &= ~0x08; // Last transfer + Pico_mcd->s68k_regs[4] |= 0x80; // End data transfer + Pico_mcd->s68k_regs[4] &= ~0x40; // no more data ready + Pico_mcd->cdc.IFSTAT |= 0x08; // No more data transfer in progress + + if (Pico_mcd->cdc.IFCTRL & 0x40) // DTEIEN = Data Transfer End Interrupt Enable ? + { + Pico_mcd->cdc.IFSTAT &= ~0x40; + + if (Pico_mcd->s68k_regs[0x33]&(1<<5)) { + dprintf("m68k: s68k irq 5"); + SekInterruptS68k(5); + } + + cdprintf("CDC - DTE interrupt\n"); + } + } + + addr = Pico_mcd->cdc.DAC.N; + Pico_mcd->cdc.DAC.N += 2; + return (Pico_mcd->cdc.Buffer[addr]<<8) | Pico_mcd->cdc.Buffer[addr+1]; + +#if 0 + __asm + { + mov esi, Pico_mcd->cdc.DAC.N + lea ebx, Pico_mcd->cdc.Buffer +// and esi, 0x3FFF + mov ax, [ebx + esi] + add esi, 2 + rol ax, 8 + mov Pico_mcd->cdc.DAC.N, esi + mov val, ax + } +#endif +} + + +void CDC_Update_Header(void) +{ + if (Pico_mcd->cdc.CTRL.B.B1 & 0x01) // Sub-Header wanted ? + { + Pico_mcd->cdc.HEAD.B.B0 = 0; + Pico_mcd->cdc.HEAD.B.B1 = 0; + Pico_mcd->cdc.HEAD.B.B2 = 0; + Pico_mcd->cdc.HEAD.B.B3 = 0; + } + else + { + _msf MSF; + + LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF); + + Pico_mcd->cdc.HEAD.B.B0 = INT_TO_BCDB(MSF.M); + Pico_mcd->cdc.HEAD.B.B1 = INT_TO_BCDB(MSF.S); + Pico_mcd->cdc.HEAD.B.B2 = INT_TO_BCDB(MSF.F); + Pico_mcd->cdc.HEAD.B.B3 = 0x01; + } +} + + +unsigned char CDC_Read_Reg(void) +{ + unsigned char ret; + + cdprintf("CDC read reg %.2d = ", Pico_mcd->s68k_regs[5] & 0xF); + + switch(Pico_mcd->s68k_regs[5] & 0xF) + { + case 0x0: // COMIN + cdprintf("%.2X\n", Pico_mcd->cdc.COMIN); + + Pico_mcd->s68k_regs[5] = 0x1; + return Pico_mcd->cdc.COMIN; + + case 0x1: // IFSTAT + cdprintf("%.2X\n", Pico_mcd->cdc.IFSTAT); + + CDC_Decode_Reg_Read |= (1 << 1); // Reg 1 (decoding) + Pico_mcd->s68k_regs[5] = 0x2; + return Pico_mcd->cdc.IFSTAT; + + case 0x2: // DBCL + cdprintf("%.2X\n", Pico_mcd->cdc.DBC.B.L); + + Pico_mcd->s68k_regs[5] = 0x3; + return Pico_mcd->cdc.DBC.B.L; + + case 0x3: // DBCH + cdprintf("%.2X\n", Pico_mcd->cdc.DBC.B.H); + + Pico_mcd->s68k_regs[5] = 0x4; + return Pico_mcd->cdc.DBC.B.H; + + case 0x4: // HEAD0 + cdprintf("%.2X\n", Pico_mcd->cdc.HEAD.B.B0); + + CDC_Decode_Reg_Read |= (1 << 4); // Reg 4 (decoding) + Pico_mcd->s68k_regs[5] = 0x5; + return Pico_mcd->cdc.HEAD.B.B0; + + case 0x5: // HEAD1 + cdprintf("%.2X\n", Pico_mcd->cdc.HEAD.B.B1); + + CDC_Decode_Reg_Read |= (1 << 5); // Reg 5 (decoding) + Pico_mcd->s68k_regs[5] = 0x6; + return Pico_mcd->cdc.HEAD.B.B1; + + case 0x6: // HEAD2 + cdprintf("%.2X\n", Pico_mcd->cdc.HEAD.B.B2); + + CDC_Decode_Reg_Read |= (1 << 6); // Reg 6 (decoding) + Pico_mcd->s68k_regs[5] = 0x7; + return Pico_mcd->cdc.HEAD.B.B2; + + case 0x7: // HEAD3 + cdprintf("%.2X\n", Pico_mcd->cdc.HEAD.B.B3); + + CDC_Decode_Reg_Read |= (1 << 7); // Reg 7 (decoding) + Pico_mcd->s68k_regs[5] = 0x8; + return Pico_mcd->cdc.HEAD.B.B3; + + case 0x8: // PTL + cdprintf("%.2X\n", Pico_mcd->cdc.PT.B.L); + + CDC_Decode_Reg_Read |= (1 << 8); // Reg 8 (decoding) + Pico_mcd->s68k_regs[5] = 0x9; + return Pico_mcd->cdc.PT.B.L; + + case 0x9: // PTH + cdprintf("%.2X\n", Pico_mcd->cdc.PT.B.H); + + CDC_Decode_Reg_Read |= (1 << 9); // Reg 9 (decoding) + Pico_mcd->s68k_regs[5] = 0xA; + return Pico_mcd->cdc.PT.B.H; + + case 0xA: // WAL + cdprintf("%.2X\n", Pico_mcd->cdc.WA.B.L); + + Pico_mcd->s68k_regs[5] = 0xB; + return Pico_mcd->cdc.WA.B.L; + + case 0xB: // WAH + cdprintf("%.2X\n", Pico_mcd->cdc.WA.B.H); + + Pico_mcd->s68k_regs[5] = 0xC; + return Pico_mcd->cdc.WA.B.H; + + case 0xC: // STAT0 + cdprintf("%.2X\n", Pico_mcd->cdc.STAT.B.B0); + + CDC_Decode_Reg_Read |= (1 << 12); // Reg 12 (decoding) + Pico_mcd->s68k_regs[5] = 0xD; + return Pico_mcd->cdc.STAT.B.B0; + + case 0xD: // STAT1 + cdprintf("%.2X\n", Pico_mcd->cdc.STAT.B.B1); + + CDC_Decode_Reg_Read |= (1 << 13); // Reg 13 (decoding) + Pico_mcd->s68k_regs[5] = 0xE; + return Pico_mcd->cdc.STAT.B.B1; + + case 0xE: // STAT2 + cdprintf("%.2X\n", Pico_mcd->cdc.STAT.B.B2); + + CDC_Decode_Reg_Read |= (1 << 14); // Reg 14 (decoding) + Pico_mcd->s68k_regs[5] = 0xF; + return Pico_mcd->cdc.STAT.B.B2; + + case 0xF: // STAT3 + cdprintf("%.2X\n", Pico_mcd->cdc.STAT.B.B3); + + ret = Pico_mcd->cdc.STAT.B.B3; + Pico_mcd->cdc.IFSTAT |= 0x20; // decoding interrupt flag cleared + if ((Pico_mcd->cdc.CTRL.B.B0 & 0x80) && (Pico_mcd->cdc.IFCTRL & 0x20)) + { + if ((CDC_Decode_Reg_Read & 0x73F2) == 0x73F2) + Pico_mcd->cdc.STAT.B.B3 = 0x80; + } + return ret; + } + + return 0; +} + + +void CDC_Write_Reg(unsigned char Data) +{ + cdprintf("CDC write reg%d = %.2X\n", Pico_mcd->s68k_regs[5] & 0xF, Data); + + switch (Pico_mcd->s68k_regs[5] & 0xF) + { + case 0x0: // SBOUT + Pico_mcd->s68k_regs[5] = 0x1; + Pico_mcd->cdc.SBOUT = Data; + + break; + + case 0x1: // IFCTRL + Pico_mcd->s68k_regs[5] = 0x2; + Pico_mcd->cdc.IFCTRL = Data; + + if ((Pico_mcd->cdc.IFCTRL & 0x02) == 0) // Stop data transfer + { + Pico_mcd->cdc.DBC.N = 0; + Status_CDC &= ~0x08; + Pico_mcd->cdc.IFSTAT |= 0x08; // No more data transfer in progress + } + break; + + case 0x2: // DBCL + Pico_mcd->s68k_regs[5] = 0x3; + Pico_mcd->cdc.DBC.B.L = Data; + + break; + + case 0x3: // DBCH + Pico_mcd->s68k_regs[5] = 0x4; + Pico_mcd->cdc.DBC.B.H = Data; + + break; + + case 0x4: // DACL + Pico_mcd->s68k_regs[5] = 0x5; + Pico_mcd->cdc.DAC.B.L = Data; + + break; + + case 0x5: // DACH + Pico_mcd->s68k_regs[5] = 0x6; + Pico_mcd->cdc.DAC.B.H = Data; + + break; + + case 0x6: // DTTRG + if (Pico_mcd->cdc.IFCTRL & 0x02) // Data transfer enable ? + { + Pico_mcd->cdc.IFSTAT &= ~0x08; // Data transfer in progress + Status_CDC |= 0x08; // Data transfer in progress + Pico_mcd->s68k_regs[4] &= 0x7F; // A data transfer start + + cdprintf("\n************** Starting Data Transfer ***********\n"); + cdprintf("RS0 = %.4X DAC = %.4X DBC = %.4X DMA adr = %.4X\n\n", Pico_mcd->s68k_regs[4]<<8, + Pico_mcd->cdc.DAC.N, Pico_mcd->cdc.DBC.N, Pico_mcd->cdc.DMA_Adr); + } + break; + + case 0x7: // DTACK + Pico_mcd->cdc.IFSTAT |= 0x40; // end data transfer interrupt flag cleared + break; + + case 0x8: // WAL + Pico_mcd->s68k_regs[5] = 0x9; + Pico_mcd->cdc.WA.B.L = Data; + + break; + + case 0x9: // WAH + Pico_mcd->s68k_regs[5] = 0xA; + Pico_mcd->cdc.WA.B.H = Data; + + break; + + case 0xA: // CTRL0 + Pico_mcd->s68k_regs[5] = 0xB; + Pico_mcd->cdc.CTRL.B.B0 = Data; + + break; + + case 0xB: // CTRL1 + Pico_mcd->s68k_regs[5] = 0xC; + Pico_mcd->cdc.CTRL.B.B1 = Data; + + break; + + case 0xC: // PTL + Pico_mcd->s68k_regs[5] = 0xD; + Pico_mcd->cdc.PT.B.L = Data; + + break; + + case 0xD: // PTH + Pico_mcd->s68k_regs[5] = 0xE; + Pico_mcd->cdc.PT.B.H = Data; + + break; + + case 0xE: // CTRL2 + Pico_mcd->cdc.CTRL.B.B2 = Data; + break; + + case 0xF: // RESET + CDC_Reset(); + break; + } +} + + +static int bswapwrite(int a, unsigned short d) +{ + *(unsigned short *)(Pico_mcd->s68k_regs + a) = (d>>8)|(d<<8); + return d + (d >> 8); +} + +void CDD_Export_Status(void) +{ + unsigned int csum; + + csum = bswapwrite( 0x38+0, Pico_mcd->cdd.Status); + csum += bswapwrite( 0x38+2, Pico_mcd->cdd.Minute); + csum += bswapwrite( 0x38+4, Pico_mcd->cdd.Seconde); + csum += bswapwrite( 0x38+6, Pico_mcd->cdd.Frame); + Pico_mcd->s68k_regs[0x38+8] = Pico_mcd->cdd.Ext; + csum += Pico_mcd->cdd.Ext; + Pico_mcd->s68k_regs[0x38+9] = ~csum & 0xf; + + Pico_mcd->s68k_regs[0x36] &= 3; // CDD.Control + + if (Pico_mcd->s68k_regs[0x33] & (1<<4)) + { + dprintf("cdd export irq 4"); + SekInterruptS68k(4); + } + + cdprintf("CDD exported status\n"); + cdprintf("Status =%.4X, Minute=%.4X, Second=%.4X, Frame=%.4X Checksum=%.4X\n", + (Pico_mcd->s68k_regs[0x38+0] << 8) | Pico_mcd->s68k_regs[0x38+1], + (Pico_mcd->s68k_regs[0x38+2] << 8) | Pico_mcd->s68k_regs[0x38+3], + (Pico_mcd->s68k_regs[0x38+4] << 8) | Pico_mcd->s68k_regs[0x38+5], + (Pico_mcd->s68k_regs[0x38+6] << 8) | Pico_mcd->s68k_regs[0x38+7], + (Pico_mcd->s68k_regs[0x38+8] << 8) | Pico_mcd->s68k_regs[0x38+9]); +} + + +void CDD_Import_Command(void) +{ + cdprintf("CDD importing command\n"); + cdprintf("Command=%.4X, Minute=%.4X, Second=%.4X, Frame=%.4X Checksum=%.4X\n", + (Pico_mcd->s68k_regs[0x38+10+0] << 8) | Pico_mcd->s68k_regs[0x38+10+1], + (Pico_mcd->s68k_regs[0x38+10+2] << 8) | Pico_mcd->s68k_regs[0x38+10+3], + (Pico_mcd->s68k_regs[0x38+10+4] << 8) | Pico_mcd->s68k_regs[0x38+10+5], + (Pico_mcd->s68k_regs[0x38+10+6] << 8) | Pico_mcd->s68k_regs[0x38+10+7], + (Pico_mcd->s68k_regs[0x38+10+8] << 8) | Pico_mcd->s68k_regs[0x38+10+9]); + + switch (Pico_mcd->s68k_regs[0x38+10+0]) + { + case 0x0: // STATUS (?) + Get_Status_CDD_c0(); + break; + + case 0x1: // STOP ALL (?) + Stop_CDD_c1(); + break; + + case 0x2: // GET TOC INFORMATIONS + switch(Pico_mcd->s68k_regs[0x38+10+3]) + { + case 0x0: // get current position (MSF format) + Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00); + Get_Pos_CDD_c20(); + break; + + case 0x1: // get elapsed time of current track played/scanned (relative MSF format) + Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 1; + Get_Track_Pos_CDD_c21(); + break; + + case 0x2: // get current track in RS2-RS3 + Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 2; + Get_Current_Track_CDD_c22(); + break; + + case 0x3: // get total lenght (MSF format) + Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 3; + Get_Total_Lenght_CDD_c23(); + break; + + case 0x4: // first & last track number + Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 4; + Get_First_Last_Track_CDD_c24(); + break; + + case 0x5: // get track addresse (MSF format) + Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 5; + Get_Track_Adr_CDD_c25(); + break; + + default : // invalid, then we return status + Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 0xF; + Get_Status_CDD_c0(); + break; + } + break; + + case 0x3: // READ + Play_CDD_c3(); + break; + + case 0x4: // SEEK + Seek_CDD_c4(); + break; + + case 0x6: // PAUSE/STOP + Pause_CDD_c6(); + break; + + case 0x7: // RESUME + Resume_CDD_c7(); + break; + + case 0x8: // FAST FOWARD + Fast_Foward_CDD_c8(); + break; + + case 0x9: // FAST REWIND + Fast_Rewind_CDD_c9(); + break; + + case 0xA: // RECOVER INITIAL STATE (?) + CDD_cA(); + break; + + case 0xC: // CLOSE TRAY + Close_Tray_CDD_cC(); + break; + + case 0xD: // OPEN TRAY + Open_Tray_CDD_cD(); + break; + + default: // UNKNOWN + CDD_Def(); + break; + } +} + diff --git a/Pico/cd/LC89510.h b/Pico/cd/LC89510.h new file mode 100644 index 00000000..7a0fa5e2 --- /dev/null +++ b/Pico/cd/LC89510.h @@ -0,0 +1,130 @@ +#ifndef _LC89510_H +#define _LC89510_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + unsigned int Host_Data; + unsigned int DMA_Adr; + unsigned int Stop_Watch; + unsigned int COMIN; + unsigned int IFSTAT; + union + { + struct + { + unsigned char L; + unsigned char H; + unsigned short unused; + } B; + int N; + } DBC; + union + { + struct + { + unsigned char L; + unsigned char H; + unsigned short unused; + } B; + int N; + } DAC; + union + { + struct + { + unsigned char B0; + unsigned char B1; + unsigned char B2; + unsigned char B3; + } B; + unsigned int N; + } HEAD; + union + { + struct + { + unsigned char L; + unsigned char H; + unsigned short unused; + } B; + int N; + } PT; + union + { + struct + { + unsigned char L; + unsigned char H; + unsigned short unused; + } B; + int N; + } WA; + union + { + struct + { + unsigned char B0; + unsigned char B1; + unsigned char B2; + unsigned char B3; + } B; + unsigned int N; + } STAT; + unsigned int SBOUT; + unsigned int IFCTRL; + union + { + struct + { + unsigned char B0; + unsigned char B1; + unsigned char B2; + unsigned char B3; + } B; + unsigned int N; + } CTRL; + unsigned char Buffer[(32 * 1024 * 2) + 2352]; +} CDC; + +typedef struct +{ +// unsigned short Fader; // 34 +// unsigned short Control; // 36 +// unsigned short Cur_Comm;// unused + + // "Receive status" + unsigned short Status; + unsigned short Minute; + unsigned short Seconde; + unsigned short Frame; + unsigned char Ext; +} CDD; + + +extern int CDC_Decode_Reg_Read; + + +void LC89510_Reset(void); +unsigned short Read_CDC_Host(int is_sub); +void Update_CDC_TRansfer(void); +void CDC_Update_Header(void); + +unsigned char CDC_Read_Reg(void); +void CDC_Write_Reg(unsigned char Data); + +void CDD_Export_Status(void); +void CDD_Import_Command(void); + +unsigned char SCD_Read_Byte(unsigned int Adr); +unsigned short SCD_Read_Word(unsigned int Adr); + +#ifdef __cplusplus +}; +#endif + +#endif + diff --git a/Pico/cd/Memory.c b/Pico/cd/Memory.c new file mode 100644 index 00000000..b8322d8a --- /dev/null +++ b/Pico/cd/Memory.c @@ -0,0 +1,788 @@ +// This is part of Pico Library + +// (c) Copyright 2004 Dave, All rights reserved. +// (c) Copyright 2006 notaz, All rights reserved. +// Free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + +// A68K no longer supported here + +//#define __debug_io + +#include "../PicoInt.h" + +#include "../sound/sound.h" +#include "../sound/ym2612.h" +#include "../sound/sn76496.h" + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; + +//#define __debug_io +//#define __debug_io2 + +// ----------------------------------------------------------------- + +extern m68ki_cpu_core m68ki_cpu; + +extern int counter75hz; + + +static u32 m68k_reg_read16(u32 a, int realsize) +{ + u32 d=0; + a &= 0x3e; + dprintf("m68k_regs r%2i: [%02x] @%06x", realsize&~1, a+(realsize&1), SekPc); + + switch (a) { + case 2: + d = (Pico_mcd->m68k_regs[a]<<8) | Pico_mcd->m68k_regs[a+1] | 1; // for now 2M to m68k + goto end; + case 8: + dprintf("m68k host data read"); + d = Read_CDC_Host(0); + goto end; + case 0xC: + dprintf("m68k stopwatch read"); + break; + } + + if (a < 0xE) { + d = (Pico_mcd->m68k_regs[a]<<8) | Pico_mcd->m68k_regs[a+1]; + goto end; + } + + if (a < 0x30) { + // comm flag/cmd/status (0xE-0x2F) + d = (Pico_mcd->s68k_regs[a]<<8) | Pico_mcd->s68k_regs[a+1]; + goto end; + } + + dprintf("m68k_regs invalid read @ %02x", a); + +end: + + dprintf("ret = %04x", d); + return d; +} + +static void m68k_reg_write8(u32 a, u32 d, int realsize) +{ + a &= 0x3f; + dprintf("m68k_regs w%2i: [%02x] %02x @%06x", realsize, a, d, SekPc); + + switch (a) { + case 0: + if ((d&1) && (Pico_mcd->s68k_regs[0x33]&(1<<2))) { dprintf("m68k: s68k irq 2"); SekInterruptS68k(2); } + break; + case 1: + if (!(d&1)) PicoMCD |= 2; // reset pending, needed to be sure we fetch the right vectors on reset + if ( (Pico_mcd->m68k_regs[1]&1) != (d&1)) dprintf("m68k: s68k reset %i", !(d&1)); + if ( (Pico_mcd->m68k_regs[1]&2) != (d&2)) dprintf("m68k: s68k brq %i", (d&2)>>1); + if (/*!(Pico_mcd->m68k_regs[1]&1) &&*/ (PicoMCD&2) && (d&3)==1) { + SekResetS68k(); // S68k comes out of RESET or BRQ state + PicoMCD&=~2; + dprintf("m68k: resetting s68k"); + } + break; + case 3: + if ((Pico_mcd->m68k_regs[3]>>6) != ((d>>6)&3)) + dprintf("m68k: prg bank: %i -> %i", (Pico_mcd->m68k_regs[a]>>6), ((d>>6)&3)); + if ((Pico_mcd->m68k_regs[3]&4) != (d&4)) dprintf("m68k: ram mode %i mbit", (d&4) ? 1 : 2); + if ((Pico_mcd->m68k_regs[3]&2) != (d&2)) dprintf("m68k: %s", (d&4) ? ((d&2) ? "word swap req" : "noop?") : + ((d&2) ? "word ram to s68k" : "word ram to m68k")); + break; + case 0xe: + dprintf("m68k: comm flag: %02x", d); + + dprintf("s68k @ %06x", SekPcS68k); + + Pico_mcd->s68k_regs[0xe] = d; + break; + } + + if ((a&0xff) == 0x10) { + Pico_mcd->s68k_regs[a] = d; + } + + if (a >= 0x20 || (a >= 0xa && a <= 0xd) || a == 0x0f) + dprintf("m68k: invalid write?"); + + if (a < 0x10) + Pico_mcd->m68k_regs[a] = (u8) d; +} + + + +static u32 s68k_reg_read16(u32 a, int realsize) +{ + u32 d=0; + a &= 0x1fe; + + dprintf("s68k_regs r%2i: [%02x] @ %06x", realsize&~1, a+(realsize&1), SekPcS68k); + + switch (a) { + case 0: + d = 1; goto end; // ver = 0, not in reset state + case 6: + d = CDC_Read_Reg(); + goto end; + case 8: + dprintf("s68k host data read"); + d = Read_CDC_Host(1); + goto end; + case 0xC: + dprintf("s68k stopwatch read"); + break; + case 0x34: // fader + d = 0; // no busy bit + goto end; + } + + d = (Pico_mcd->s68k_regs[a]<<8) | Pico_mcd->s68k_regs[a+1]; + +end: + + dprintf("ret = %04x", d); + + return d; +} + +static void s68k_reg_write8(u32 a, u32 d, int realsize) +{ + a &= 0x1ff; + dprintf("s68k_regs w%2i: [%02x] %02x @ %06x", realsize, a, d, SekPcS68k); + + // TODO: review against Gens + switch (a) { + case 4: + dprintf("s68k CDC dest: %x", d&7); + Pico_mcd->s68k_regs[4] = (Pico_mcd->s68k_regs[4]&0xC0) | (d&7); // CDC mode + return; + case 5: + dprintf("s68k CDC reg addr: %x", d&0xf); + break; + case 7: + CDC_Write_Reg(d); + return; + case 0xa: + dprintf("s68k set CDC dma addr"); + break; + case 0x33: // IRQ mask + dprintf("s68k irq mask: %02x", d); + if ((d&(1<<4)) && (Pico_mcd->s68k_regs[0x37]&4) && !(Pico_mcd->s68k_regs[0x33]&(1<<4))) { + CDD_Export_Status(); + // counter75hz = 0; // ??? + } + break; + case 0x34: // fader + Pico_mcd->s68k_regs[a] = (u8) d & 0x7f; + return; + case 0x37: + if ((d&4) && !(Pico_mcd->s68k_regs[0x37]&4)) { + CDD_Export_Status(); + // counter75hz = 0; // ??? + } + break; + case 0x4b: + Pico_mcd->s68k_regs[a] = (u8) d; + CDD_Import_Command(); + return; + } + + if ((a&0x1f0) == 0x10 || a == 0x0e || (a >= 0x38 && a < 0x42)) + { + dprintf("m68k: invalid write @ %02x?", a); + return; + } + + Pico_mcd->s68k_regs[a] = (u8) d; +} + + + + + +static int PadRead(int i) +{ + int pad=0,value=0,TH; + pad=~PicoPad[i]; // Get inverse of pad MXYZ SACB RLDU + TH=Pico.ioports[i+1]&0x40; + + if(PicoOpt & 0x20) { // 6 button gamepad enabled + int phase = Pico.m.padTHPhase[i]; + + if(phase == 2 && !TH) { + value=(pad&0xc0)>>2; // ?0SA 0000 + goto end; + } else if(phase == 3 && TH) { + value=(pad&0x30)|((pad>>8)&0xf); // ?1CB MXYZ + goto end; + } else if(phase == 3 && !TH) { + value=((pad&0xc0)>>2)|0x0f; // ?0SA 1111 + goto end; + } + } + + if(TH) value=(pad&0x3f); // ?1CB RLDU + else value=((pad&0xc0)>>2)|(pad&3); // ?0SA 00DU + + end: + + // orr the bits, which are set as output + value |= Pico.ioports[i+1]&Pico.ioports[i+4]; + + return value; // will mirror later +} + +static u8 z80Read8(u32 a) +{ + if(Pico.m.z80Run&1) return 0; + + a&=0x1fff; + + if(!(PicoOpt&4)) { + // Z80 disabled, do some faking + static u8 zerosent = 0; + if(a == Pico.m.z80_lastaddr) { // probably polling something + u8 d = Pico.m.z80_fakeval; + if((d & 0xf) == 0xf && !zerosent) { + d = 0; zerosent = 1; + } else { + Pico.m.z80_fakeval++; + zerosent = 0; + } + return d; + } else { + Pico.m.z80_fakeval = 0; + } + } + + Pico.m.z80_lastaddr = (u16) a; + return Pico.zram[a]; +} + + +// for nonstandard reads +static u32 UnusualRead16(u32 a, int realsize) +{ + u32 d=0; + + dprintf("unusual r%i: %06x @%06x", realsize&~1, (a&0xfffffe)+(realsize&1), SekPc); + + + dprintf("ret = %04x", d); + return d; +} + +static u32 OtherRead16(u32 a, int realsize) +{ + u32 d=0; + + if ((a&0xff0000)==0xa00000) { + if ((a&0x4000)==0x0000) { d=z80Read8(a); d|=d<<8; goto end; } // Z80 ram (not byteswaped) + if ((a&0x6000)==0x4000) { if(PicoOpt&1) d=YM2612Read(); else d=Pico.m.rotate++&3; goto end; } // 0x4000-0x5fff, Fudge if disabled + d=0xffff; goto end; + } + if ((a&0xffffe0)==0xa10000) { // I/O ports + a=(a>>1)&0xf; + switch(a) { + case 0: d=Pico.m.hardware; break; // Hardware value (Version register) + case 1: d=PadRead(0); d|=Pico.ioports[1]&0x80; break; + case 2: d=PadRead(1); d|=Pico.ioports[2]&0x80; break; + default: d=Pico.ioports[a]; break; // IO ports can be used as RAM + } + d|=d<<8; + goto end; + } + // |=0x80 for Shadow of the Beast & Super Offroad; rotate fakes next fetched instruction for Time Killers + if (a==0xa11100) { d=((Pico.m.z80Run&1)<<8)|0x8000|Pico.m.rotate++; goto end; } + + if ((a&0xe700e0)==0xc00000) { d=PicoVideoRead(a); goto end; } + + if ((a&0xffffc0)==0xa12000) { d=m68k_reg_read16(a, realsize); goto end; } + + d = UnusualRead16(a, realsize); + +end: + return d; +} + +//extern UINT32 mz80GetRegisterValue(void *, UINT32); + +static void OtherWrite8(u32 a,u32 d,int realsize) +{ + if ((a&0xe700f9)==0xc00011||(a&0xff7ff9)==0xa07f11) { if(PicoOpt&2) SN76496Write(d); return; } // PSG Sound + if ((a&0xff4000)==0xa00000) { if(!(Pico.m.z80Run&1)) Pico.zram[a&0x1fff]=(u8)d; return; } // Z80 ram + if ((a&0xff6000)==0xa04000) { if(PicoOpt&1) emustatus|=YM2612Write(a&3, d); return; } // FM Sound + if ((a&0xffffe0)==0xa10000) { // I/O ports + a=(a>>1)&0xf; + // 6 button gamepad: if TH went from 0 to 1, gamepad changes state + if(PicoOpt&0x20) { + if(a==1) { + Pico.m.padDelay[0] = 0; + if(!(Pico.ioports[1]&0x40) && (d&0x40)) Pico.m.padTHPhase[0]++; + } + else if(a==2) { + Pico.m.padDelay[1] = 0; + if(!(Pico.ioports[2]&0x40) && (d&0x40)) Pico.m.padTHPhase[1]++; + } + } + Pico.ioports[a]=(u8)d; // IO ports can be used as RAM + return; + } + if (a==0xa11100) { + extern int z80startCycle, z80stopCycle; + //int lineCycles=(488-SekCyclesLeft)&0x1ff; + d&=1; d^=1; + if(!d) { + // hack: detect a nasty situation where Z80 was enabled and disabled in the same 68k timeslice (Golden Axe III) + if((PicoOpt&4) && Pico.m.z80Run==1) z80_run(20); + z80stopCycle = SekCyclesDone(); + //z80ExtraCycles += (lineCycles>>1)-(lineCycles>>5); // only meaningful in PicoFrameHints() + } else { + z80startCycle = SekCyclesDone(); + //if(Pico.m.scanline != -1) + //z80ExtraCycles -= (lineCycles>>1)-(lineCycles>>5)+16; + } + //dprintf("set_zrun: %i [%i|%i] zPC=%04x @%06x", d, Pico.m.scanline, SekCyclesDone(), mz80GetRegisterValue(NULL, 0), SekPc); + Pico.m.z80Run=(u8)d; return; + } + if (a==0xa11200) { if(!(d&1)) z80_reset(); return; } + + if ((a&0xff7f00)==0xa06000) // Z80 BANK register + { + Pico.m.z80_bank68k>>=1; + Pico.m.z80_bank68k|=(d&1)<<8; + Pico.m.z80_bank68k&=0x1ff; // 9 bits and filled in the new top one + return; + } + + if ((a&0xe700e0)==0xc00000) { PicoVideoWrite(a,(u16)(d|(d<<8))); return; } // Byte access gets mirrored + + if ((a&0xffffc0)==0xa12000) { m68k_reg_write8(a, d, realsize); return; } + + dprintf("strange w%i: %06x, %08x @%06x", realsize, a&0xffffff, d, SekPc); +} + +static void OtherWrite16(u32 a,u32 d) +{ + if ((a&0xe700e0)==0xc00000) { PicoVideoWrite(a,(u16)d); return; } + if ((a&0xff4000)==0xa00000) { if(!(Pico.m.z80Run&1)) Pico.zram[a&0x1fff]=(u8)(d>>8); return; } // Z80 ram (MSB only) + + if ((a&0xffffe0)==0xa10000) { // I/O ports + a=(a>>1)&0xf; + // 6 button gamepad: if TH went from 0 to 1, gamepad changes state + if(PicoOpt&0x20) { + if(a==1) { + Pico.m.padDelay[0] = 0; + if(!(Pico.ioports[1]&0x40) && (d&0x40)) Pico.m.padTHPhase[0]++; + } + else if(a==2) { + Pico.m.padDelay[1] = 0; + if(!(Pico.ioports[2]&0x40) && (d&0x40)) Pico.m.padTHPhase[1]++; + } + } + Pico.ioports[a]=(u8)d; // IO ports can be used as RAM + return; + } + if (a==0xa11100) { OtherWrite8(a, d>>8, 16); return; } + if (a==0xa11200) { if(!(d&0x100)) z80_reset(); return; } + + OtherWrite8(a, d>>8, 16); + OtherWrite8(a+1,d&0xff, 16); +} + +// ----------------------------------------------------------------- +// Read Rom and read Ram + +u8 PicoReadM68k8(u32 a) +{ + u32 d=0; + + if ((a&0xe00000)==0xe00000) { d = *(u8 *)(Pico.ram+((a^1)&0xffff)); goto end; } // Ram + + a&=0xffffff; + + if (a < 0x20000) { d = *(u8 *)(Pico_mcd->bios+(a^1)); goto end; } // bios + + // prg RAM + if ((a&0xfe0000)==0x020000) { + u8 *prg_bank = Pico_mcd->prg_ram_b[Pico_mcd->m68k_regs[3]>>6]; + d = *(prg_bank+((a^1)&0x1ffff)); + goto end; + } + + if ((a&0xff4000)==0xa00000) { d=z80Read8(a); goto end; } // Z80 Ram + + d=OtherRead16(a&~1, 8|(a&1)); if ((a&1)==0) d>>=8; + + end: + +#ifdef __debug_io + dprintf("r8 : %06x, %02x @%06x", a&0xffffff, (u8)d, SekPc); +#endif + return (u8)d; +} + +u16 PicoReadM68k16(u32 a) +{ + u16 d=0; + + if ((a&0xe00000)==0xe00000) { d=*(u16 *)(Pico.ram+(a&0xfffe)); goto end; } // Ram + + a&=0xfffffe; + + if (a < 0x20000) { d = *(u16 *)(Pico_mcd->bios+a); goto end; } // bios + + // prg RAM + if ((a&0xfe0000)==0x020000) { + u8 *prg_bank = Pico_mcd->prg_ram_b[Pico_mcd->m68k_regs[3]>>6]; + d = *(u16 *)(prg_bank+(a&0x1fffe)); + goto end; + } + + d = (u16)OtherRead16(a, 16); + + end: + +#ifdef __debug_io + dprintf("r16: %06x, %04x @%06x", a&0xffffff, d, SekPc); +#endif + return d; +} + +u32 PicoReadM68k32(u32 a) +{ + u32 d=0; + + if ((a&0xe00000)==0xe00000) { u16 *pm=(u16 *)(Pico.ram+(a&0xfffe)); d = (pm[0]<<16)|pm[1]; goto end; } // Ram + + a&=0xfffffe; + + if (a < 0x20000) { u16 *pm=(u16 *)(Pico_mcd->bios+a); d = (pm[0]<<16)|pm[1]; goto end; } // bios + + // prg RAM + if ((a&0xfe0000)==0x020000) { + u8 *prg_bank = Pico_mcd->prg_ram_b[Pico_mcd->m68k_regs[3]>>6]; + u16 *pm=(u16 *)(prg_bank+(a&0x1fffe)); + d = (pm[0]<<16)|pm[1]; + goto end; + } + + d = (OtherRead16(a, 32)<<16)|OtherRead16(a+2, 32); + + end: +#ifdef __debug_io + dprintf("r32: %06x, %08x @%06x", a&0xffffff, d, SekPc); +#endif + return d; +} + +// ----------------------------------------------------------------- +// Write Ram + +void PicoWriteM68k8(u32 a,u8 d) +{ +#ifdef __debug_io + dprintf("w8 : %06x, %02x @%06x", a&0xffffff, d, SekPc); +#endif + //if ((a&0xe0ffff)==0xe0a9ba+0x69c) + // dprintf("w8 : %06x, %02x @%06x", a&0xffffff, d, SekPc); + + + if ((a&0xe00000)==0xe00000) { u8 *pm=(u8 *)(Pico.ram+((a^1)&0xffff)); pm[0]=d; return; } // Ram + + a&=0xffffff; + + // prg RAM + if ((a&0xfe0000)==0x020000) { + u8 *prg_bank = Pico_mcd->prg_ram_b[Pico_mcd->m68k_regs[3]>>6]; + u8 *pm=(u8 *)(prg_bank+((a^1)&0x1ffff)); + *pm=d; + return; + } + + OtherWrite8(a,d,8); +} + +void PicoWriteM68k16(u32 a,u16 d) +{ +#ifdef __debug_io + dprintf("w16: %06x, %04x", a&0xffffff, d); +#endif + //if ((a&0xe0ffff)==0xe0AF0E+0x69c||(a&0xe0ffff)==0xe0A9A8+0x69c||(a&0xe0ffff)==0xe0A9AA+0x69c||(a&0xe0ffff)==0xe0A9AC+0x69c) + // dprintf("w16: %06x, %04x @%06x", a&0xffffff, d, SekPc); + + if ((a&0xe00000)==0xe00000) { *(u16 *)(Pico.ram+(a&0xfffe))=d; return; } // Ram + + a&=0xfffffe; + + // prg RAM + if ((a&0xfe0000)==0x020000) { + u8 *prg_bank = Pico_mcd->prg_ram_b[Pico_mcd->m68k_regs[3]>>6]; + *(u16 *)(prg_bank+(a&0x1fffe))=d; + return; + } + + + OtherWrite16(a,d); +} + +void PicoWriteM68k32(u32 a,u32 d) +{ +#ifdef __debug_io + dprintf("w32: %06x, %08x", a&0xffffff, d); +#endif + + if ((a&0xe00000)==0xe00000) + { + // Ram: + u16 *pm=(u16 *)(Pico.ram+(a&0xfffe)); + pm[0]=(u16)(d>>16); pm[1]=(u16)d; + return; + } + + a&=0xfffffe; + + // prg RAM + if ((a&0xfe0000)==0x020000) { + u8 *prg_bank = Pico_mcd->prg_ram_b[Pico_mcd->m68k_regs[3]>>6]; + u16 *pm=(u16 *)(prg_bank+(a&0x1fffe)); + pm[0]=(u16)(d>>16); pm[1]=(u16)d; + return; + } + + + OtherWrite16(a, (u16)(d>>16)); + OtherWrite16(a+2,(u16)d); +} + + +// ----------------------------------------------------------------- + + +u8 PicoReadS68k8(u32 a) +{ + u32 d=0; + + a&=0xffffff; + + // prg RAM + if (a < 0x80000) { + d = *(Pico_mcd->prg_ram+(a^1)); + goto end; + } + + // regs + if ((a&0xfffe00) == 0xff8000) { + d = s68k_reg_read16(a&~1, 8|(a&1)); if ((a&1)==0) d>>=8; + goto end; + } + + dprintf("s68k r8 : %06x, %02x @%06x", a&0xffffff, (u8)d, SekPcS68k); + + end: + +#ifdef __debug_io2 + dprintf("s68k r8 : %06x, %02x @%06x", a&0xffffff, (u8)d, SekPcS68k); +#endif + return (u8)d; +} + +u16 PicoReadS68k16(u32 a) +{ + u16 d=0; + + a&=0xfffffe; + + // prg RAM + if (a < 0x80000) { + d = *(u16 *)(Pico_mcd->prg_ram+a); + goto end; + } + + // regs + if ((a&0xfffe00) == 0xff8000) { + d = s68k_reg_read16(a, 16); + goto end; + } + + dprintf("s68k r16: %06x, %04x @%06x", a&0xffffff, d, SekPcS68k); + + end: + +#ifdef __debug_io2 + dprintf("s68k r16: %06x, %04x @%06x", a&0xffffff, d, SekPcS68k); +#endif + return d; +} + +u32 PicoReadS68k32(u32 a) +{ + u32 d=0; + + a&=0xfffffe; + + // prg RAM + if (a < 0x80000) { + u16 *pm=(u16 *)(Pico_mcd->prg_ram+a); + d = (pm[0]<<16)|pm[1]; + goto end; + } + + // regs + if ((a&0xfffe00) == 0xff8000) { + d = (s68k_reg_read16(a, 32)<<16)|s68k_reg_read16(a+2, 32); + goto end; + } + + dprintf("s68k r32: %06x, %08x @%06x", a&0xffffff, d, SekPcS68k); + + end: + +#ifdef __debug_io2 + dprintf("s68k r32: %06x, %08x @%06x", a&0xffffff, d, SekPcS68k); +#endif + return d; +} + +// ----------------------------------------------------------------- + +void PicoWriteS68k8(u32 a,u8 d) +{ +#ifdef __debug_io2 + dprintf("s68k w8 : %06x, %02x @%06x", a&0xffffff, d, SekPcS68k); +#endif + + a&=0xffffff; + + // prg RAM + if (a < 0x80000) { + u8 *pm=(u8 *)(Pico_mcd->prg_ram+(a^1)); + *pm=d; + return; + } + + // regs + if ((a&0xfffe00) == 0xff8000) { + s68k_reg_write8(a,d,8); + return; + } + + dprintf("s68k w8 : %06x, %02x @%06x", a&0xffffff, d, SekPcS68k); +} + +void PicoWriteS68k16(u32 a,u16 d) +{ +#ifdef __debug_io2 + dprintf("s68k w16: %06x, %04x @%06x", a&0xffffff, d, SekPcS68k); +#endif + + a&=0xfffffe; + + // prg RAM + if (a < 0x80000) { + *(u16 *)(Pico_mcd->prg_ram+a)=d; + return; + } + + // regs + if ((a&0xfffe00) == 0xff8000) { + s68k_reg_write8(a, d>>8, 16); + s68k_reg_write8(a+1,d&0xff, 16); + return; + } + + dprintf("s68k w16: %06x, %04x @%06x", a&0xffffff, d, SekPcS68k); +} + +void PicoWriteS68k32(u32 a,u32 d) +{ +#ifdef __debug_io2 + dprintf("s68k w32: %06x, %08x @%06x", a&0xffffff, d, SekPcS68k); +#endif + + a&=0xfffffe; + + // prg RAM + if (a < 0x80000) { + u16 *pm=(u16 *)(Pico_mcd->prg_ram+a); + pm[0]=(u16)(d>>16); pm[1]=(u16)d; + return; + } + + // regs + if ((a&0xfffe00) == 0xff8000) { + s68k_reg_write8(a, d>>24, 32); + s68k_reg_write8(a+1,(d>>16)&0xff, 32); + s68k_reg_write8(a+2,(d>>8) &0xff, 32); + s68k_reg_write8(a+3, d &0xff, 32); + return; + } + + dprintf("s68k w32: %06x, %08x @%06x", a&0xffffff, d, SekPcS68k); +} + + + +// ----------------------------------------------------------------- + +#ifdef EMU_M68K +unsigned char PicoReadCD8w (unsigned int a) { + return m68ki_cpu_p == &PicoS68kCPU ? PicoReadS68k8(a) : PicoReadM68k8(a); +} +unsigned short PicoReadCD16w(unsigned int a) { + return m68ki_cpu_p == &PicoS68kCPU ? PicoReadS68k16(a) : PicoReadM68k16(a); +} +unsigned int PicoReadCD32w(unsigned int a) { + return m68ki_cpu_p == &PicoS68kCPU ? PicoReadS68k32(a) : PicoReadM68k32(a); +} +void PicoWriteCD8w (unsigned int a, unsigned char d) { + if (m68ki_cpu_p == &PicoS68kCPU) PicoWriteS68k8(a, d); else PicoWriteM68k8(a, d); +} +void PicoWriteCD16w(unsigned int a, unsigned short d) { + if (m68ki_cpu_p == &PicoS68kCPU) PicoWriteS68k16(a, d); else PicoWriteM68k16(a, d); +} +void PicoWriteCD32w(unsigned int a, unsigned int d) { + if (m68ki_cpu_p == &PicoS68kCPU) PicoWriteS68k32(a, d); else PicoWriteM68k32(a, d); +} + +// these are allowed to access RAM +unsigned int m68k_read_pcrelative_CD8 (unsigned int a) { + a&=0xffffff; + if(m68ki_cpu_p == &PicoS68kCPU) { + if (a < 0x80000) return *(u8 *)(Pico_mcd->prg_ram+(a^1)); // PRG Ram + else dprintf("s68k read_pcrel8 @ %06x", a); + } else { + if(aprg_ram+(a&~1)); // PRG Ram + else dprintf("s68k read_pcrel16 @ %06x", a); + } else { + if(aprg_ram+(a&~1)); return (pm[0]<<16)|pm[1]; } // PRG Ram + else dprintf("s68k read_pcrel32 @ %06x", a); + } else { + if(aprg_ram, 0, sizeof(mcd_state) - sizeof(Pico_mcd->bios)); + PicoMCD |= 2; // s68k reset pending + counter75hz = 0; + + LC89510_Reset(); + Reset_CD(); + + return 0; +} + +static __inline void SekRun(int cyc) +{ + int cyc_do; + SekCycleAim+=cyc; + if((cyc_do=SekCycleAim-SekCycleCnt) < 0) return; +#if defined(EMU_M68K) + m68k_set_context(&PicoM68kCPU); + SekCycleCnt+=m68k_execute(cyc_do); +#endif +} + +static __inline void SekRunS68k(int cyc) +{ + int cyc_do; + SekCycleAimS68k+=cyc; + if((cyc_do=SekCycleAimS68k-SekCycleCntS68k) < 0) return; +#if defined(EMU_M68K) + m68k_set_context(&PicoS68kCPU); + SekCycleCntS68k+=m68k_execute(cyc_do); +#endif +} + +// TODO: tidy +extern unsigned char m68k_regs[0x40]; +extern unsigned char s68k_regs[0x200]; + +// Accurate but slower frame which does hints +static int PicoFrameHintsMCD(void) +{ + struct PicoVideo *pv=&Pico.video; + int total_z80=0,lines,y,lines_vis = 224,z80CycleAim = 0,line_sample; + const int cycles_68k=488,cycles_z80=228,cycles_s68k=795; // both PAL and NTSC compile to same values + int skip=PicoSkipFrame || (PicoOpt&0x10); + int hint; // Hint counter + + if(Pico.m.pal) { // + //cycles_68k = (int) ((double) OSC_PAL / 7 / 50 / 312 + 0.4); // should compile to a constant (488) + //cycles_z80 = (int) ((double) OSC_PAL / 15 / 50 / 312 + 0.4); // 228 + lines = 312; // Steve Snake says there are 313 lines, but this seems to also work well + line_sample = 68; + if(pv->reg[1]&8) lines_vis = 240; + } else { + //cycles_68k = (int) ((double) OSC_NTSC / 7 / 60 / 262 + 0.4); // 488 + //cycles_z80 = (int) ((double) OSC_NTSC / 15 / 60 / 262 + 0.4); // 228 + lines = 262; + line_sample = 93; + } + + SekCyclesReset(); + SekCyclesResetS68k(); + //z80ExtraCycles = 0; + + if(PicoOpt&4) + z80CycleAim = 0; +// z80_resetCycles(); + + pv->status&=~0x88; // clear V-Int, come out of vblank + + hint=pv->reg[10]; // Load H-Int counter + //dprintf("-hint: %i", hint); + + for (y=0;y 25) Pico.m.padTHPhase[0]=0; + if(Pico.m.padDelay[1]++ > 25) Pico.m.padTHPhase[1]=0; + } + + // H-Interrupts: + if(y <= lines_vis && --hint < 0) // y <= lines_vis: Comix Zone, Golden Axe + { + //dprintf("rhint:old @ %06x", SekPc); + hint=pv->reg[10]; // Reload H-Int counter + pv->pending_ints|=0x10; + if (pv->reg[0]&0x10) SekInterrupt(4); + //dprintf("rhint: %i @ %06x [%i|%i]", hint, SekPc, y, SekCycleCnt); + //dprintf("hint_routine: %x", (*(unsigned short*)(Pico.ram+0x0B84)<<16)|*(unsigned short*)(Pico.ram+0x0B86)); + } + + // V-Interrupt: + if (y == lines_vis) + { + //dprintf("vint: @ %06x [%i|%i]", SekPc, y, SekCycleCnt); + pv->status|=0x88; // V-Int happened, go into vblank + SekRun(128); SekCycleAim-=128; // there must be a gap between H and V ints, also after vblank bit set (Mazin Saga, Bram Stoker's Dracula) + /*if(Pico.m.z80Run && (PicoOpt&4)) { + z80CycleAim+=cycles_z80/2; + total_z80+=z80_run(z80CycleAim-total_z80); + z80CycleAim-=cycles_z80/2; + }*/ + pv->pending_ints|=0x20; + if(pv->reg[1]&0x20) SekInterrupt(6); + if(Pico.m.z80Run && (PicoOpt&4)) // ? + z80_int(); + //dprintf("zint: [%i|%i] zPC=%04x", Pico.m.scanline, SekCyclesDone(), mz80GetRegisterValue(NULL, 0)); + } + + // decide if we draw this line +#if CAN_HANDLE_240_LINES + if(!skip && ((!(pv->reg[1]&8) && y<224) || ((pv->reg[1]&8) && y<240)) ) +#else + if(!skip && y<224) +#endif + PicoLine(y); + + if(PicoOpt&1) + sound_timers_and_dac(y); + + // get samples from sound chips + if(y == 32 && PsndOut) + emustatus &= ~1; + else if((y == 224 || y == line_sample) && PsndOut) + ;//getSamples(y); + + // Run scanline: + //dprintf("m68k starting exec @ %06x", SekPc); + SekRun(cycles_68k); + if ((Pico_mcd->m68k_regs[1]&3) == 1) { // no busreq/no reset +#if 0 + int i; + FILE *f = fopen("prg_ram.bin", "wb"); + for (i = 0; i < 0x80000; i+=2) + { + int tmp = Pico_mcd->prg_ram[i]; + Pico_mcd->prg_ram[i] = Pico_mcd->prg_ram[i+1]; + Pico_mcd->prg_ram[i+1] = tmp; + } + fwrite(Pico_mcd->prg_ram, 1, 0x80000, f); + fclose(f); + exit(1); +#endif + //dprintf("s68k starting exec @ %06x", SekPcS68k); + SekRunS68k(cycles_s68k); + } + + if((PicoOpt&4) && Pico.m.z80Run) { + Pico.m.z80Run|=2; + z80CycleAim+=cycles_z80; + total_z80+=z80_run(z80CycleAim-total_z80); + } + + // if cdd is on, counter elapsed and irq4 is not masked, do irq4 + if ((Pico_mcd->s68k_regs[0x37]&4) && ++counter75hz > 209 && (Pico_mcd->s68k_regs[0x33]&(1<<4))) { + counter75hz = 0; + Check_CD_Command(); + } + } + + // draw a frame just after vblank in alternative render mode + if(!PicoSkipFrame && (PicoOpt&0x10)) + PicoFrameFull(); + + return 0; +} + + +int PicoFrameMCD(void) +{ + if(!(PicoOpt&0x10)) + PicoFrameStart(); + + PicoFrameHintsMCD(); + + return 0; +} + + diff --git a/Pico/cd/Sek.c b/Pico/cd/Sek.c new file mode 100644 index 00000000..c9d3737b --- /dev/null +++ b/Pico/cd/Sek.c @@ -0,0 +1,78 @@ +// This is part of Pico Library + +// (c) Copyright 2004 Dave, All rights reserved. +// (c) Copyright 2006 notaz, All rights reserved. +// Free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + + +#include "../PicoInt.h" + + +int SekCycleCntS68k=0; // cycles done in this frame +int SekCycleAimS68k=0; // cycle aim + +#ifdef EMU_M68K +// ---------------------- MUSASHI 68000 ---------------------- +m68ki_cpu_core PicoS68kCPU; // Mega CD's CPU +#endif + + +#ifdef EMU_M68K +int SekIntAckS68k(int level) +{ + dprintf("s68k: int %i ack [%i|%i]", level, Pico.m.scanline, SekCyclesDone()); + CPU_INT_LEVEL = 0; + return M68K_INT_ACK_AUTOVECTOR; +} +#endif + + +int SekInitS68k() +{ +#ifdef EMU_M68K + { + // Musashi is not very context friendly.. + void *oldcontext = m68ki_cpu_p; + m68k_set_context(&PicoS68kCPU); + m68k_set_cpu_type(M68K_CPU_TYPE_68000); + m68k_init(); + m68k_set_int_ack_callback(SekIntAckS68k); +// m68k_pulse_reset(); // not yet, memmap is not set up + m68k_set_context(oldcontext); + } +#endif + + return 0; +} + +// Reset the 68000: +int SekResetS68k() +{ + if (Pico.rom==NULL) return 1; + +#ifdef EMU_M68K + { + void *oldcontext = m68ki_cpu_p; + + m68k_set_context(&PicoS68kCPU); + m68k_pulse_reset(); + m68k_set_context(oldcontext); + } +#endif + + return 0; +} + +int SekInterruptS68k(int irq) +{ +#ifdef EMU_M68K + void *oldcontext = m68ki_cpu_p; + m68k_set_context(&PicoS68kCPU); + m68k_set_irq(irq); // raise irq (gets lowered after taken or must be done in ack) + m68k_set_context(oldcontext); +#endif + return 0; +} + diff --git a/Pico/cd/cd_sys.c b/Pico/cd/cd_sys.c new file mode 100644 index 00000000..72d6c0ed --- /dev/null +++ b/Pico/cd/cd_sys.c @@ -0,0 +1,996 @@ +#include +#include "cd_sys.h" +//#include "cd_file.h" + +#include "../PicoInt.h" + +#define cdprintf printf +//#define cdprintf(x...) + +#define TRAY_OPEN 0x0500 // TRAY OPEN CDD status +#define NOCD 0x0000 // CD removed CDD status +#define STOPPED 0x0900 // STOPPED CDD status (happen after stop or close tray command) +#define READY 0x0400 // READY CDD status (also used for seeking) +#define FAST_FOW 0x0300 // FAST FORWARD track CDD status +#define FAST_REV 0x10300 // FAST REVERSE track CDD status +#define PLAYING 0x0100 // PLAYING audio track CDD status + +/* +#include "gens.h" +#include "G_dsound.h" +#include "cdda_mp3.h" +#include "lc89510.h" +#include "Star_68k.h" +#include "Mem_M68K.h" +#include "Mem_S68K.h" +#include "save.h" +#include "misc.h" +*/ + + +/* +int CDDA_Enable; + +int CD_Audio_Buffer_L[8192]; +int CD_Audio_Buffer_R[8192]; +int CD_Audio_Buffer_Read_Pos = 0; +int CD_Audio_Buffer_Write_Pos = 2000; +int CD_Audio_Starting; +*/ + +static int CD_Present = 0; +int CD_Timer_Counter = 0; // TODO: check refs + +static int CDD_Complete; + +static int File_Add_Delay = 0; + +//_scd SCD; + + + +#define CHECK_TRAY_OPEN \ +if (Pico_mcd->scd.Status_CDD == TRAY_OPEN) \ +{ \ + Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD; \ + \ + Pico_mcd->cdd.Minute = 0; \ + Pico_mcd->cdd.Seconde = 0; \ + Pico_mcd->cdd.Frame = 0; \ + Pico_mcd->cdd.Ext = 0; \ + \ + CDD_Complete = 1; \ + \ + return 2; \ +} + + +#define CHECK_CD_PRESENT \ +if (!CD_Present) \ +{ \ + Pico_mcd->scd.Status_CDD = NOCD; \ + Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD; \ + \ + Pico_mcd->cdd.Minute = 0; \ + Pico_mcd->cdd.Seconde = 0; \ + Pico_mcd->cdd.Frame = 0; \ + Pico_mcd->cdd.Ext = 0; \ + \ + CDD_Complete = 1; \ + \ + return 3; \ +} + + +#if 0 +static void MSB2DWORD(unsigned int *d, unsigned char *b) +{ + unsigned int retVal; + + retVal = (unsigned int )b[0]; + retVal = (retVal<<8) + (unsigned int )b[1]; + retVal = (retVal<<8) + (unsigned int )b[2]; + retVal = (retVal<<8) + (unsigned int )b[3]; + + *d = retVal; +} +#endif + +static int MSF_to_LBA(_msf *MSF) +{ + return (MSF->M * 60 * 75) + (MSF->S * 75) + MSF->F - 150; +} + + +void LBA_to_MSF(int lba, _msf *MSF) +{ + if (lba < -150) lba = 0; + else lba += 150; + MSF->M = lba / (60 * 75); + MSF->S = (lba / 75) % 60; + MSF->F = lba % 75; +} + + +static unsigned int MSF_to_Track(_msf *MSF) +{ + int i, Start, Cur; + + Start = (MSF->M << 16) + (MSF->S << 8) + MSF->F; + + for(i = Pico_mcd->scd.TOC.First_Track; i <= (Pico_mcd->scd.TOC.Last_Track + 1); i++) + { + Cur = Pico_mcd->scd.TOC.Tracks[i - Pico_mcd->scd.TOC.First_Track].MSF.M << 16; + Cur += Pico_mcd->scd.TOC.Tracks[i - Pico_mcd->scd.TOC.First_Track].MSF.S << 8; + Cur += Pico_mcd->scd.TOC.Tracks[i - Pico_mcd->scd.TOC.First_Track].MSF.F; + + if (Cur > Start) break; + } + + --i; + + if (i > Pico_mcd->scd.TOC.Last_Track) return 100; + if (i < Pico_mcd->scd.TOC.First_Track) i = Pico_mcd->scd.TOC.First_Track; + + return (unsigned) i; +} + + +static unsigned int LBA_to_Track(int lba) +{ + _msf MSF; + + LBA_to_MSF(lba, &MSF); + return MSF_to_Track(&MSF); +} + + +static void Track_to_MSF(int track, _msf *MSF) +{ + if (track < Pico_mcd->scd.TOC.First_Track) track = Pico_mcd->scd.TOC.First_Track; + else if (track > Pico_mcd->scd.TOC.Last_Track) track = Pico_mcd->scd.TOC.Last_Track; + + MSF->M = Pico_mcd->scd.TOC.Tracks[track - Pico_mcd->scd.TOC.First_Track].MSF.M; + MSF->S = Pico_mcd->scd.TOC.Tracks[track - Pico_mcd->scd.TOC.First_Track].MSF.S; + MSF->F = Pico_mcd->scd.TOC.Tracks[track - Pico_mcd->scd.TOC.First_Track].MSF.F; +} + + +int Track_to_LBA(int track) +{ + _msf MSF; + + Track_to_MSF(track, &MSF); + return MSF_to_LBA(&MSF); +} + + +void Check_CD_Command(void) +{ + cdprintf("CHECK CD COMMAND\n"); + + // Check CDD + + if (CDD_Complete) + { + CDD_Complete = 0; + + CDD_Export_Status(); + } + + // Check CDC + + if (Pico_mcd->scd.Status_CDC & 1) // CDC is reading data ... + { + cdprintf("Sending a read command\n"); + + // DATA ? + if (Pico_mcd->scd.TOC.Tracks[Pico_mcd->scd.Cur_Track - Pico_mcd->scd.TOC.First_Track].Type) + Pico_mcd->s68k_regs[0x36] |= 0x01; + else Pico_mcd->s68k_regs[0x36] &= ~0x01; // AUDIO + + if (File_Add_Delay == 0) + { +#if 0 // TODO + FILE_Read_One_LBA_CDC(); +#endif + } + else File_Add_Delay--; + } + + if (Pico_mcd->scd.Status_CDD == FAST_FOW) + { + Pico_mcd->scd.Cur_LBA += 10; + CDC_Update_Header(); + + } + else if (Pico_mcd->scd.Status_CDD == FAST_REV) + { + Pico_mcd->scd.Cur_LBA -= 10; + if (Pico_mcd->scd.Cur_LBA < -150) Pico_mcd->scd.Cur_LBA = -150; + CDC_Update_Header(); + } +} + + +int Init_CD_Driver(void) +{ +#if 0 // TODO + FILE_Init(); +#endif + + return 0; +} + + +void End_CD_Driver(void) +{ +#if 0 // TODO + FILE_End(); +#endif +} + + +void Reset_CD(void) +{ + Pico_mcd->scd.Cur_Track = 0; + Pico_mcd->scd.Cur_LBA = -150; + Pico_mcd->scd.Status_CDD = READY; + CDD_Complete = 0; +} + + +int Insert_CD(char *buf, char *iso_name) +{ +// memset(CD_Audio_Buffer_L, 0, 4096 * 4); +// memset(CD_Audio_Buffer_R, 0, 4096 * 4); + + if (iso_name == NULL) + { + CD_Present = 0; + } + else + { +#if 0 // TODO + Load_ISO(buf, iso_name); + CD_Present = 1; +#endif + return 0; + } + + return 0; +} + + +void Stop_CD(void) +{ +#if 0 // TODO + Unload_ISO(); +#endif + CD_Present = 0; +} + + +void Change_CD(void) +{ + if (Pico_mcd->scd.Status_CDD == TRAY_OPEN) Close_Tray_CDD_cC(); + else Open_Tray_CDD_cD(); +} + + +int Get_Status_CDD_c0(void) +{ + cdprintf("Status command : Cur LBA = %d\n", Pico_mcd->scd.Cur_LBA); + + // Clear immediat status + if ((Pico_mcd->cdd.Status & 0x0F00) == 0x0200) + Pico_mcd->cdd.Status = (Pico_mcd->scd.Status_CDD & 0xFF00) | (Pico_mcd->cdd.Status & 0x00FF); + else if ((Pico_mcd->cdd.Status & 0x0F00) == 0x0700) + Pico_mcd->cdd.Status = (Pico_mcd->scd.Status_CDD & 0xFF00) | (Pico_mcd->cdd.Status & 0x00FF); + else if ((Pico_mcd->cdd.Status & 0x0F00) == 0x0E00) + Pico_mcd->cdd.Status = (Pico_mcd->scd.Status_CDD & 0xFF00) | (Pico_mcd->cdd.Status & 0x00FF); + + CDD_Complete = 1; + + return 0; +} + + +int Stop_CDD_c1(void) +{ + CHECK_TRAY_OPEN + + Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read + + if (CD_Present) Pico_mcd->scd.Status_CDD = STOPPED; + else Pico_mcd->scd.Status_CDD = NOCD; + Pico_mcd->cdd.Status = 0x0000; + + Pico_mcd->s68k_regs[0x36] |= 0x01; // Data bit set because stopped + + Pico_mcd->cdd.Minute = 0; + Pico_mcd->cdd.Seconde = 0; + Pico_mcd->cdd.Frame = 0; + Pico_mcd->cdd.Ext = 0; + + CDD_Complete = 1; + + return 0; +} + + +int Get_Pos_CDD_c20(void) +{ + _msf MSF; + + cdprintf("command 200 : Cur LBA = %d\n", Pico_mcd->scd.Cur_LBA); + + CHECK_TRAY_OPEN + + Pico_mcd->cdd.Status &= 0xFF; + if (!CD_Present) + { + Pico_mcd->scd.Status_CDD = NOCD; + Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD; + } +// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD; + Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD; + + cdprintf("Status CDD = %.4X Status = %.4X\n", Pico_mcd->scd.Status_CDD, Pico_mcd->cdd.Status); + + LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF); + + Pico_mcd->cdd.Minute = INT_TO_BCDW(MSF.M); + Pico_mcd->cdd.Seconde = INT_TO_BCDW(MSF.S); + Pico_mcd->cdd.Frame = INT_TO_BCDW(MSF.F); + Pico_mcd->cdd.Ext = 0; + + CDD_Complete = 1; + + return 0; +} + + +int Get_Track_Pos_CDD_c21(void) +{ + int elapsed_time; + _msf MSF; + + cdprintf("command 201 : Cur LBA = %d", Pico_mcd->scd.Cur_LBA); + + CHECK_TRAY_OPEN + + Pico_mcd->cdd.Status &= 0xFF; + if (!CD_Present) + { + Pico_mcd->scd.Status_CDD = NOCD; + Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD; + } +// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD; + Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD; + + elapsed_time = Pico_mcd->scd.Cur_LBA - Track_to_LBA(LBA_to_Track(Pico_mcd->scd.Cur_LBA)); + LBA_to_MSF(elapsed_time - 150, &MSF); + + cdprintf(" elapsed = %d\n", elapsed_time); + + Pico_mcd->cdd.Minute = INT_TO_BCDW(MSF.M); + Pico_mcd->cdd.Seconde = INT_TO_BCDW(MSF.S); + Pico_mcd->cdd.Frame = INT_TO_BCDW(MSF.F); + Pico_mcd->cdd.Ext = 0; + + CDD_Complete = 1; + + return 0; +} + + +int Get_Current_Track_CDD_c22(void) +{ + cdprintf("Status CDD = %.4X Status = %.4X\n", Pico_mcd->scd.Status_CDD, Pico_mcd->cdd.Status); + + CHECK_TRAY_OPEN + + Pico_mcd->cdd.Status &= 0xFF; + if (!CD_Present) + { + Pico_mcd->scd.Status_CDD = NOCD; + Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD; + } +// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD; + Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD; + + Pico_mcd->scd.Cur_Track = LBA_to_Track(Pico_mcd->scd.Cur_LBA); + + if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02; + else Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track); + Pico_mcd->cdd.Seconde = 0; + Pico_mcd->cdd.Frame = 0; + Pico_mcd->cdd.Ext = 0; + + CDD_Complete = 1; + + return 0; +} + + +int Get_Total_Lenght_CDD_c23(void) +{ + CHECK_TRAY_OPEN + + Pico_mcd->cdd.Status &= 0xFF; + if (!CD_Present) + { + Pico_mcd->scd.Status_CDD = NOCD; + Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD; + } +// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD; + Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD; + + Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.TOC.Tracks[Pico_mcd->scd.TOC.Last_Track - + Pico_mcd->scd.TOC.First_Track + 1].MSF.M); + Pico_mcd->cdd.Seconde = INT_TO_BCDW(Pico_mcd->scd.TOC.Tracks[Pico_mcd->scd.TOC.Last_Track - + Pico_mcd->scd.TOC.First_Track + 1].MSF.S); + Pico_mcd->cdd.Frame = INT_TO_BCDW(Pico_mcd->scd.TOC.Tracks[Pico_mcd->scd.TOC.Last_Track - + Pico_mcd->scd.TOC.First_Track + 1].MSF.F); + Pico_mcd->cdd.Ext = 0; + +// FIXME: remove +Pico_mcd->cdd.Seconde = 2; + + CDD_Complete = 1; + + return 0; +} + + +int Get_First_Last_Track_CDD_c24(void) +{ + CHECK_TRAY_OPEN + + Pico_mcd->cdd.Status &= 0xFF; + if (!CD_Present) + { + Pico_mcd->scd.Status_CDD = NOCD; + } +// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD; + Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD; + + Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.TOC.First_Track); + Pico_mcd->cdd.Seconde = INT_TO_BCDW(Pico_mcd->scd.TOC.Last_Track); + Pico_mcd->cdd.Frame = 0; + Pico_mcd->cdd.Ext = 0; + +// FIXME: remove +Pico_mcd->cdd.Minute = Pico_mcd->cdd.Seconde = 1; + + CDD_Complete = 1; + + return 0; +} + + +int Get_Track_Adr_CDD_c25(void) +{ + int track_number; + + CHECK_TRAY_OPEN + + // track number in TC4 & TC5 + + track_number = (Pico_mcd->s68k_regs[0x38+10+4] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+5] & 0xF); + + Pico_mcd->cdd.Status &= 0xFF; + if (!CD_Present) + { + Pico_mcd->scd.Status_CDD = NOCD; + Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD; + } +// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD; + Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD; + + if (track_number > Pico_mcd->scd.TOC.Last_Track) track_number = Pico_mcd->scd.TOC.Last_Track; + else if (track_number < Pico_mcd->scd.TOC.First_Track) track_number = Pico_mcd->scd.TOC.First_Track; + + Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.TOC.Tracks[track_number - Pico_mcd->scd.TOC.First_Track].MSF.M); + Pico_mcd->cdd.Seconde = INT_TO_BCDW(Pico_mcd->scd.TOC.Tracks[track_number - Pico_mcd->scd.TOC.First_Track].MSF.S); + Pico_mcd->cdd.Frame = INT_TO_BCDW(Pico_mcd->scd.TOC.Tracks[track_number - Pico_mcd->scd.TOC.First_Track].MSF.F); + Pico_mcd->cdd.Ext = track_number % 10; + + if (Pico_mcd->scd.TOC.Tracks[track_number - Pico_mcd->scd.TOC.First_Track].Type) Pico_mcd->cdd.Frame |= 0x0800; + + CDD_Complete = 1; + return 0; +} + + +int Play_CDD_c3(void) +{ + _msf MSF; + int delay, new_lba; + + CHECK_TRAY_OPEN + CHECK_CD_PRESENT + + // MSF of the track to play in TC buffer + + MSF.M = (Pico_mcd->s68k_regs[0x38+10+2] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+3] & 0xF); + MSF.S = (Pico_mcd->s68k_regs[0x38+10+4] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+5] & 0xF); + MSF.F = (Pico_mcd->s68k_regs[0x38+10+6] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+7] & 0xF); + + Pico_mcd->scd.Cur_Track = MSF_to_Track(&MSF); + + new_lba = MSF_to_LBA(&MSF); + delay = new_lba - Pico_mcd->scd.Cur_LBA; + if (delay < 0) delay = -delay; + delay >>= 12; + + Pico_mcd->scd.Cur_LBA = new_lba; + CDC_Update_Header(); + + cdprintf("Read : Cur LBA = %d, M=%d, S=%d, F=%d\n", Pico_mcd->scd.Cur_LBA, MSF.M, MSF.S, MSF.F); + + if (Pico_mcd->scd.Status_CDD != PLAYING) delay += 20; + + Pico_mcd->scd.Status_CDD = PLAYING; + Pico_mcd->cdd.Status = 0x0102; +// Pico_mcd->cdd.Status = COMM_OK; + + if (File_Add_Delay == 0) File_Add_Delay = delay; + + if (Pico_mcd->scd.TOC.Tracks[Pico_mcd->scd.Cur_Track - Pico_mcd->scd.TOC.First_Track].Type) + { + Pico_mcd->s68k_regs[0x36] |= 0x01; // DATA + } + else + { + Pico_mcd->s68k_regs[0x36] &= ~0x01; // AUDIO + //CD_Audio_Starting = 1; +#if 0 // TODO + FILE_Play_CD_LBA(); +#endif + } + + if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02; + else Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track); + Pico_mcd->cdd.Seconde = 0; + Pico_mcd->cdd.Frame = 0; + Pico_mcd->cdd.Ext = 0; + + Pico_mcd->scd.Status_CDC |= 1; // Read data with CDC + + CDD_Complete = 1; + return 0; +} + + +int Seek_CDD_c4(void) +{ + _msf MSF; + + CHECK_TRAY_OPEN + CHECK_CD_PRESENT + + // MSF to seek in TC buffer + + MSF.M = (Pico_mcd->s68k_regs[0x38+10+2] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+3] & 0xF); + MSF.S = (Pico_mcd->s68k_regs[0x38+10+4] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+5] & 0xF); + MSF.F = (Pico_mcd->s68k_regs[0x38+10+6] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+7] & 0xF); + + Pico_mcd->scd.Cur_Track = MSF_to_Track(&MSF); + Pico_mcd->scd.Cur_LBA = MSF_to_LBA(&MSF); + CDC_Update_Header(); + + Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read + + Pico_mcd->scd.Status_CDD = READY; + Pico_mcd->cdd.Status = 0x0200; + + // DATA ? + if (Pico_mcd->scd.TOC.Tracks[Pico_mcd->scd.Cur_Track - Pico_mcd->scd.TOC.First_Track].Type) + Pico_mcd->s68k_regs[0x36] |= 0x01; + else Pico_mcd->s68k_regs[0x36] &= ~0x01; // AUDIO + + Pico_mcd->cdd.Minute = 0; + Pico_mcd->cdd.Seconde = 0; + Pico_mcd->cdd.Frame = 0; + Pico_mcd->cdd.Ext = 0; + + CDD_Complete = 1; + + return 0; +} + + +int Pause_CDD_c6(void) +{ + CHECK_TRAY_OPEN + CHECK_CD_PRESENT + + Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read to start a new one if raw data + + Pico_mcd->scd.Status_CDD = READY; + Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD; + + Pico_mcd->s68k_regs[0x36] |= 0x01; // Data bit set because stopped + + Pico_mcd->cdd.Minute = 0; + Pico_mcd->cdd.Seconde = 0; + Pico_mcd->cdd.Frame = 0; + Pico_mcd->cdd.Ext = 0; + + CDD_Complete = 1; + + return 0; +} + + +int Resume_CDD_c7(void) +{ + CHECK_TRAY_OPEN + CHECK_CD_PRESENT + + Pico_mcd->scd.Cur_Track = LBA_to_Track(Pico_mcd->scd.Cur_LBA); + +#ifdef DEBUG_CD + { + _msf MSF; + LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF); + cdprintf("Resume read : Cur LBA = %d, M=%d, S=%d, F=%d\n", Pico_mcd->scd.Cur_LBA, MSF.M, MSF.S, MSF.F); + } +#endif + + Pico_mcd->scd.Status_CDD = PLAYING; + Pico_mcd->cdd.Status = 0x0102; + + if (Pico_mcd->scd.TOC.Tracks[Pico_mcd->scd.Cur_Track - Pico_mcd->scd.TOC.First_Track].Type) + { + Pico_mcd->s68k_regs[0x36] |= 0x01; // DATA + } + else + { + Pico_mcd->s68k_regs[0x36] &= ~0x01; // AUDIO + //CD_Audio_Starting = 1; +#if 0 // TODO + FILE_Play_CD_LBA(); +#endif + } + + if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02; + else Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track); + Pico_mcd->cdd.Seconde = 0; + Pico_mcd->cdd.Frame = 0; + Pico_mcd->cdd.Ext = 0; + + Pico_mcd->scd.Status_CDC |= 1; // Read data with CDC + + CDD_Complete = 1; + return 0; +} + + +int Fast_Foward_CDD_c8(void) +{ + CHECK_TRAY_OPEN + CHECK_CD_PRESENT + + Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read + + Pico_mcd->scd.Status_CDD = FAST_FOW; + Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD | 2; + + Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track); + Pico_mcd->cdd.Seconde = 0; + Pico_mcd->cdd.Frame = 0; + Pico_mcd->cdd.Ext = 0; + + CDD_Complete = 1; + + return 0; +} + + +int Fast_Rewind_CDD_c9(void) +{ + CHECK_TRAY_OPEN + CHECK_CD_PRESENT + + Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read + + Pico_mcd->scd.Status_CDD = FAST_REV; + Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD | 2; + + Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track); + Pico_mcd->cdd.Seconde = 0; + Pico_mcd->cdd.Frame = 0; + Pico_mcd->cdd.Ext = 0; + + CDD_Complete = 1; + + return 0; +} + + +int Close_Tray_CDD_cC(void) +{ + //Clear_Sound_Buffer(); + + Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read + + { +#if 0 // TODO + char new_iso[1024]; + + memset(new_iso, 0, 1024); + + while (!Change_File_L(new_iso, Rom_Dir, "Load SegaCD image file", "SegaCD image file\0*.bin;*.iso;*.raw\0All files\0*.*\0\0", "")); + Reload_SegaCD(new_iso); + + CD_Present = 1; +#else + CD_Present = 0; +#endif + Pico_mcd->scd.Status_CDD = STOPPED; + Pico_mcd->cdd.Status = 0x0000; + + Pico_mcd->cdd.Minute = 0; + Pico_mcd->cdd.Seconde = 0; + Pico_mcd->cdd.Frame = 0; + Pico_mcd->cdd.Ext = 0; + } + + CDD_Complete = 1; + + return 0; +} + + +int Open_Tray_CDD_cD(void) +{ + CHECK_TRAY_OPEN + + Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read + +#if 0 // TODO + Unload_ISO(); +#endif + CD_Present = 0; + + Pico_mcd->scd.Status_CDD = TRAY_OPEN; + Pico_mcd->cdd.Status = 0x0E00; + + Pico_mcd->cdd.Minute = 0; + Pico_mcd->cdd.Seconde = 0; + Pico_mcd->cdd.Frame = 0; + Pico_mcd->cdd.Ext = 0; + + CDD_Complete = 1; + + return 0; +} + + +int CDD_cA(void) +{ + CHECK_TRAY_OPEN + CHECK_CD_PRESENT + + Pico_mcd->scd.Status_CDC &= ~1; + + Pico_mcd->scd.Status_CDD = READY; + Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD; + + Pico_mcd->cdd.Minute = 0; + Pico_mcd->cdd.Seconde = INT_TO_BCDW(1); + Pico_mcd->cdd.Frame = INT_TO_BCDW(1); + Pico_mcd->cdd.Ext = 0; + + CDD_Complete = 1; + + return 0; +} + + +int CDD_Def(void) +{ + Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD; + + Pico_mcd->cdd.Minute = 0; + Pico_mcd->cdd.Seconde = 0; + Pico_mcd->cdd.Frame = 0; + Pico_mcd->cdd.Ext = 0; + + return 0; +} + + + + +/*************************** + * Others CD functions * + **************************/ + + +// do we need them? +#if 0 +void Write_CD_Audio(short *Buf, int rate, int channel, int lenght) +{ + unsigned int lenght_src, lenght_dst; + unsigned int pos_src, pas_src; + + if (rate == 0) return; + if (Sound_Rate == 0) return; + + if (CD_Audio_Starting) + { + CD_Audio_Starting = 0; + memset(CD_Audio_Buffer_L, 0, 4096 * 4); + memset(CD_Audio_Buffer_R, 0, 4096 * 4); + CD_Audio_Buffer_Write_Pos = (CD_Audio_Buffer_Read_Pos + 2000) & 0xFFF; + } + + lenght_src = rate / 75; // 75th of a second + lenght_dst = Sound_Rate / 75; // 75th of a second + + pas_src = (lenght_src << 16) / lenght_dst; + pos_src = 0; + +#ifdef DEBUG_CD + fprintf(debug_SCD_file, "\n********* Write Pos = %d ", CD_Audio_Buffer_Write_Pos); +#endif + + if (channel == 2) + { + __asm + { + mov edi, CD_Audio_Buffer_Write_Pos + mov ebx, Buf + xor esi, esi + mov ecx, lenght_dst + xor eax, eax + mov edx, pas_src + dec ecx + jmp short loop_stereo + +align 16 + +loop_stereo: + movsx eax, word ptr [ebx + esi * 4] + mov CD_Audio_Buffer_L[edi * 4], eax + movsx eax, word ptr [ebx + esi * 4 + 2] + mov CD_Audio_Buffer_R[edi * 4], eax + mov esi, dword ptr pos_src + inc edi + add esi, edx + and edi, 0xFFF + mov dword ptr pos_src, esi + shr esi, 16 + dec ecx + jns short loop_stereo + + mov CD_Audio_Buffer_Write_Pos, edi + } + } + else + { + __asm + { + mov edi, CD_Audio_Buffer_Write_Pos + mov ebx, Buf + xor esi, esi + mov ecx, lenght_dst + xor eax, eax + mov edx, pas_src + dec ecx + jmp short loop_mono + +align 16 + +loop_mono: + movsx eax, word ptr [ebx + esi * 2] + mov CD_Audio_Buffer_L[edi * 4], eax + mov CD_Audio_Buffer_R[edi * 4], eax + mov esi, dword ptr pos_src + inc edi + add esi, edx + and edi, 0xFFF + mov dword ptr pos_src, esi + shr esi, 16 + dec ecx + jns short loop_mono + + mov CD_Audio_Buffer_Write_Pos, edi + } + } + +#ifdef DEBUG_CD + fprintf(debug_SCD_file, "Write Pos 2 = %d\n\n", CD_Audio_Buffer_Write_Pos); +#endif +} + + +void Update_CD_Audio(int **buf, int lenght) +{ + int *Buf_L, *Buf_R; + int diff; + + Buf_L = buf[0]; + Buf_R = buf[1]; + + if (Pico_mcd->s68k_regs[0x36] & 0x01) return; + if (!(Pico_mcd->scd.Status_CDC & 1)) return; + if (CD_Audio_Starting) return; + +#ifdef DEBUG_CD + fprintf(debug_SCD_file, "\n********* Read Pos Normal = %d ", CD_Audio_Buffer_Read_Pos); +#endif + + if (CD_Audio_Buffer_Write_Pos < CD_Audio_Buffer_Read_Pos) + { + diff = CD_Audio_Buffer_Write_Pos + (4096) - CD_Audio_Buffer_Read_Pos; + } + else + { + diff = CD_Audio_Buffer_Write_Pos - CD_Audio_Buffer_Read_Pos; + } + + if (diff < 500) CD_Audio_Buffer_Read_Pos -= 2000; + else if (diff > 3500) CD_Audio_Buffer_Read_Pos += 2000; + +#ifdef DEBUG_CD + else fprintf(debug_SCD_file, " pas de modifs "); +#endif + + CD_Audio_Buffer_Read_Pos &= 0xFFF; + +#ifdef DEBUG_CD + fprintf(debug_SCD_file, "Read Pos = %d ", CD_Audio_Buffer_Read_Pos); +#endif + + if (CDDA_Enable) + { + __asm + { + mov ecx, lenght + mov esi, CD_Audio_Buffer_Read_Pos + mov edi, Buf_L + dec ecx + +loop_L: + mov eax, CD_Audio_Buffer_L[esi * 4] + add [edi], eax + inc esi + add edi, 4 + and esi, 0xFFF + dec ecx + jns short loop_L + + mov ecx, lenght + mov esi, CD_Audio_Buffer_Read_Pos + mov edi, Buf_R + dec ecx + +loop_R: + mov eax, CD_Audio_Buffer_R[esi * 4] + add [edi], eax + inc esi + add edi, 4 + and esi, 0xFFF + dec ecx + jns short loop_R + + mov CD_Audio_Buffer_Read_Pos, esi + } + } + else + { + CD_Audio_Buffer_Read_Pos += lenght; + CD_Audio_Buffer_Read_Pos &= 0xFFF; + } + +#ifdef DEBUG_CD + fprintf(debug_SCD_file, "Read Pos 2 = %d\n\n", CD_Audio_Buffer_Read_Pos); +#endif +} +#endif + diff --git a/Pico/cd/cd_sys.h b/Pico/cd/cd_sys.h new file mode 100644 index 00000000..34c9126f --- /dev/null +++ b/Pico/cd/cd_sys.h @@ -0,0 +1,97 @@ +#ifndef _CD_SYS_H +#define _CD_SYS_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#define INT_TO_BCDB(c) \ +((c) > 99)?(0x99):((((c) / 10) << 4) + ((c) % 10)); + +#define INT_TO_BCDW(c) \ +((c) > 99)?(0x0909):((((c) / 10) << 8) + ((c) % 10)); + +#define BCDB_TO_INT(c) \ +(((c) >> 4) * 10) + ((c) & 0xF); + +#define BCDW_TO_INT(c) \ +(((c) >> 8) * 10) + ((c) & 0xF); + + +typedef struct +{ + unsigned char M; + unsigned char S; + unsigned char F; +} _msf; + +typedef struct +{ + unsigned char Type; + unsigned char Num; + _msf MSF; +} _scd_track; + +typedef struct +{ + unsigned char First_Track; + unsigned char Last_Track; + _scd_track Tracks[100]; +} _scd_toc; + +typedef struct { + unsigned int Status_CDD; + unsigned int Status_CDC; + _scd_toc TOC; + int Cur_LBA; + unsigned int Cur_Track; +} _scd; + + +extern int CD_Timer_Counter; + + +void LBA_to_MSF(int lba, _msf *MSF); +int Track_to_LBA(int track); + + +void Check_CD_Command(void); + +int Init_CD_Driver(void); +void End_CD_Driver(void); +int Insert_CD(char *buf, char *iso_name); +void Stop_CD(void); +void Change_CD(void); +void Reset_CD(void); + +int Get_Status_CDD_c0(void); +int Stop_CDD_c1(void); +int Get_Pos_CDD_c20(void); +int Get_Track_Pos_CDD_c21(void); +int Get_Current_Track_CDD_c22(void); +int Get_Total_Lenght_CDD_c23(void); +int Get_First_Last_Track_CDD_c24(void); +int Get_Track_Adr_CDD_c25(void); +int Play_CDD_c3(void); +int Seek_CDD_c4(void); +int Pause_CDD_c6(void); +int Resume_CDD_c7(void); +int Fast_Foward_CDD_c8(void); +int Fast_Rewind_CDD_c9(void); +int CDD_cA(void); +int Close_Tray_CDD_cC(void); +int Open_Tray_CDD_cD(void); + +int CDD_Def(void); + +//void Write_CD_Audio(short *Buf, int rate, int channel, int lenght); +//void Update_CD_Audio(int **Buf, int lenght); + + +#ifdef __cplusplus +}; +#endif + +#endif + diff --git a/Pico/sound/sn76496.c b/Pico/sound/sn76496.c new file mode 100644 index 00000000..1afd3bef --- /dev/null +++ b/Pico/sound/sn76496.c @@ -0,0 +1,347 @@ +/*************************************************************************** + + sn76496.c + + Routines to emulate the Texas Instruments SN76489 / SN76496 programmable + tone /noise generator. Also known as (or at least compatible with) TMS9919. + + Noise emulation is not accurate due to lack of documentation. The noise + generator uses a shift register with a XOR-feedback network, but the exact + layout is unknown. It can be set for either period or white noise; again, + the details are unknown. + + 28/03/2005 : Sebastien Chevalier + Update th SN76496Write func, according to SN76489 doc found on SMSPower. + - On write with 0x80 set to 0, when LastRegister is other then TONE, + the function is similar than update with 0x80 set to 1 +***************************************************************************/ + +#ifndef __GNUC__ +#pragma warning (disable:4244) +#endif + +#include "sn76496.h" + +#define MAX_OUTPUT 0x47ff // was 0x7fff + +#define STEP 0x10000 + + +/* Formulas for noise generator */ +/* bit0 = output */ + +/* noise feedback for white noise mode (verified on real SN76489 by John Kortink) */ +#define FB_WNOISE 0x14002 /* (16bits) bit16 = bit0(out) ^ bit2 ^ bit15 */ + +/* noise feedback for periodic noise mode */ +//#define FB_PNOISE 0x10000 /* 16bit rorate */ +#define FB_PNOISE 0x08000 /* JH 981127 - fixes Do Run Run */ + +/* +0x08000 is definitely wrong. The Master System conversion of Marble Madness +uses periodic noise as a baseline. With a 15-bit rotate, the bassline is +out of tune. +The 16-bit rotate has been confirmed against a real PAL Sega Master System 2. +Hope that helps the System E stuff, more news on the PSG as and when! +*/ + +/* noise generator start preset (for periodic noise) */ +#define NG_PRESET 0x0f35 + + +struct SN76496 +{ + //sound_stream * Channel; + int SampleRate; + unsigned int UpdateStep; + int VolTable[16]; /* volume table */ + int Register[8]; /* registers */ + int LastRegister; /* last register written */ + int Volume[4]; /* volume of voice 0-2 and noise */ + unsigned int RNG; /* noise generator */ + int NoiseFB; /* noise feedback mask */ + int Period[4]; + int Count[4]; + int Output[4]; + int pad[1]; +}; + +static struct SN76496 ono_sn; // one and only SN76496 +int *sn76496_regs; + +//static +void SN76496Write(int data) +{ + struct SN76496 *R = &ono_sn; + int n; + + + /* update the output buffer before changing the registers */ + //stream_update(R->Channel,0); + + if (data & 0x80) + { + int r = (data & 0x70) >> 4; + int c = r/2; + + R->LastRegister = r; + R->Register[r] = (R->Register[r] & 0x3f0) | (data & 0x0f); + switch (r) + { + case 0: /* tone 0 : frequency */ + case 2: /* tone 1 : frequency */ + case 4: /* tone 2 : frequency */ + R->Period[c] = R->UpdateStep * R->Register[r]; + if (R->Period[c] == 0) R->Period[c] = R->UpdateStep; + if (r == 4) + { + /* update noise shift frequency */ + if ((R->Register[6] & 0x03) == 0x03) + R->Period[3] = 2 * R->Period[2]; + } + break; + case 1: /* tone 0 : volume */ + case 3: /* tone 1 : volume */ + case 5: /* tone 2 : volume */ + case 7: /* noise : volume */ + R->Volume[c] = R->VolTable[data & 0x0f]; + break; + case 6: /* noise : frequency, mode */ + { + int n = R->Register[6]; + R->NoiseFB = (n & 4) ? FB_WNOISE : FB_PNOISE; + n &= 3; + /* N/512,N/1024,N/2048,Tone #3 output */ + R->Period[3] = ((n&3) == 3) ? 2 * R->Period[2] : (R->UpdateStep << (5+(n&3))); + + /* reset noise shifter */ + R->RNG = NG_PRESET; + R->Output[3] = R->RNG & 1; + } + break; + } + } + else + { + int r = R->LastRegister; + int c = r/2; + + switch (r) + { + case 0: /* tone 0 : frequency */ + case 2: /* tone 1 : frequency */ + case 4: /* tone 2 : frequency */ + R->Register[r] = (R->Register[r] & 0x0f) | ((data & 0x3f) << 4); + R->Period[c] = R->UpdateStep * R->Register[r]; + if (R->Period[c] == 0) R->Period[c] = R->UpdateStep; + if (r == 4) + { + /* update noise shift frequency */ + if ((R->Register[6] & 0x03) == 0x03) + R->Period[3] = 2 * R->Period[2]; + } + break; + case 1: /* tone 0 : volume */ + case 3: /* tone 1 : volume */ + case 5: /* tone 2 : volume */ + case 7: /* noise : volume */ + R->Volume[c] = R->VolTable[data & 0x0f]; + R->Register[r] = (R->Register[r] & 0x3f0) | (data & 0x0f); + break; + case 6: /* noise : frequency, mode */ + { + R->Register[r] = (R->Register[r] & 0x3f0) | (data & 0x0f); + n = R->Register[6]; + R->NoiseFB = (n & 4) ? FB_WNOISE : FB_PNOISE; + n &= 3; + /* N/512,N/1024,N/2048,Tone #3 output */ + R->Period[3] = ((n&3) == 3) ? 2 * R->Period[2] : (R->UpdateStep << (5+(n&3))); + + /* reset noise shifter */ + R->RNG = NG_PRESET; + R->Output[3] = R->RNG & 1; + } + break; + } + } +} + +/* +WRITE8_HANDLER( SN76496_0_w ) { SN76496Write(0,data); } +WRITE8_HANDLER( SN76496_1_w ) { SN76496Write(1,data); } +WRITE8_HANDLER( SN76496_2_w ) { SN76496Write(2,data); } +WRITE8_HANDLER( SN76496_3_w ) { SN76496Write(3,data); } +WRITE8_HANDLER( SN76496_4_w ) { SN76496Write(4,data); } +*/ + +//static +void SN76496Update(short *buffer,int length,int stereo) +{ + int i; + struct SN76496 *R = &ono_sn; + + /* If the volume is 0, increase the counter */ + for (i = 0;i < 4;i++) + { + if (R->Volume[i] == 0) + { + /* note that I do count += length, NOT count = length + 1. You might think */ + /* it's the same since the volume is 0, but doing the latter could cause */ + /* interferencies when the program is rapidly modulating the volume. */ + if (R->Count[i] <= length*STEP) R->Count[i] += length*STEP; + } + } + + while (length > 0) + { + int vol[4]; + unsigned int out; + int left; + + + /* vol[] keeps track of how long each square wave stays */ + /* in the 1 position during the sample period. */ + vol[0] = vol[1] = vol[2] = vol[3] = 0; + + for (i = 0;i < 3;i++) + { + if (R->Output[i]) vol[i] += R->Count[i]; + R->Count[i] -= STEP; + /* Period[i] is the half period of the square wave. Here, in each */ + /* loop I add Period[i] twice, so that at the end of the loop the */ + /* square wave is in the same status (0 or 1) it was at the start. */ + /* vol[i] is also incremented by Period[i], since the wave has been 1 */ + /* exactly half of the time, regardless of the initial position. */ + /* If we exit the loop in the middle, Output[i] has to be inverted */ + /* and vol[i] incremented only if the exit status of the square */ + /* wave is 1. */ + while (R->Count[i] <= 0) + { + R->Count[i] += R->Period[i]; + if (R->Count[i] > 0) + { + R->Output[i] ^= 1; + if (R->Output[i]) vol[i] += R->Period[i]; + break; + } + R->Count[i] += R->Period[i]; + vol[i] += R->Period[i]; + } + if (R->Output[i]) vol[i] -= R->Count[i]; + } + + left = STEP; + do + { + int nextevent; + + if (R->Count[3] < left) nextevent = R->Count[3]; + else nextevent = left; + + if (R->Output[3]) vol[3] += R->Count[3]; + R->Count[3] -= nextevent; + if (R->Count[3] <= 0) + { + if (R->RNG & 1) R->RNG ^= R->NoiseFB; + R->RNG >>= 1; + R->Output[3] = R->RNG & 1; + R->Count[3] += R->Period[3]; + if (R->Output[3]) vol[3] += R->Period[3]; + } + if (R->Output[3]) vol[3] -= R->Count[3]; + + left -= nextevent; + } while (left > 0); + + out = vol[0] * R->Volume[0] + vol[1] * R->Volume[1] + + vol[2] * R->Volume[2] + vol[3] * R->Volume[3]; + + if (out > MAX_OUTPUT * STEP) out = MAX_OUTPUT * STEP; + + out /= STEP; // will be optimized to shift + if(stereo) { + // only left channel for stereo (will be copied to right by ym2612 mixing code) + *buffer += out; + buffer+=2; + } else + *buffer++ += out; + + length--; + } +} + + +static void SN76496_set_clock(struct SN76496 *R,int clock) +{ + + /* the base clock for the tone generators is the chip clock divided by 16; */ + /* for the noise generator, it is clock / 256. */ + /* Here we calculate the number of steps which happen during one sample */ + /* at the given sample rate. No. of events = sample rate / (clock/16). */ + /* STEP is a multiplier used to turn the fraction into a fixed point */ + /* number. */ + R->UpdateStep = ((double)STEP * R->SampleRate * 16) / clock; +} + + +static void SN76496_set_gain(struct SN76496 *R,int gain) +{ + int i; + double out; + + + gain &= 0xff; + + /* increase max output basing on gain (0.2 dB per step) */ + out = MAX_OUTPUT / 3; + while (gain-- > 0) + out *= 1.023292992; /* = (10 ^ (0.2/20)) */ + + /* build volume table (2dB per step) */ + for (i = 0;i < 15;i++) + { + /* limit volume to avoid clipping */ + if (out > MAX_OUTPUT / 3) R->VolTable[i] = MAX_OUTPUT / 3; + else R->VolTable[i] = out; + + out /= 1.258925412; /* = 10 ^ (2/20) = 2dB */ + } + R->VolTable[15] = 0; +} + + +//static +int SN76496_init(int clock,int sample_rate) +{ + struct SN76496 *R = &ono_sn; + int i; + + //R->Channel = stream_create(0,1, sample_rate,R,SN76496Update); + sn76496_regs = R->Register; + + R->SampleRate = sample_rate; + SN76496_set_clock(R,clock); + + for (i = 0;i < 4;i++) R->Volume[i] = 0; + + R->LastRegister = 0; + for (i = 0;i < 8;i+=2) + { + R->Register[i] = 0; + R->Register[i + 1] = 0x0f; /* volume = 0 */ + } + + for (i = 0;i < 4;i++) + { + R->Output[i] = 0; + R->Period[i] = R->Count[i] = R->UpdateStep; + } + R->RNG = NG_PRESET; + R->Output[3] = R->RNG & 1; + + // added + SN76496_set_gain(R, 0); + + return 0; +} + diff --git a/Pico/sound/sn76496.h b/Pico/sound/sn76496.h new file mode 100644 index 00000000..e0de6eda --- /dev/null +++ b/Pico/sound/sn76496.h @@ -0,0 +1,8 @@ +#ifndef SN76496_H +#define SN76496_H + +void SN76496Write(int data); +void SN76496Update(short *buffer,int length,int stereo); +int SN76496_init(int clock,int sample_rate); + +#endif diff --git a/Pico/sound/sound.c b/Pico/sound/sound.c new file mode 100644 index 00000000..d5802bdc --- /dev/null +++ b/Pico/sound/sound.c @@ -0,0 +1,390 @@ +// This is part of Pico Library + +// (c) Copyright 2004 Dave, All rights reserved. +// (c) Copyright 2006 notaz, All rights reserved. +// Free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + + +#include +#include "sound.h" +#include "ym2612.h" +#include "sn76496.h" + +#ifndef __GNUC__ +#pragma warning (disable:4244) +#endif + +#if defined(_USE_MZ80) +#include "../../cpu/mz80/mz80.h" +#elif defined(_USE_DRZ80) +#include "../../cpu/DrZ80/drz80.h" +#endif + +#include "../PicoInt.h" + + +//int z80CycleAim = 0; + +// dac +short *dac_out; +unsigned short dac_info[312]; // pppppppp ppppllll, p - pos in buff, l - length to write for this sample + +// for Pico +int PsndRate=0; +int PsndLen=0; // number of mono samples, multiply by 2 for stereo +short *PsndOut=NULL; // PCM data buffer + +// from ym2612.c +extern int *ym2612_dacen; +extern INT32 *ym2612_dacout; +void YM2612TimerHandler(int c,int cnt); + +// sn76496 +extern int *sn76496_regs; + + +static void dac_recalculate() +{ + int i, dac_cnt, pos, len, lines = Pico.m.pal ? 312 : 262, mid = Pico.m.pal ? 68 : 93; + + if(PsndLen <= lines) { + // shrinking algo + dac_cnt = 0;//lines - PsndLen; + len=1; pos=0; + dac_info[225] = 1; + + for(i=226; i != 225; i++) { + if (i >= lines) i = 0; + len = 0; + if(dac_cnt < 0) { + len=1; + pos++; + dac_cnt += lines; + } + dac_cnt -= PsndLen; + dac_info[i] = (pos<<4)|len; + } + } else { + // stretching + dac_cnt = PsndLen/2; + pos=0; + for(i = 225; i != 224; i++) { + if (i >= lines) i = 0; + len=0; + while(dac_cnt >= 0) { + dac_cnt -= lines; + len++; + } + if (i == mid) // midpoint + while(pos+len < PsndLen/2) { + dac_cnt -= lines; + len++; + } + dac_cnt += PsndLen; + dac_info[i] = (pos<<4)|len; + pos+=len; + } + // last sample + for(len = 0, i = pos; i < PsndLen; i++) len++; + dac_info[224] = (pos<<4)|len; + } +// dprintf("rate is %i, len %i", PsndRate, PsndLen); +// for(i=0; i < lines; i++) +// dprintf("%03i : %03i : %i", i, dac_info[i]>>4, dac_info[i]&0xf); +//exit(8); +} + + +void sound_reset() +{ + extern int z80stopCycle; + void *ym2612_regs; + + // init even if we are not going to use them, just in case we ever enable it + YM2612Init(Pico.m.pal ? OSC_PAL/7 : OSC_NTSC/7, PsndRate); + // also clear the internal registers+addr line + ym2612_regs = YM2612GetRegs(); + memset(ym2612_regs, 0, 0x200+4); + + SN76496_init(Pico.m.pal ? OSC_PAL/15 : OSC_NTSC/15, PsndRate); + + // calculate PsndLen + PsndLen=PsndRate/(Pico.m.pal ? 50 : 60); + + // recalculate dac info + dac_recalculate(); + z80stopCycle = 0; +} + + +// to be called after changing sound rate or chips +void sound_rerate() +{ + unsigned int state[28]; + + YM2612Init(Pico.m.pal ? OSC_PAL/7 : OSC_NTSC/7, PsndRate); + // feed it back it's own registers, just like after loading state + YM2612PicoStateLoad(); + + memcpy(state, sn76496_regs, 28*4); // remember old state + SN76496_init(Pico.m.pal ? OSC_PAL/15 : OSC_NTSC/15, PsndRate); + memcpy(sn76496_regs, state, 28*4); // restore old state + + // calculate PsndLen + PsndLen=PsndRate/(Pico.m.pal ? 50 : 60); + + // recalculate dac info + dac_recalculate(); +} + + +// This is called once per raster (aka line), but not necessarily for every line +int sound_timers_and_dac(int raster) +{ + if(raster >= 0 && PsndOut && (PicoOpt&1) && *ym2612_dacen) { + short dout = (short) *ym2612_dacout; + int pos=dac_info[raster], len=pos&0xf; + short *d; + pos>>=4; + + if(PicoOpt&8) { // only left channel for stereo (will be copied to right by ym2612 mixing code) + d=PsndOut+pos*2; + while(len--) { *d = dout; d += 2; } + } else { + d=PsndOut+pos; + while(len--) *d++ = dout; + } + } + + //dprintf("s: %03i", raster); + + // Our raster lasts 63.61323/64.102564 microseconds (NTSC/PAL) + YM2612PicoTick(1); + + return 0; +} + + +int sound_render(int offset, int length) +{ + int stereo = (PicoOpt & 8) >> 3; + offset <<= stereo; + + // PSG + if(PicoOpt & 2) + SN76496Update(PsndOut+offset, length, stereo); + + // Add in the stereo FM buffer + if(PicoOpt & 1) { + YM2612UpdateOne(PsndOut+offset, length, stereo); + } else { + // YM2612 upmixes to stereo, so we have to do this manually here + int i; + short *s = PsndOut+offset; + for (i = 0; i < length; i++) { + *(s+1) = *s; s+=2; + } + } + + return 0; +} + + + +#if defined(_USE_MZ80) + +// memhandlers for mz80 core +unsigned char mz80_read(UINT32 a, struct MemoryReadByte *w) { return z80_read(a); } +void mz80_write(UINT32 a, UINT8 d, struct MemoryWriteByte *w) { z80_write(d, a); } + +// structures for mz80 core +static struct MemoryReadByte mz80_mem_read[]= +{ + {0x0000,0xffff,mz80_read}, + {(UINT32) -1,(UINT32) -1,NULL} +}; +static struct MemoryWriteByte mz80_mem_write[]= +{ + {0x0000,0xffff,mz80_write}, + {(UINT32) -1,(UINT32) -1,NULL} +}; +static struct z80PortRead mz80_io_read[] ={ + {(UINT16) -1,(UINT16) -1,NULL} +}; +static struct z80PortWrite mz80_io_write[]={ + {(UINT16) -1,(UINT16) -1,NULL} +}; + +#elif defined(_USE_DRZ80) + +static struct DrZ80 drZ80; + +static unsigned int DrZ80_rebasePC(unsigned short a) +{ + drZ80.Z80PC_BASE = (unsigned int) Pico.zram; + return drZ80.Z80PC_BASE + a; +} + +static unsigned int DrZ80_rebaseSP(unsigned short a) +{ + drZ80.Z80SP_BASE = (unsigned int) Pico.zram; + return drZ80.Z80SP_BASE + a; +} + +static unsigned char DrZ80_in(unsigned short p) +{ + return 0xff; +} + +static void DrZ80_out(unsigned short p,unsigned char d) +{ +} + +static void DrZ80_irq_callback() +{ + drZ80.Z80_IRQ = 0; // lower irq when accepted +} + +#endif + +// z80 functionality wrappers +void z80_init() +{ +#if defined(_USE_MZ80) + struct mz80context z80; + + // z80 + mz80init(); + // Modify the default context + mz80GetContext(&z80); + + // point mz80 stuff + z80.z80Base=Pico.zram; + z80.z80MemRead=mz80_mem_read; + z80.z80MemWrite=mz80_mem_write; + z80.z80IoRead=mz80_io_read; + z80.z80IoWrite=mz80_io_write; + + mz80SetContext(&z80); + +#elif defined(_USE_DRZ80) + + memset(&drZ80, 0, sizeof(struct DrZ80)); + drZ80.z80_rebasePC=DrZ80_rebasePC; + drZ80.z80_rebaseSP=DrZ80_rebaseSP; + drZ80.z80_read8 =z80_read; + drZ80.z80_read16 =z80_read16; + drZ80.z80_write8 =z80_write; + drZ80.z80_write16 =z80_write16; + drZ80.z80_in =DrZ80_in; + drZ80.z80_out =DrZ80_out; + drZ80.z80_irq_callback=DrZ80_irq_callback; +#endif +} + +void z80_reset() +{ +#if defined(_USE_MZ80) + mz80reset(); +#elif defined(_USE_DRZ80) + memset(&drZ80, 0, 0x54); + drZ80.Z80F = (1<<2); // set ZFlag + drZ80.Z80F2 = (1<<2); // set ZFlag + drZ80.Z80IX = 0xFFFF << 16; + drZ80.Z80IY = 0xFFFF << 16; + drZ80.Z80IM = 0; // 1? + drZ80.Z80PC = drZ80.z80_rebasePC(0); + drZ80.Z80SP = drZ80.z80_rebaseSP(0x2000); // 0xf000 ? +#endif + Pico.m.z80_fakeval = 0; // for faking when Z80 is disabled +} + +void z80_resetCycles() +{ +#if defined(_USE_MZ80) + mz80GetElapsedTicks(1); +#endif +} + +void z80_int() +{ +#if defined(_USE_MZ80) + mz80int(0); +#elif defined(_USE_DRZ80) + drZ80.z80irqvector = 0xFF; // default IRQ vector RST opcode + drZ80.Z80_IRQ = 1; +#endif +} + +// returns number of cycles actually executed +int z80_run(int cycles) +{ +#if defined(_USE_MZ80) + int ticks_pre = mz80GetElapsedTicks(0); + mz80exec(cycles); + return mz80GetElapsedTicks(0) - ticks_pre; +#elif defined(_USE_DRZ80) + return cycles - DrZ80Run(&drZ80, cycles); +#else + return cycles; +#endif +} + +void z80_pack(unsigned char *data) +{ +#if defined(_USE_MZ80) + struct mz80context mz80; + *(int *)data = 0x00005A6D; // "mZ" + mz80GetContext(&mz80); + memcpy(data+4, &mz80.z80clockticks, sizeof(mz80)-5*4); // don't save base&memhandlers +#elif defined(_USE_DRZ80) + *(int *)data = 0x015A7244; // "DrZ" v1 + drZ80.Z80PC = drZ80.z80_rebasePC(drZ80.Z80PC-drZ80.Z80PC_BASE); + drZ80.Z80SP = drZ80.z80_rebaseSP(drZ80.Z80SP-drZ80.Z80SP_BASE); + memcpy(data+4, &drZ80, 0x54); +#endif +} + +void z80_unpack(unsigned char *data) +{ +#if defined(_USE_MZ80) + if(*(int *)data == 0x00005A6D) { // "mZ" save? + struct mz80context mz80; + mz80GetContext(&mz80); + memcpy(&mz80.z80clockticks, data+4, sizeof(mz80)-5*4); + mz80SetContext(&mz80); + } else { + z80_reset(); + z80_int(); + } +#elif defined(_USE_DRZ80) + if(*(int *)data == 0x015A7244) { // "DrZ" v1 save? + memcpy(&drZ80, data+4, 0x54); + // update bases + drZ80.Z80PC = drZ80.z80_rebasePC(drZ80.Z80PC-drZ80.Z80PC_BASE); + drZ80.Z80SP = drZ80.z80_rebaseSP(drZ80.Z80SP-drZ80.Z80SP_BASE); + } else { + z80_reset(); + drZ80.Z80IM = 1; + z80_int(); // try to goto int handler, maybe we won't execute trash there? + } +#endif +} + +void z80_exit() +{ +#if defined(_USE_MZ80) + mz80shutdown(); +#endif +} + +#if defined(__DEBUG_PRINT) || defined(WIN32) +void z80_debug(char *dstr) +{ +#if defined(_USE_DRZ80) + sprintf(dstr, "%sZ80 state: PC: %04x SP: %04x\n", dstr, drZ80.Z80PC-drZ80.Z80PC_BASE, drZ80.Z80SP-drZ80.Z80SP_BASE); +#endif +} +#endif diff --git a/Pico/sound/sound.h b/Pico/sound/sound.h new file mode 100644 index 00000000..8335fb22 --- /dev/null +++ b/Pico/sound/sound.h @@ -0,0 +1,28 @@ +// This is part of Pico Library + +// (c) Copyright 2004 Dave, All rights reserved. +// (c) Copyright 2006 notaz, All rights reserved. +// Free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + + +#ifdef __cplusplus +extern "C" { +#endif + +int sound_timers_and_dac(int raster); +int sound_render(int offset, int length); + +//int YM2612PicoTick(int n); + +// z80 functionality wrappers +void z80_init(); +void z80_resetCycles(); +void z80_int(); +int z80_run(int cycles); +void z80_exit(); + +#ifdef __cplusplus +} // End of extern "C" +#endif diff --git a/Pico/sound/ym2612.c b/Pico/sound/ym2612.c new file mode 100644 index 00000000..56e53127 --- /dev/null +++ b/Pico/sound/ym2612.c @@ -0,0 +1,1899 @@ +/* +** This is a bunch of remains of original fm.c from MAME project. All stuff +** unrelated to ym2612 was removed, multiple chip support was removed, +** some parts of code were slightly rewritten and tied to the emulator. +** +** SSG-EG was also removed, because it's rarely used, Sega2.doc even does not +** document it ("proprietary") and tells to write 0 to SSG-EG control register. +*/ + +/* +** +** File: fm.c -- software implementation of Yamaha FM sound generator +** +** Copyright (C) 2001, 2002, 2003 Jarek Burczynski (bujar at mame dot net) +** Copyright (C) 1998 Tatsuyuki Satoh , MultiArcadeMachineEmulator development +** +** Version 1.4 (final beta) +** +*/ + +/* +** History: +** +** 03-08-2003 Jarek Burczynski: +** - fixed YM2608 initial values (after the reset) +** - fixed flag and irqmask handling (YM2608) +** - fixed BUFRDY flag handling (YM2608) +** +** 14-06-2003 Jarek Burczynski: +** - implemented all of the YM2608 status register flags +** - implemented support for external memory read/write via YM2608 +** - implemented support for deltat memory limit register in YM2608 emulation +** +** 22-05-2003 Jarek Burczynski: +** - fixed LFO PM calculations (copy&paste bugfix) +** +** 08-05-2003 Jarek Burczynski: +** - fixed SSG support +** +** 22-04-2003 Jarek Burczynski: +** - implemented 100% correct LFO generator (verified on real YM2610 and YM2608) +** +** 15-04-2003 Jarek Burczynski: +** - added support for YM2608's register 0x110 - status mask +** +** 01-12-2002 Jarek Burczynski: +** - fixed register addressing in YM2608, YM2610, YM2610B chips. (verified on real YM2608) +** The addressing patch used for early Neo-Geo games can be removed now. +** +** 26-11-2002 Jarek Burczynski, Nicola Salmoria: +** - recreated YM2608 ADPCM ROM using data from real YM2608's output which leads to: +** - added emulation of YM2608 drums. +** - output of YM2608 is two times lower now - same as YM2610 (verified on real YM2608) +** +** 16-08-2002 Jarek Burczynski: +** - binary exact Envelope Generator (verified on real YM2203); +** identical to YM2151 +** - corrected 'off by one' error in feedback calculations (when feedback is off) +** - corrected connection (algorithm) calculation (verified on real YM2203 and YM2610) +** +** 18-12-2001 Jarek Burczynski: +** - added SSG-EG support (verified on real YM2203) +** +** 12-08-2001 Jarek Burczynski: +** - corrected ym_sin_tab and ym_tl_tab data (verified on real chip) +** - corrected feedback calculations (verified on real chip) +** - corrected phase generator calculations (verified on real chip) +** - corrected envelope generator calculations (verified on real chip) +** - corrected FM volume level (YM2610 and YM2610B). +** - changed YMxxxUpdateOne() functions (YM2203, YM2608, YM2610, YM2610B, YM2612) : +** this was needed to calculate YM2610 FM channels output correctly. +** (Each FM channel is calculated as in other chips, but the output of the channel +** gets shifted right by one *before* sending to accumulator. That was impossible to do +** with previous implementation). +** +** 23-07-2001 Jarek Burczynski, Nicola Salmoria: +** - corrected YM2610 ADPCM type A algorithm and tables (verified on real chip) +** +** 11-06-2001 Jarek Burczynski: +** - corrected end of sample bug in ADPCMA_calc_cha(). +** Real YM2610 checks for equality between current and end addresses (only 20 LSB bits). +** +** 08-12-98 hiro-shi: +** rename ADPCMA -> ADPCMB, ADPCMB -> ADPCMA +** move ROM limit check.(CALC_CH? -> 2610Write1/2) +** test program (ADPCMB_TEST) +** move ADPCM A/B end check. +** ADPCMB repeat flag(no check) +** change ADPCM volume rate (8->16) (32->48). +** +** 09-12-98 hiro-shi: +** change ADPCM volume. (8->16, 48->64) +** replace ym2610 ch0/3 (YM-2610B) +** change ADPCM_SHIFT (10->8) missing bank change 0x4000-0xffff. +** add ADPCM_SHIFT_MASK +** change ADPCMA_DECODE_MIN/MAX. +*/ + + + + +/************************************************************************/ +/* comment of hiro-shi(Hiromitsu Shioya) */ +/* YM2610(B) = OPN-B */ +/* YM2610 : PSG:3ch FM:4ch ADPCM(18.5KHz):6ch DeltaT ADPCM:1ch */ +/* YM2610B : PSG:3ch FM:6ch ADPCM(18.5KHz):6ch DeltaT ADPCM:1ch */ +/************************************************************************/ + +//#include + +#include +#include + +#include "ym2612.h" + +#ifndef EXTERNAL_YM2612 +#include +// let it be 1 global to simplify things +static YM2612 ym2612; + +#else +extern YM2612 *ym2612_940; +extern int *mix_buffer; +#define ym2612 (*ym2612_940) + +#endif + + +#ifndef __GNUC__ +#pragma warning (disable:4100) // unreferenced formal parameter +#pragma warning (disable:4244) +#pragma warning (disable:4245) // signed/unsigned in conversion +#pragma warning (disable:4710) +#pragma warning (disable:4018) // signed/unsigned +#endif + +#ifndef INLINE +#define INLINE static __inline +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + + +/* globals */ + +#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ +#define EG_SH 16 /* 16.16 fixed point (envelope generator timing) */ +#define LFO_SH 25 /* 7.25 fixed point (LFO calculations) */ +#define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */ + +#define ENV_BITS 10 +#define ENV_LEN (1< max ) val = max; \ + else if ( val < min ) val = min; \ +} + + +/* TL_TAB_LEN is calculated as: +* 13 - sinus amplitude bits (Y axis) +* 2 - sinus sign bit (Y axis) +* TL_RES_LEN - sinus resolution (X axis) +*/ +//#define TL_TAB_LEN (13*2*TL_RES_LEN) +#define TL_TAB_LEN (13*TL_RES_LEN*256/8) // 106496*2 +UINT16 ym_tl_tab[TL_TAB_LEN]; + +/* ~3K wasted but oh well */ +UINT16 ym_tl_tab2[13*TL_RES_LEN]; + +#define ENV_QUIET (2*13*TL_RES_LEN/8) + +/* sin waveform table in 'decibel' scale (use only period/4 values) */ +static UINT16 ym_sin_tab[256]; + +/* sustain level table (3dB per step) */ +/* bit0, bit1, bit2, bit3, bit4, bit5, bit6 */ +/* 1, 2, 4, 8, 16, 32, 64 (value)*/ +/* 0.75, 1.5, 3, 6, 12, 24, 48 (dB)*/ + +/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/ +#define SC(db) (UINT32) ( db * (4.0/ENV_STEP) ) +static const UINT32 sl_table[16]={ + SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7), + SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31) +}; +#undef SC + + +#if 0 +#define RATE_STEPS (8) +static const UINT8 eg_inc[19*RATE_STEPS]={ + +/*cycle:0 1 2 3 4 5 6 7*/ + +/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..11 0 (increment by 0 or 1) */ +/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..11 1 */ +/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..11 2 */ +/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..11 3 */ + +/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 12 0 (increment by 1) */ +/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 12 1 */ +/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 12 2 */ +/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 12 3 */ + +/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 13 0 (increment by 2) */ +/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 13 1 */ +/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 13 2 */ +/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 13 3 */ + +/*12 */ 4,4, 4,4, 4,4, 4,4, /* rate 14 0 (increment by 4) */ +/*13 */ 4,4, 4,8, 4,4, 4,8, /* rate 14 1 */ +/*14 */ 4,8, 4,8, 4,8, 4,8, /* rate 14 2 */ +/*15 */ 4,8, 8,8, 4,8, 8,8, /* rate 14 3 */ + +/*16 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 8) */ +/*17 */ 16,16,16,16,16,16,16,16, /* rates 15 2, 15 3 for attack */ +/*18 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */ +}; +#endif + + +#define PACK(a0,a1,a2,a3,a4,a5,a6,a7) ((a7<<21)|(a6<<18)|(a5<<15)|(a4<<12)|(a3<<9)|(a2<<6)|(a1<<3)|(a0<<0)) +static const UINT32 eg_inc_pack[19] = +{ +/* 0 */ PACK(0,1,0,1,0,1,0,1), /* rates 00..11 0 (increment by 0 or 1) */ +/* 1 */ PACK(0,1,0,1,1,1,0,1), /* rates 00..11 1 */ +/* 2 */ PACK(0,1,1,1,0,1,1,1), /* rates 00..11 2 */ +/* 3 */ PACK(0,1,1,1,1,1,1,1), /* rates 00..11 3 */ + +/* 4 */ PACK(1,1,1,1,1,1,1,1), /* rate 12 0 (increment by 1) */ +/* 5 */ PACK(1,1,1,2,1,1,1,2), /* rate 12 1 */ +/* 6 */ PACK(1,2,1,2,1,2,1,2), /* rate 12 2 */ +/* 7 */ PACK(1,2,2,2,1,2,2,2), /* rate 12 3 */ + +/* 8 */ PACK(2,2,2,2,2,2,2,2), /* rate 13 0 (increment by 2) */ +/* 9 */ PACK(2,2,2,3,2,2,2,3), /* rate 13 1 */ +/*10 */ PACK(2,3,2,3,2,3,2,3), /* rate 13 2 */ +/*11 */ PACK(2,3,3,3,2,3,3,3), /* rate 13 3 */ + +/*12 */ PACK(3,3,3,3,3,3,3,3), /* rate 14 0 (increment by 4) */ +/*13 */ PACK(3,3,3,4,3,3,3,4), /* rate 14 1 */ +/*14 */ PACK(3,4,3,4,3,4,3,4), /* rate 14 2 */ +/*15 */ PACK(3,4,4,4,3,4,4,4), /* rate 14 3 */ + +/*16 */ PACK(4,4,4,4,4,4,4,4), /* rates 15 0, 15 1, 15 2, 15 3 (increment by 8) */ +/*17 */ PACK(5,5,5,5,5,5,5,5), /* rates 15 2, 15 3 for attack */ +/*18 */ PACK(0,0,0,0,0,0,0,0), /* infinity rates for attack and decay(s) */ +}; + + +//#define O(a) (a*RATE_STEPS) +#define O(a) a + +/*note that there is no O(17) in this table - it's directly in the code */ +static const UINT8 eg_rate_select[32+64+32]={ /* Envelope Generator rates (32 + 64 rates + 32 RKS) */ +/* 32 infinite time rates */ +O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), +O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), +O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), +O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), + +/* rates 00-11 */ +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), + +/* rate 12 */ +O( 4),O( 5),O( 6),O( 7), + +/* rate 13 */ +O( 8),O( 9),O(10),O(11), + +/* rate 14 */ +O(12),O(13),O(14),O(15), + +/* rate 15 */ +O(16),O(16),O(16),O(16), + +/* 32 dummy rates (same as 15 3) */ +O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16), +O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16), +O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16), +O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16) + +}; +#undef O + +/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15*/ +/*shift 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0 */ +/*mask 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0, 0, 0 */ + +#define O(a) (a*1) +static const UINT8 eg_rate_shift[32+64+32]={ /* Envelope Generator counter shifts (32 + 64 rates + 32 RKS) */ +/* 32 infinite time rates */ +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), + +/* rates 00-11 */ +O(11),O(11),O(11),O(11), +O(10),O(10),O(10),O(10), +O( 9),O( 9),O( 9),O( 9), +O( 8),O( 8),O( 8),O( 8), +O( 7),O( 7),O( 7),O( 7), +O( 6),O( 6),O( 6),O( 6), +O( 5),O( 5),O( 5),O( 5), +O( 4),O( 4),O( 4),O( 4), +O( 3),O( 3),O( 3),O( 3), +O( 2),O( 2),O( 2),O( 2), +O( 1),O( 1),O( 1),O( 1), +O( 0),O( 0),O( 0),O( 0), + +/* rate 12 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 13 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 14 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 15 */ +O( 0),O( 0),O( 0),O( 0), + +/* 32 dummy rates (same as 15 3) */ +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0) + +}; +#undef O + +static const UINT8 dt_tab[4 * 32]={ +/* this is YM2151 and YM2612 phase increment data (in 10.10 fixed point format)*/ +/* FD=0 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* FD=1 */ + 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8, +/* FD=2 */ + 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, + 5, 6, 6, 7, 8, 8, 9,10,11,12,13,14,16,16,16,16, +/* FD=3 */ + 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, + 8 , 8, 9,10,11,12,13,14,16,17,19,20,22,22,22,22 +}; + + +/* OPN key frequency number -> key code follow table */ +/* fnum higher 4bit -> keycode lower 2bit */ +static const UINT8 opn_fktable[16] = {0,0,0,0,0,0,0,1,2,3,3,3,3,3,3,3}; + + +/* 8 LFO speed parameters */ +/* each value represents number of samples that one LFO level will last for */ +static const UINT32 lfo_samples_per_step[8] = {108, 77, 71, 67, 62, 44, 8, 5}; + + + +/*There are 4 different LFO AM depths available, they are: + 0 dB, 1.4 dB, 5.9 dB, 11.8 dB + Here is how it is generated (in EG steps): + + 11.8 dB = 0, 2, 4, 6, 8, 10,12,14,16...126,126,124,122,120,118,....4,2,0 + 5.9 dB = 0, 1, 2, 3, 4, 5, 6, 7, 8....63, 63, 62, 61, 60, 59,.....2,1,0 + 1.4 dB = 0, 0, 0, 0, 1, 1, 1, 1, 2,...15, 15, 15, 15, 14, 14,.....0,0,0 + + (1.4 dB is loosing precision as you can see) + + It's implemented as generator from 0..126 with step 2 then a shift + right N times, where N is: + 8 for 0 dB + 3 for 1.4 dB + 1 for 5.9 dB + 0 for 11.8 dB +*/ +static const UINT8 lfo_ams_depth_shift[4] = {8, 3, 1, 0}; + + + +/*There are 8 different LFO PM depths available, they are: + 0, 3.4, 6.7, 10, 14, 20, 40, 80 (cents) + + Modulation level at each depth depends on F-NUMBER bits: 4,5,6,7,8,9,10 + (bits 8,9,10 = FNUM MSB from OCT/FNUM register) + + Here we store only first quarter (positive one) of full waveform. + Full table (lfo_pm_table) containing all 128 waveforms is build + at run (init) time. + + One value in table below represents 4 (four) basic LFO steps + (1 PM step = 4 AM steps). + + For example: + at LFO SPEED=0 (which is 108 samples per basic LFO step) + one value from "lfo_pm_output" table lasts for 432 consecutive + samples (4*108=432) and one full LFO waveform cycle lasts for 13824 + samples (32*432=13824; 32 because we store only a quarter of whole + waveform in the table below) +*/ +static const UINT8 lfo_pm_output[7*8][8]={ /* 7 bits meaningful (of F-NUMBER), 8 LFO output levels per one depth (out of 32), 8 LFO depths */ +/* FNUM BIT 4: 000 0001xxxx */ +/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 1 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 2 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 3 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 4 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 5 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 6 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 7 */ {0, 0, 0, 0, 1, 1, 1, 1}, + +/* FNUM BIT 5: 000 0010xxxx */ +/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 1 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 2 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 3 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 4 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 5 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 6 */ {0, 0, 0, 0, 1, 1, 1, 1}, +/* DEPTH 7 */ {0, 0, 1, 1, 2, 2, 2, 3}, + +/* FNUM BIT 6: 000 0100xxxx */ +/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 1 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 2 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 3 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 4 */ {0, 0, 0, 0, 0, 0, 0, 1}, +/* DEPTH 5 */ {0, 0, 0, 0, 1, 1, 1, 1}, +/* DEPTH 6 */ {0, 0, 1, 1, 2, 2, 2, 3}, +/* DEPTH 7 */ {0, 0, 2, 3, 4, 4, 5, 6}, + +/* FNUM BIT 7: 000 1000xxxx */ +/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 1 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 2 */ {0, 0, 0, 0, 0, 0, 1, 1}, +/* DEPTH 3 */ {0, 0, 0, 0, 1, 1, 1, 1}, +/* DEPTH 4 */ {0, 0, 0, 1, 1, 1, 1, 2}, +/* DEPTH 5 */ {0, 0, 1, 1, 2, 2, 2, 3}, +/* DEPTH 6 */ {0, 0, 2, 3, 4, 4, 5, 6}, +/* DEPTH 7 */ {0, 0, 4, 6, 8, 8, 0xa, 0xc}, + +/* FNUM BIT 8: 001 0000xxxx */ +/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 1 */ {0, 0, 0, 0, 1, 1, 1, 1}, +/* DEPTH 2 */ {0, 0, 0, 1, 1, 1, 2, 2}, +/* DEPTH 3 */ {0, 0, 1, 1, 2, 2, 3, 3}, +/* DEPTH 4 */ {0, 0, 1, 2, 2, 2, 3, 4}, +/* DEPTH 5 */ {0, 0, 2, 3, 4, 4, 5, 6}, +/* DEPTH 6 */ {0, 0, 4, 6, 8, 8, 0xa, 0xc}, +/* DEPTH 7 */ {0, 0, 8, 0xc,0x10,0x10,0x14,0x18}, + +/* FNUM BIT 9: 010 0000xxxx */ +/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 1 */ {0, 0, 0, 0, 2, 2, 2, 2}, +/* DEPTH 2 */ {0, 0, 0, 2, 2, 2, 4, 4}, +/* DEPTH 3 */ {0, 0, 2, 2, 4, 4, 6, 6}, +/* DEPTH 4 */ {0, 0, 2, 4, 4, 4, 6, 8}, +/* DEPTH 5 */ {0, 0, 4, 6, 8, 8, 0xa, 0xc}, +/* DEPTH 6 */ {0, 0, 8, 0xc,0x10,0x10,0x14,0x18}, +/* DEPTH 7 */ {0, 0,0x10,0x18,0x20,0x20,0x28,0x30}, + +/* FNUM BIT10: 100 0000xxxx */ +/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 1 */ {0, 0, 0, 0, 4, 4, 4, 4}, +/* DEPTH 2 */ {0, 0, 0, 4, 4, 4, 8, 8}, +/* DEPTH 3 */ {0, 0, 4, 4, 8, 8, 0xc, 0xc}, +/* DEPTH 4 */ {0, 0, 4, 8, 8, 8, 0xc,0x10}, +/* DEPTH 5 */ {0, 0, 8, 0xc,0x10,0x10,0x14,0x18}, +/* DEPTH 6 */ {0, 0,0x10,0x18,0x20,0x20,0x28,0x30}, +/* DEPTH 7 */ {0, 0,0x20,0x30,0x40,0x40,0x50,0x60}, + +}; + +/* all 128 LFO PM waveforms */ +static INT32 lfo_pm_table[128*8*32]; /* 128 combinations of 7 bits meaningful (of F-NUMBER), 8 LFO depths, 32 LFO output levels per one depth */ + +/* there are 2048 FNUMs that can be generated using FNUM/BLK registers + but LFO works with one more bit of a precision so we really need 4096 elements */ +static UINT32 fn_table[4096]; /* fnumber->increment counter */ + +static int g_lfo_ampm = 0; + +/* register number to channel number , slot offset */ +#define OPN_CHAN(N) (N&3) +#define OPN_SLOT(N) ((N>>2)&3) + +/* slot number */ +#define SLOT1 0 +#define SLOT2 2 +#define SLOT3 1 +#define SLOT4 3 + + +/* OPN Mode Register Write */ +INLINE void set_timers( int v ) +{ + /* b7 = CSM MODE */ + /* b6 = 3 slot mode */ + /* b5 = reset b */ + /* b4 = reset a */ + /* b3 = timer enable b */ + /* b2 = timer enable a */ + /* b1 = load b */ + /* b0 = load a */ + ym2612.OPN.ST.mode = v; + + /* reset Timer b flag */ + if( v & 0x20 ) + ym2612.OPN.ST.status &= ~2; + + /* reset Timer a flag */ + if( v & 0x10 ) + ym2612.OPN.ST.status &= ~1; +} + + +INLINE void FM_KEYON(FM_CH *CH , int s ) +{ + FM_SLOT *SLOT = &CH->SLOT[s]; + if( !SLOT->key ) + { + SLOT->key = 1; + SLOT->phase = 0; /* restart Phase Generator */ + SLOT->state = EG_ATT; /* phase -> Attack */ + } +} + +INLINE void FM_KEYOFF(FM_CH *CH , int s ) +{ + FM_SLOT *SLOT = &CH->SLOT[s]; + if( SLOT->key ) + { + SLOT->key = 0; + if (SLOT->state>EG_REL) + SLOT->state = EG_REL;/* phase -> Release */ + } +} + + +/* set detune & multiple */ +INLINE void set_det_mul(FM_CH *CH, FM_SLOT *SLOT, int v) +{ + SLOT->mul = (v&0x0f)? (v&0x0f)*2 : 1; + SLOT->DT = ym2612.OPN.ST.dt_tab[(v>>4)&7]; + CH->SLOT[SLOT1].Incr=-1; +} + +/* set total level */ +INLINE void set_tl(FM_SLOT *SLOT, int v) +{ + SLOT->tl = (v&0x7f)<<(ENV_BITS-7); /* 7bit TL */ +} + +/* set attack rate & key scale */ +INLINE void set_ar_ksr(FM_CH *CH, FM_SLOT *SLOT, int v) +{ + UINT8 old_KSR = SLOT->KSR; + + SLOT->ar = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0; + + SLOT->KSR = 3-(v>>6); + if (SLOT->KSR != old_KSR) + { + CH->SLOT[SLOT1].Incr=-1; + } + else + { + int eg_sh_ar, eg_sel_ar; + + /* refresh Attack rate */ + if ((SLOT->ar + SLOT->ksr) < 32+62) + { + eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } + else + { + eg_sh_ar = 0; + eg_sel_ar = 17; + } + + SLOT->eg_pack_ar = eg_inc_pack[eg_sel_ar] | (eg_sh_ar<<24); + } +} + +/* set decay rate */ +INLINE void set_dr(FM_SLOT *SLOT, int v) +{ + int eg_sh_d1r, eg_sel_d1r; + + SLOT->d1r = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0; + + eg_sh_d1r = eg_rate_shift [SLOT->d1r + SLOT->ksr]; + eg_sel_d1r= eg_rate_select[SLOT->d1r + SLOT->ksr]; + + SLOT->eg_pack_d1r = eg_inc_pack[eg_sel_d1r] | (eg_sh_d1r<<24); +} + +/* set sustain rate */ +INLINE void set_sr(FM_SLOT *SLOT, int v) +{ + int eg_sh_d2r, eg_sel_d2r; + + SLOT->d2r = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0; + + eg_sh_d2r = eg_rate_shift [SLOT->d2r + SLOT->ksr]; + eg_sel_d2r= eg_rate_select[SLOT->d2r + SLOT->ksr]; + + SLOT->eg_pack_d2r = eg_inc_pack[eg_sel_d2r] | (eg_sh_d2r<<24); +} + +/* set release rate */ +INLINE void set_sl_rr(FM_SLOT *SLOT, int v) +{ + int eg_sh_rr, eg_sel_rr; + + SLOT->sl = sl_table[ v>>4 ]; + + SLOT->rr = 34 + ((v&0x0f)<<2); + + eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr]; + eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr]; + + SLOT->eg_pack_rr = eg_inc_pack[eg_sel_rr] | (eg_sh_rr<<24); +} + + + +INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm) +{ + int ret, sin = (phase>>16) + (pm>>1); + int neg = sin & 0x200; + if (sin & 0x100) sin ^= 0xff; + sin&=0xff; + env&=~1; + + // this was already checked + // if (env >= ENV_QUIET) // 384 + // return 0; + + ret = ym_tl_tab[sin | (env<<7)]; + + return neg ? -ret : ret; +} + +INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm) +{ + int ret, sin = (phase+pm)>>16; + int neg = sin & 0x200; + if (sin & 0x100) sin ^= 0xff; + sin&=0xff; + env&=~1; + + // if (env >= ENV_QUIET) // 384 + // return 0; + + ret = ym_tl_tab[sin | (env<<7)]; + + return neg ? -ret : ret; +} + +#if !defined(_ASM_YM2612_C) || defined(EXTERNAL_YM2612) +/* advance LFO to next sample */ +INLINE int advance_lfo(int lfo_ampm, UINT32 lfo_cnt_old, UINT32 lfo_cnt) +{ + UINT8 pos; + UINT8 prev_pos; + + prev_pos = (lfo_cnt_old >> LFO_SH) & 127; + + pos = (lfo_cnt >> LFO_SH) & 127; + + /* update AM when LFO output changes */ + + if (prev_pos != pos) + { + lfo_ampm &= 0xff; + /* triangle */ + /* AM: 0 to 126 step +2, 126 to 0 step -2 */ + if (pos<64) + lfo_ampm |= ((pos&63) * 2) << 8; /* 0 - 126 */ + else + lfo_ampm |= (126 - (pos&63)*2) << 8; + } + else + { + return lfo_ampm; + } + + /* PM works with 4 times slower clock */ + prev_pos >>= 2; + pos >>= 2; + /* update PM when LFO output changes */ + if (prev_pos != pos) + { + lfo_ampm &= ~0xff; + lfo_ampm |= pos; /* 0 - 32 */ + } + return lfo_ampm; +} + +#define EG_INC_VAL() \ + ((1 << ((pack >> ((eg_cnt>>shift)&7)*3)&7)) >> 1) + +INLINE UINT32 update_eg_phase(FM_SLOT *SLOT, UINT32 eg_cnt) +{ + INT32 volume = SLOT->volume; + + switch(SLOT->state) + { + case EG_ATT: /* attack phase */ + { + UINT32 pack = SLOT->eg_pack_ar; + UINT32 shift = pack>>24; + if ( !(eg_cnt & ((1<>4; + + if (volume <= MIN_ATT_INDEX) + { + volume = MIN_ATT_INDEX; + SLOT->state = EG_DEC; + } + } + break; + } + + case EG_DEC: /* decay phase */ + { + UINT32 pack = SLOT->eg_pack_d1r; + UINT32 shift = pack>>24; + if ( !(eg_cnt & ((1<= (INT32) SLOT->sl ) + SLOT->state = EG_SUS; + } + break; + } + + case EG_SUS: /* sustain phase */ + { + UINT32 pack = SLOT->eg_pack_d2r; + UINT32 shift = pack>>24; + if ( !(eg_cnt & ((1<= MAX_ATT_INDEX ) + { + volume = MAX_ATT_INDEX; + /* do not change SLOT->state (verified on real chip) */ + } + } + break; + } + + case EG_REL: /* release phase */ + { + UINT32 pack = SLOT->eg_pack_rr; + UINT32 shift = pack>>24; + if ( !(eg_cnt & ((1<= MAX_ATT_INDEX ) + { + volume = MAX_ATT_INDEX; + SLOT->state = EG_OFF; + } + } + break; + } + } + + SLOT->volume = volume; + return SLOT->tl + ((UINT32)volume); /* tl is 7bit<<3, volume 0-1023 (0-2039 total) */ +} +#endif + + +typedef struct +{ + UINT16 vol_out1; /* 00: current output from EG circuit (without AM from LFO) */ + UINT16 vol_out2; + UINT16 vol_out3; + UINT16 vol_out4; + UINT32 pad[2]; + UINT32 phase1; /* 10 */ + UINT32 phase2; + UINT32 phase3; + UINT32 phase4; + UINT32 incr1; /* 20: phase step */ + UINT32 incr2; + UINT32 incr3; + UINT32 incr4; + UINT32 lfo_cnt; /* 30 */ + UINT32 lfo_inc; + INT32 mem; /* one sample delay memory */ + UINT32 eg_cnt; /* envelope generator counter */ + FM_CH *CH; /* 40: envelope generator counter */ + UINT32 eg_timer; + UINT32 eg_timer_add; + UINT32 pack; // 4c: stereo, lastchan, disabled, lfo_enabled | pan_r, pan_l, ams[2] | AMmasks[4] | FB[4] | lfo_ampm[16] + UINT32 algo; /* 50 */ + INT32 op1_out; +} chan_rend_context; + + +#if !defined(_ASM_YM2612_C) || defined(EXTERNAL_YM2612) +static void chan_render_loop(chan_rend_context *ct, int *buffer, int length) +{ + int scounter; /* sample counter */ + + /* sample generating loop */ + for (scounter = 0; scounter < length; scounter++) + { + int smp = 0; /* produced sample */ + unsigned int eg_out, eg_out2, eg_out4; + + if (ct->pack & 8) { /* LFO enabled ? (test Earthworm Jim in between demo 1 and 2) */ + ct->pack = (ct->pack&0xffff) | (advance_lfo(ct->pack >> 16, ct->lfo_cnt, ct->lfo_cnt + ct->lfo_inc) << 16); + ct->lfo_cnt += ct->lfo_inc; + } + + ct->eg_timer += ct->eg_timer_add; + while (ct->eg_timer >= EG_TIMER_OVERFLOW) + { + ct->eg_timer -= EG_TIMER_OVERFLOW; + ct->eg_cnt++; + + if (ct->CH->SLOT[SLOT1].state != EG_OFF) ct->vol_out1 = update_eg_phase(&ct->CH->SLOT[SLOT1], ct->eg_cnt); + if (ct->CH->SLOT[SLOT2].state != EG_OFF) ct->vol_out2 = update_eg_phase(&ct->CH->SLOT[SLOT2], ct->eg_cnt); + if (ct->CH->SLOT[SLOT3].state != EG_OFF) ct->vol_out3 = update_eg_phase(&ct->CH->SLOT[SLOT3], ct->eg_cnt); + if (ct->CH->SLOT[SLOT4].state != EG_OFF) ct->vol_out4 = update_eg_phase(&ct->CH->SLOT[SLOT4], ct->eg_cnt); + } + + if (ct->pack & 4) continue; /* output disabled */ + + /* calculate channel sample */ + eg_out = ct->vol_out1; + if ( (ct->pack & 8) && (ct->pack&(1<<(SLOT1+8))) ) eg_out += ct->pack >> (((ct->pack&0xc0)>>6)+24); + + if( eg_out < ENV_QUIET ) /* SLOT 1 */ + { + int out = 0; + + if (ct->pack&0xf000) out = ((ct->op1_out>>16) + (ct->op1_out<<16>>16)) << ((ct->pack&0xf000)>>12); /* op1_out0 + op1_out1 */ + ct->op1_out <<= 16; + ct->op1_out |= (unsigned short)op_calc1(ct->phase1, eg_out, out); + } else { + ct->op1_out <<= 16; /* op1_out0 = op1_out1; op1_out1 = 0; */ + } + + eg_out = ct->vol_out3; // volume_calc(&CH->SLOT[SLOT3]); + eg_out2 = ct->vol_out2; // volume_calc(&CH->SLOT[SLOT2]); + eg_out4 = ct->vol_out4; // volume_calc(&CH->SLOT[SLOT4]); + + if (ct->pack & 8) { + unsigned int add = ct->pack >> (((ct->pack&0xc0)>>6)+24); + if (ct->pack & (1<<(SLOT3+8))) eg_out += add; + if (ct->pack & (1<<(SLOT2+8))) eg_out2 += add; + if (ct->pack & (1<<(SLOT4+8))) eg_out4 += add; + } + + switch( ct->CH->ALGO ) + { +#if 0 + case 0: smp = upd_algo0(ct); break; + case 1: smp = upd_algo1(ct); break; + case 2: smp = upd_algo2(ct); break; + case 3: smp = upd_algo3(ct); break; + case 4: smp = upd_algo4(ct); break; + case 5: smp = upd_algo5(ct); break; + case 6: smp = upd_algo6(ct); break; + case 7: smp = upd_algo7(ct); break; +#else + case 0: + { + /* M1---C1---MEM---M2---C2---OUT */ + int m2,c1,c2=0; /* Phase Modulation input for operators 2,3,4 */ + m2 = ct->mem; + c1 = ct->op1_out>>16; + if( eg_out < ENV_QUIET ) { /* SLOT 3 */ + c2 = op_calc(ct->phase3, eg_out, m2); + } + if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */ + ct->mem = op_calc(ct->phase2, eg_out2, c1); + } + else ct->mem = 0; + if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */ + smp = op_calc(ct->phase4, eg_out4, c2); + } + break; + } + case 1: + { + /* M1------+-MEM---M2---C2---OUT */ + /* C1-+ */ + int m2,c2=0; + m2 = ct->mem; + ct->mem = ct->op1_out>>16; + if( eg_out < ENV_QUIET ) { /* SLOT 3 */ + c2 = op_calc(ct->phase3, eg_out, m2); + } + if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */ + ct->mem+= op_calc(ct->phase2, eg_out2, 0); + } + if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */ + smp = op_calc(ct->phase4, eg_out4, c2); + } + break; + } + case 2: + { + /* M1-----------------+-C2---OUT */ + /* C1---MEM---M2-+ */ + int m2,c2; + m2 = ct->mem; + c2 = ct->op1_out>>16; + if( eg_out < ENV_QUIET ) { /* SLOT 3 */ + c2 += op_calc(ct->phase3, eg_out, m2); + } + if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */ + ct->mem = op_calc(ct->phase2, eg_out2, 0); + } + else ct->mem = 0; + if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */ + smp = op_calc(ct->phase4, eg_out4, c2); + } + break; + } + case 3: + { + /* M1---C1---MEM------+-C2---OUT */ + /* M2-+ */ + int c1,c2; + c2 = ct->mem; + c1 = ct->op1_out>>16; + if( eg_out < ENV_QUIET ) { /* SLOT 3 */ + c2 += op_calc(ct->phase3, eg_out, 0); + } + if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */ + ct->mem = op_calc(ct->phase2, eg_out2, c1); + } + else ct->mem = 0; + if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */ + smp = op_calc(ct->phase4, eg_out4, c2); + } + break; + } + case 4: + { + /* M1---C1-+-OUT */ + /* M2---C2-+ */ + /* MEM: not used */ + int c1,c2=0; + c1 = ct->op1_out>>16; + if( eg_out < ENV_QUIET ) { /* SLOT 3 */ + c2 = op_calc(ct->phase3, eg_out, 0); + } + if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */ + smp = op_calc(ct->phase2, eg_out2, c1); + } + if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */ + smp+= op_calc(ct->phase4, eg_out4, c2); + } + break; + } + case 5: + { + /* +----C1----+ */ + /* M1-+-MEM---M2-+-OUT */ + /* +----C2----+ */ + int m2,c1,c2; + m2 = ct->mem; + ct->mem = c1 = c2 = ct->op1_out>>16; + if( eg_out < ENV_QUIET ) { /* SLOT 3 */ + smp = op_calc(ct->phase3, eg_out, m2); + } + if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */ + smp+= op_calc(ct->phase2, eg_out2, c1); + } + if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */ + smp+= op_calc(ct->phase4, eg_out4, c2); + } + break; + } + case 6: + { + /* M1---C1-+ */ + /* M2-+-OUT */ + /* C2-+ */ + /* MEM: not used */ + int c1; + c1 = ct->op1_out>>16; + if( eg_out < ENV_QUIET ) { /* SLOT 3 */ + smp = op_calc(ct->phase3, eg_out, 0); + } + if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */ + smp+= op_calc(ct->phase2, eg_out2, c1); + } + if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */ + smp+= op_calc(ct->phase4, eg_out4, 0); + } + break; + } + case 7: + { + /* M1-+ */ + /* C1-+-OUT */ + /* M2-+ */ + /* C2-+ */ + /* MEM: not used*/ + smp = ct->op1_out>>16; + if( eg_out < ENV_QUIET ) { /* SLOT 3 */ + smp += op_calc(ct->phase3, eg_out, 0); + } + if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */ + smp += op_calc(ct->phase2, eg_out2, 0); + } + if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */ + smp += op_calc(ct->phase4, eg_out4, 0); + } + break; + } +#endif + } + /* done calculating channel sample */ + + /* mix sample to output buffer */ + if (smp) { + if (ct->pack & 1) { /* stereo */ + if (ct->pack & 0x20) /* L */ /* TODO: check correctness */ + buffer[scounter*2] += smp; + if (ct->pack & 0x10) /* R */ + buffer[scounter*2+1] += smp; + } else { + buffer[scounter] += smp; + } + } + + /* update phase counters AFTER output calculations */ + ct->phase1 += ct->incr1; + ct->phase2 += ct->incr2; + ct->phase3 += ct->incr3; + ct->phase4 += ct->incr4; + } +} +#else +void chan_render_loop(chan_rend_context *ct, int *buffer, unsigned short length); +#endif + + +static void chan_render(int *buffer, int length, FM_CH *CH, UINT32 flags) // flags: stereo, lastchan, disabled, ?, pan_r, pan_l +{ + chan_rend_context ct; + + ct.CH = CH; + ct.mem = CH->mem_value; /* one sample delay memory */ + ct.lfo_cnt = ym2612.OPN.lfo_cnt; + ct.lfo_inc = ym2612.OPN.lfo_inc; + + flags &= 0x37; + + if (ct.lfo_inc) { + flags |= 8; + flags |= g_lfo_ampm << 16; + flags |= CH->AMmasks << 8; + if (CH->ams == 8) // no ams + flags &= ~0xf00; + else flags |= (CH->ams&3)<<6; + } + flags |= (CH->FB&0xf)<<12; /* feedback shift */ + ct.pack = flags; + + ct.eg_cnt = ym2612.OPN.eg_cnt; /* envelope generator counter */ + ct.eg_timer = ym2612.OPN.eg_timer; + ct.eg_timer_add = ym2612.OPN.eg_timer_add; + + /* precalculate phase modulation incr */ + ct.phase1 = CH->SLOT[SLOT1].phase; + ct.phase2 = CH->SLOT[SLOT2].phase; + ct.phase3 = CH->SLOT[SLOT3].phase; + ct.phase4 = CH->SLOT[SLOT4].phase; + + /* current output from EG circuit (without AM from LFO) */ + ct.vol_out1 = CH->SLOT[SLOT1].tl + ((UINT32)CH->SLOT[SLOT1].volume); + ct.vol_out2 = CH->SLOT[SLOT2].tl + ((UINT32)CH->SLOT[SLOT2].volume); + ct.vol_out3 = CH->SLOT[SLOT3].tl + ((UINT32)CH->SLOT[SLOT3].volume); + ct.vol_out4 = CH->SLOT[SLOT4].tl + ((UINT32)CH->SLOT[SLOT4].volume); + + ct.op1_out = CH->op1_out; + ct.algo = CH->ALGO & 7; + + if(CH->pms) + { + /* add support for 3 slot mode */ + UINT32 block_fnum = CH->block_fnum; + + UINT32 fnum_lfo = ((block_fnum & 0x7f0) >> 4) * 32 * 8; + INT32 lfo_fn_table_index_offset = lfo_pm_table[ fnum_lfo + CH->pms + ((ct.pack>>16)&0xff) ]; + + if (lfo_fn_table_index_offset) /* LFO phase modulation active */ + { + UINT8 blk; + UINT32 fn; + int kc,fc; + + block_fnum = block_fnum*2 + lfo_fn_table_index_offset; + + blk = (block_fnum&0x7000) >> 12; + fn = block_fnum & 0xfff; + + /* keyscale code */ + kc = (blk<<2) | opn_fktable[fn >> 8]; + /* phase increment counter */ + fc = fn_table[fn]>>(7-blk); + + ct.incr1 = ((fc+CH->SLOT[SLOT1].DT[kc])*CH->SLOT[SLOT1].mul) >> 1; + ct.incr2 = ((fc+CH->SLOT[SLOT2].DT[kc])*CH->SLOT[SLOT2].mul) >> 1; + ct.incr3 = ((fc+CH->SLOT[SLOT3].DT[kc])*CH->SLOT[SLOT3].mul) >> 1; + ct.incr4 = ((fc+CH->SLOT[SLOT4].DT[kc])*CH->SLOT[SLOT4].mul) >> 1; + } + else /* LFO phase modulation = zero */ + { + ct.incr1 = CH->SLOT[SLOT1].Incr; + ct.incr2 = CH->SLOT[SLOT2].Incr; + ct.incr3 = CH->SLOT[SLOT3].Incr; + ct.incr4 = CH->SLOT[SLOT4].Incr; + } + } + else /* no LFO phase modulation */ + { + ct.incr1 = CH->SLOT[SLOT1].Incr; + ct.incr2 = CH->SLOT[SLOT2].Incr; + ct.incr3 = CH->SLOT[SLOT3].Incr; + ct.incr4 = CH->SLOT[SLOT4].Incr; + } + + chan_render_loop(&ct, buffer, length); + + // write back persistent stuff: + if (flags & 2) { /* last channel */ + ym2612.OPN.eg_cnt = ct.eg_cnt; + ym2612.OPN.eg_timer = ct.eg_timer; + g_lfo_ampm = ct.pack >> 16; + ym2612.OPN.lfo_cnt = ct.lfo_cnt; + } + + CH->op1_out = ct.op1_out; + CH->SLOT[SLOT1].phase = ct.phase1; + CH->SLOT[SLOT2].phase = ct.phase2; + CH->SLOT[SLOT3].phase = ct.phase3; + CH->SLOT[SLOT4].phase = ct.phase4; + CH->mem_value = ct.mem; +} + +/* update phase increment and envelope generator */ +INLINE void refresh_fc_eg_slot(FM_SLOT *SLOT, int fc, int kc) +{ + int ksr; + + /* (frequency) phase increment counter */ + SLOT->Incr = ((fc+SLOT->DT[kc])*SLOT->mul) >> 1; + + ksr = kc >> SLOT->KSR; + if( SLOT->ksr != ksr ) + { + int eg_sh, eg_sel; + SLOT->ksr = ksr; + + /* calculate envelope generator rates */ + if ((SLOT->ar + SLOT->ksr) < 32+62) + { + eg_sh = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + eg_sel = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } + else + { + eg_sh = 0; + eg_sel = 17; + } + + SLOT->eg_pack_ar = eg_inc_pack[eg_sel] | (eg_sh<<24); + + eg_sh = eg_rate_shift [SLOT->d1r + SLOT->ksr]; + eg_sel = eg_rate_select[SLOT->d1r + SLOT->ksr]; + + SLOT->eg_pack_d1r = eg_inc_pack[eg_sel] | (eg_sh<<24); + + eg_sh = eg_rate_shift [SLOT->d2r + SLOT->ksr]; + eg_sel = eg_rate_select[SLOT->d2r + SLOT->ksr]; + + SLOT->eg_pack_d2r = eg_inc_pack[eg_sel] | (eg_sh<<24); + + eg_sh = eg_rate_shift [SLOT->rr + SLOT->ksr]; + eg_sel = eg_rate_select[SLOT->rr + SLOT->ksr]; + + SLOT->eg_pack_rr = eg_inc_pack[eg_sel] | (eg_sh<<24); + } +} + +/* update phase increment counters */ +INLINE void refresh_fc_eg_chan(FM_CH *CH) +{ + if( CH->SLOT[SLOT1].Incr==-1){ + int fc = CH->fc; + int kc = CH->kcode; + refresh_fc_eg_slot(&CH->SLOT[SLOT1] , fc , kc ); + refresh_fc_eg_slot(&CH->SLOT[SLOT2] , fc , kc ); + refresh_fc_eg_slot(&CH->SLOT[SLOT3] , fc , kc ); + refresh_fc_eg_slot(&CH->SLOT[SLOT4] , fc , kc ); + } +} + +/* initialize time tables */ +static void init_timetables(const UINT8 *dttable) +{ + int i,d; + double rate; + + /* DeTune table */ + for (d = 0;d <= 3;d++){ + for (i = 0;i <= 31;i++){ + rate = ((double)dttable[d*32 + i]) * SIN_LEN * ym2612.OPN.ST.freqbase * (1<0.0) + o = 8*log(1.0/m)/log(2); /* convert to 'decibels' */ + else + o = 8*log(-1.0/m)/log(2); /* convert to 'decibels' */ + + o = o / (ENV_STEP/4); + + n = (int)(2.0*o); + if (n&1) /* round to nearest */ + n = (n>>1)+1; + else + n = n>>1; + + ym_sin_tab[ i ] = n; + //dprintf("FM.C: sin [%4i]= %4i", i, ym_sin_tab[i]); + } + + //dprintf("FM.C: ENV_QUIET= %08x", ENV_QUIET ); + + + for (x=0; x < TL_RES_LEN; x++) + { + m = (1<<16) / pow(2, (x+1) * (ENV_STEP/4.0) / 8.0); + m = floor(m); + + /* we never reach (1<<16) here due to the (x+1) */ + /* result fits within 16 bits at maximum */ + + n = (int)m; /* 16 bits here */ + n >>= 4; /* 12 bits here */ + if (n&1) /* round to nearest */ + n = (n>>1)+1; + else + n = n>>1; + /* 11 bits here (rounded) */ + n <<= 2; /* 13 bits here (as in real chip) */ + ym_tl_tab2[ x ] = n; + + for (i=1; i < 13; i++) + { + ym_tl_tab2[ x + i*TL_RES_LEN ] = n >> i; + } + } + + for (x=0; x < 256; x++) + { + int sin = ym_sin_tab[ x ]; + + for (y=0; y < 2*13*TL_RES_LEN/8; y+=2) + { + p = (y<<2) + sin; + if (p >= 13*TL_RES_LEN) + ym_tl_tab[(y<<7) | x] = 0; + else ym_tl_tab[(y<<7) | x] = ym_tl_tab2[p]; + } + } + + + /* build LFO PM modulation table */ + for(i = 0; i < 8; i++) /* 8 PM depths */ + { + UINT8 fnum; + for (fnum=0; fnum<128; fnum++) /* 7 bits meaningful of F-NUMBER */ + { + UINT8 value; + UINT8 step; + UINT32 offset_depth = i; + UINT32 offset_fnum_bit; + UINT32 bit_tmp; + + for (step=0; step<8; step++) + { + value = 0; + for (bit_tmp=0; bit_tmp<7; bit_tmp++) /* 7 bits */ + { + if (fnum & (1< increment counter table */ + for(i = 0; i < 4096; i++) + { + /* freq table for octave 7 */ + /* OPN phase increment counter = 20bit */ + fn_table[i] = (UINT32)( (double)i * 32 * ym2612.OPN.ST.freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ + } + + /* LFO freq. table */ + for(i = 0; i < 8; i++) + { + /* Amplitude modulation: 64 output levels (triangle waveform); 1 level lasts for one of "lfo_samples_per_step" samples */ + /* Phase modulation: one entry from lfo_pm_output lasts for one of 4 * "lfo_samples_per_step" samples */ + ym2612.OPN.lfo_freq[i] = (1.0 / lfo_samples_per_step[i]) * (1<= 0x100) c+=3; + + CH = &ym2612.CH[c]; + + SLOT = &(CH->SLOT[OPN_SLOT(r)]); + + switch( r & 0xf0 ) { + case 0x30: /* DET , MUL */ + set_det_mul(CH,SLOT,v); + break; + + case 0x40: /* TL */ + set_tl(SLOT,v); + break; + + case 0x50: /* KS, AR */ + set_ar_ksr(CH,SLOT,v); + break; + + case 0x60: /* bit7 = AM ENABLE, DR */ + set_dr(SLOT,v); + if(v&0x80) CH->AMmasks |= 1<AMmasks &= ~(1<>3; + /* keyscale code */ + CH->kcode = (blk<<2) | opn_fktable[fn >> 7]; + /* phase increment counter */ + CH->fc = fn_table[fn*2]>>(7-blk); + + /* store fnum in clear form for LFO PM calculations */ + CH->block_fnum = (blk<<11) | fn; + + CH->SLOT[SLOT1].Incr=-1; + } + break; + case 1: /* 0xa4-0xa6 : FNUM2,BLK */ + ym2612.OPN.ST.fn_h = v&0x3f; + ret = 0; + break; + case 2: /* 0xa8-0xaa : 3CH FNUM1 */ + if(r < 0x100) + { + UINT32 fn = (((UINT32)(ym2612.OPN.SL3.fn_h&7))<<8) + v; + UINT8 blk = ym2612.OPN.SL3.fn_h>>3; + /* keyscale code */ + ym2612.OPN.SL3.kcode[c]= (blk<<2) | opn_fktable[fn >> 7]; + /* phase increment counter */ + ym2612.OPN.SL3.fc[c] = fn_table[fn*2]>>(7-blk); + ym2612.OPN.SL3.block_fnum[c] = fn; + ym2612.CH[2].SLOT[SLOT1].Incr=-1; + } + break; + case 3: /* 0xac-0xae : 3CH FNUM2,BLK */ + if(r < 0x100) + ym2612.OPN.SL3.fn_h = v&0x3f; + ret = 0; + break; + default: + ret = 0; + break; + } + break; + + case 0xb0: + switch( OPN_SLOT(r) ){ + case 0: /* 0xb0-0xb2 : FB,ALGO */ + { + int feedback = (v>>3)&7; + CH->ALGO = v&7; + CH->FB = feedback ? feedback+6 : 0; + } + break; + case 1: /* 0xb4-0xb6 : L , R , AMS , PMS (YM2612/YM2610B/YM2610/YM2608) */ + { + int panshift = c<<1; + + /* b0-2 PMS */ + CH->pms = (v & 7) * 32; /* CH->pms = PM depth * 32 (index in lfo_pm_table) */ + + /* b4-5 AMS */ + CH->ams = lfo_ams_depth_shift[(v>>4) & 3]; + + /* PAN : b7 = L, b6 = R */ + ym2612.OPN.pan &= ~(3<> 6) << panshift; // ..LRLR + } + break; + default: + ret = 0; + break; + } + break; + default: + ret = 0; + break; + } + + return ret; +} + + +/*******************************************************************************/ +/* YM2612 local section */ +/*******************************************************************************/ + +int *ym2612_dacen; +INT32 *ym2612_dacout; + + +/* Generate samples for YM2612 */ +void YM2612UpdateOne_(short *buffer, int length, int stereo) +{ + int pan; +#ifndef EXTERNAL_YM2612 + int i; + static int *mix_buffer = 0, mix_buffer_length = 0; +#endif + + /* refresh PG and EG */ + refresh_fc_eg_chan( &ym2612.CH[0] ); + refresh_fc_eg_chan( &ym2612.CH[1] ); + if( (ym2612.OPN.ST.mode & 0xc0) ) + { + /* 3SLOT MODE */ + if( ym2612.CH[2].SLOT[SLOT1].Incr==-1) + { + refresh_fc_eg_slot(&ym2612.CH[2].SLOT[SLOT1], ym2612.OPN.SL3.fc[1], ym2612.OPN.SL3.kcode[1] ); + refresh_fc_eg_slot(&ym2612.CH[2].SLOT[SLOT2], ym2612.OPN.SL3.fc[2], ym2612.OPN.SL3.kcode[2] ); + refresh_fc_eg_slot(&ym2612.CH[2].SLOT[SLOT3], ym2612.OPN.SL3.fc[0], ym2612.OPN.SL3.kcode[0] ); + refresh_fc_eg_slot(&ym2612.CH[2].SLOT[SLOT4], ym2612.CH[2].fc , ym2612.CH[2].kcode ); + } + } else refresh_fc_eg_chan( &ym2612.CH[2] ); + refresh_fc_eg_chan( &ym2612.CH[3] ); + refresh_fc_eg_chan( &ym2612.CH[4] ); + refresh_fc_eg_chan( &ym2612.CH[5] ); + + pan = ym2612.OPN.pan; + if (stereo) stereo = 1; + +#ifndef EXTERNAL_YM2612 + if (mix_buffer_length < length) { + mix_buffer = realloc(mix_buffer, length*4<>2)); + chan_render(mix_buffer, length, &ym2612.CH[4], stereo|((pan&0x300)>>4)); + chan_render(mix_buffer, length, &ym2612.CH[5], stereo|((pan&0xc00)>>6)|(ym2612.dacen<<2)|2); + +#ifndef EXTERNAL_YM2612 + /* limit and mix to output buffer */ + if (stereo) { + int *mb = mix_buffer; + for (i = length; i > 0; i--) { + int l, r; + l = r = *buffer; + l += *mb++, r += *mb++; + Limit( l, MAXOUT, MINOUT ); + Limit( r, MAXOUT, MINOUT ); + *buffer++ = l; *buffer++ = r; + } + } else { + for (i = 0; i < length; i++) { + int l = mix_buffer[i]; + l += buffer[i]; + Limit( l, MAXOUT, MINOUT ); + buffer[i] = l; + } + } +#endif +} + + +/* initialize YM2612 emulator */ +void YM2612Init_(int clock, int rate) +{ + // notaz + ym2612_dacen = &ym2612.dacen; + ym2612_dacout = &ym2612.dacout; + + /* clear everything but the regs */ + memset(ym2612.CH, 0, sizeof(ym2612)-sizeof(ym2612.REGS)-4); + init_tables(); + + ym2612.OPN.ST.clock = clock; + ym2612.OPN.ST.rate = rate; + + /* Extend handler */ + YM2612ResetChip_(); +} + + +/* reset */ +void YM2612ResetChip_(void) +{ + int i; + + OPNSetPres( 6*24 ); + set_timers( 0x30 ); /* mode 0 , timer reset */ + + ym2612.OPN.eg_timer = 0; + ym2612.OPN.eg_cnt = 0; + ym2612.OPN.ST.status = 0; + + reset_channels( &ym2612.CH[0] , 6 ); + for(i = 0xb6 ; i >= 0xb4 ; i-- ) + { + OPNWriteReg(i ,0xc0); + OPNWriteReg(i|0x100,0xc0); + } + for(i = 0xb2 ; i >= 0x30 ; i-- ) + { + OPNWriteReg(i ,0); + OPNWriteReg(i|0x100,0); + } + for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(i,0); + /* DAC mode clear */ + ym2612.dacen = 0; +} + + +/* YM2612 write */ +/* a = address */ +/* v = value */ +/* returns 1 if sample affecting state changed */ +int YM2612Write_(unsigned int a, unsigned int v) +{ + int addr, ret=1; + + v &= 0xff; /* adjust to 8 bit bus */ + + switch( a&3){ + case 0: /* address port 0 */ + ym2612.OPN.ST.address = v; + ym2612.addr_A1 = 0; + ret=0; + break; + + case 1: /* data port 0 */ + if (ym2612.addr_A1 != 0) { + ret=0; + break; /* verified on real YM2608 */ + } + + addr = ym2612.OPN.ST.address; + ym2612.REGS[addr] = v; + + switch( addr & 0xf0 ) + { + case 0x20: /* 0x20-0x2f Mode */ + switch( addr ) + { + case 0x22: /* LFO FREQ (YM2608/YM2610/YM2610B/YM2612) */ + if (v&0x08) /* LFO enabled ? */ + { + ym2612.OPN.lfo_inc = ym2612.OPN.lfo_freq[v&7]; + } + else + { + ym2612.OPN.lfo_inc = 0; + } + break; + case 0x24: { // timer A High 8 + int TAnew = (ym2612.OPN.ST.TA & 0x03)|(((int)v)<<2); + if(ym2612.OPN.ST.TA != TAnew) { + // we should reset ticker only if new value is written. Outrun requires this. + ym2612.OPN.ST.TA = TAnew; + ym2612.OPN.ST.TAC = (1024-TAnew)*18; + ym2612.OPN.ST.TAT = 0; + } + } + ret=0; + break; + case 0x25: { // timer A Low 2 + int TAnew = (ym2612.OPN.ST.TA & 0x3fc)|(v&3); + if(ym2612.OPN.ST.TA != TAnew) { + ym2612.OPN.ST.TA = TAnew; + ym2612.OPN.ST.TAC = (1024-TAnew)*18; + ym2612.OPN.ST.TAT = 0; + } + } + ret=0; + break; + case 0x26: // timer B + if(ym2612.OPN.ST.TB != v) { + ym2612.OPN.ST.TB = v; + ym2612.OPN.ST.TBC = (256-v)<<4; + ym2612.OPN.ST.TBC *= 18; + ym2612.OPN.ST.TBT = 0; + } + ret=0; + break; + case 0x27: /* mode, timer control */ + set_timers( v ); + ret=0; + break; + case 0x28: /* key on / off */ + { + UINT8 c; + FM_CH *CH; + + c = v & 0x03; + if( c == 3 ) { ret=0; break; } + if( v&0x04 ) c+=3; + CH = &ym2612.CH[c]; + if(v&0x10) FM_KEYON(CH,SLOT1); else FM_KEYOFF(CH,SLOT1); + if(v&0x20) FM_KEYON(CH,SLOT2); else FM_KEYOFF(CH,SLOT2); + if(v&0x40) FM_KEYON(CH,SLOT3); else FM_KEYOFF(CH,SLOT3); + if(v&0x80) FM_KEYON(CH,SLOT4); else FM_KEYOFF(CH,SLOT4); + break; + } + case 0x2a: /* DAC data (YM2612) */ + ym2612.dacout = ((int)v - 0x80) << 6; /* level unknown (notaz: 8 seems to be too much) */ + ret=0; + break; + case 0x2b: /* DAC Sel (YM2612) */ + /* b7 = dac enable */ + ym2612.dacen = v & 0x80; + ret=0; + break; + default: + break; + } + break; + default: /* 0x30-0xff OPN section */ + /* write register */ + ret = OPNWriteReg(addr,v); + } + break; + + case 2: /* address port 1 */ + ym2612.OPN.ST.address = v; + ym2612.addr_A1 = 1; + ret=0; + break; + + case 3: /* data port 1 */ + if (ym2612.addr_A1 != 1) { + ret=0; + break; /* verified on real YM2608 */ + } + + addr = ym2612.OPN.ST.address | 0x100; + ym2612.REGS[addr] = v; + + ret = OPNWriteReg(addr, v); + break; + } +/* + if(ret) { + extern int Scanline; + dprintf("ymw [%i]", Scanline); + } +*/ + return ret; +} + +UINT8 YM2612Read_(void) +{ + return ym2612.OPN.ST.status; +} + + +int YM2612PicoTick_(int n) +{ + int ret = 0; + + // timer A + if(ym2612.OPN.ST.mode & 0x01 && (ym2612.OPN.ST.TAT+=64*n) >= ym2612.OPN.ST.TAC) { + ym2612.OPN.ST.TAT -= ym2612.OPN.ST.TAC; + if(ym2612.OPN.ST.mode & 0x04) ym2612.OPN.ST.status |= 1; + // CSM mode total level latch and auto key on + if(ym2612.OPN.ST.mode & 0x80) { + CSMKeyControll( &(ym2612.CH[2]) ); // Vectorman2, etc. + ret = 1; + } + } + + // timer B + if(ym2612.OPN.ST.mode & 0x02 && (ym2612.OPN.ST.TBT+=64*n) >= ym2612.OPN.ST.TBC) { + ym2612.OPN.ST.TBT -= ym2612.OPN.ST.TBC; + if(ym2612.OPN.ST.mode & 0x08) ym2612.OPN.ST.status |= 2; + } + + return ret; +} + + +void YM2612PicoStateLoad_(void) +{ +#ifndef EXTERNAL_YM2612 + int i, old_A1 = ym2612.addr_A1; + + reset_channels( &ym2612.CH[0], 6 ); + + // feed all the registers and update internal state + for(i = 0; i < 0x100; i++) { + YM2612Write_(0, i); + YM2612Write_(1, ym2612.REGS[i]); + } + for(i = 0; i < 0x100; i++) { + YM2612Write_(2, i); + YM2612Write_(3, ym2612.REGS[i|0x100]); + } + + ym2612.addr_A1 = old_A1; +#else + reset_channels( &ym2612.CH[0], 6 ); +#endif +} + + +void *YM2612GetRegs(void) +{ + return ym2612.REGS; +} diff --git a/Pico/sound/ym2612.h b/Pico/sound/ym2612.h new file mode 100644 index 00000000..c575baef --- /dev/null +++ b/Pico/sound/ym2612.h @@ -0,0 +1,192 @@ +/* + header file for software emulation for FM sound generator + +*/ +#ifndef _H_FM_FM_ +#define _H_FM_FM_ + +/* compiler dependence */ +#ifndef UINT8 +typedef unsigned char UINT8; /* unsigned 8bit */ +typedef unsigned short UINT16; /* unsigned 16bit */ +typedef unsigned int UINT32; /* unsigned 32bit */ +#endif +#ifndef INT8 +typedef signed char INT8; /* signed 8bit */ +typedef signed short INT16; /* signed 16bit */ +typedef signed int INT32; /* signed 32bit */ +#endif + +#if 1 +/* struct describing a single operator (SLOT) */ +typedef struct +{ + INT32 *DT; /* #0x00 detune :dt_tab[DT] */ + UINT8 ar; /* #0x04 attack rate */ + UINT8 d1r; /* #0x05 decay rate */ + UINT8 d2r; /* #0x06 sustain rate */ + UINT8 rr; /* #0x07 release rate */ + UINT32 mul; /* #0x08 multiple :ML_TABLE[ML] */ + + /* Phase Generator */ + UINT32 phase; /* #0x0c phase counter */ + UINT32 Incr; /* #0x10 phase step */ + + UINT8 KSR; /* #0x14 key scale rate :3-KSR */ + UINT8 ksr; /* #0x15 key scale rate :kcode>>(3-KSR) */ + + UINT8 key; /* #0x16 0=last key was KEY OFF, 1=KEY ON */ + + /* Envelope Generator */ + UINT8 state; /* #0x17 phase type: EG_OFF=0, EG_REL, EG_SUS, EG_DEC, EG_ATT */ + UINT16 tl; /* #0x18 total level: TL << 3 */ + INT16 volume; /* #0x1a envelope counter */ + UINT32 sl; /* #0x1c sustain level:sl_table[SL] */ + + UINT32 eg_pack_ar; /* #0x20 (attack state) */ + UINT32 eg_pack_d1r; /* #0x24 (decay state) */ + UINT32 eg_pack_d2r; /* #0x28 (sustain state) */ + UINT32 eg_pack_rr; /* #0x2c (release state) */ +} FM_SLOT; + + +typedef struct +{ + FM_SLOT SLOT[4]; /* four SLOTs (operators) */ + + UINT8 ALGO; /* algorithm */ + UINT8 FB; /* feedback shift */ + INT32 op1_out; /* op1 output for feedback */ + + INT32 mem_value; /* delayed sample (MEM) value */ + + INT32 pms; /* channel PMS */ + UINT8 ams; /* channel AMS */ + + UINT8 kcode; /* key code: */ + UINT32 fc; /* fnum,blk:adjusted to sample rate */ + UINT32 block_fnum; /* current blk/fnum value for this slot (can be different betweeen slots of one channel in 3slot mode) */ + + /* LFO */ + UINT8 AMmasks; /* AM enable flag */ + +} FM_CH; + +typedef struct +{ + int clock; /* master clock (Hz) */ + int rate; /* sampling rate (Hz) */ + double freqbase; /* frequency base */ + UINT8 address; /* address register */ + UINT8 status; /* status flag */ + UINT8 mode; /* mode CSM / 3SLOT */ + UINT8 fn_h; /* freq latch */ + int TA; /* timer a */ + int TAC; /* timer a maxval */ + int TAT; /* timer a ticker */ + UINT8 TB; /* timer b */ + int TBC; /* timer b maxval */ + int TBT; /* timer b ticker */ + /* local time tables */ + INT32 dt_tab[8][32];/* DeTune table */ +} FM_ST; + +/***********************************************************/ +/* OPN unit */ +/***********************************************************/ + +/* OPN 3slot struct */ +typedef struct +{ + UINT32 fc[3]; /* fnum3,blk3: calculated */ + UINT8 fn_h; /* freq3 latch */ + UINT8 kcode[3]; /* key code */ + UINT32 block_fnum[3]; /* current fnum value for this slot (can be different betweeen slots of one channel in 3slot mode) */ +} FM_3SLOT; + +/* OPN/A/B common state */ +typedef struct +{ + FM_ST ST; /* general state */ + FM_3SLOT SL3; /* 3 slot mode state */ + UINT32 pan; /* fm channels output mask (bit 1 = enable) */ + + UINT32 eg_cnt; /* #0xb38 global envelope generator counter */ + UINT32 eg_timer; /* #0xb3c global envelope generator counter works at frequency = chipclock/64/3 */ + UINT32 eg_timer_add; /* #0xb40 step of eg_timer */ + + /* LFO */ + UINT32 lfo_cnt; + UINT32 lfo_inc; + + UINT32 lfo_freq[8]; /* LFO FREQ table */ +} FM_OPN; + +/* here's the virtual YM2612 */ +typedef struct +{ + UINT8 REGS[0x200]; /* registers (for save states) */ + INT32 addr_A1; /* address line A1 */ + + FM_CH CH[6]; /* channel state (0x168 bytes each)? */ + + /* dac output (YM2612) */ + int dacen; + INT32 dacout; + + FM_OPN OPN; /* OPN state */ +} YM2612; +#endif + + + +void YM2612Init_(int baseclock, int rate); +void YM2612ResetChip_(void); +void YM2612UpdateOne_(short *buffer, int length, int stereo); + +int YM2612Write_(unsigned int a, unsigned int v); +unsigned char YM2612Read_(void); + +int YM2612PicoTick_(int n); +void YM2612PicoStateLoad_(void); + +void *YM2612GetRegs(void); + +#ifndef __GP2X__ +#define YM2612Init YM2612Init_ +#define YM2612ResetChip YM2612ResetChip_ +#define YM2612UpdateOne YM2612UpdateOne_ +#define YM2612Write YM2612Write_ +#define YM2612Read YM2612Read_ +#define YM2612PicoTick YM2612PicoTick_ +#define YM2612PicoStateLoad YM2612PicoStateLoad_ +#else +/* GP2X specific */ +#include "../../platform/gp2x/940ctl_ym2612.h" +extern int PicoOpt; +#define YM2612Init(baseclock,rate) { \ + if (PicoOpt&0x200) YM2612Init_940(baseclock, rate); \ + else YM2612Init_(baseclock, rate); \ +} +#define YM2612ResetChip() { \ + if (PicoOpt&0x200) YM2612ResetChip_940(); \ + else YM2612ResetChip_(); \ +} +#define YM2612UpdateOne(buffer,length,stereo) { \ + if (PicoOpt&0x200) YM2612UpdateOne_940(buffer, length, stereo); \ + else YM2612UpdateOne_(buffer, length, stereo); \ +} +#define YM2612Write(a,v) \ + (PicoOpt&0x200) ? YM2612Write_940(a, v) : YM2612Write_(a, v) +#define YM2612Read() \ + (PicoOpt&0x200) ? YM2612Read_940() : YM2612Read_() +#define YM2612PicoTick(n) \ + (PicoOpt&0x200) ? YM2612PicoTick_940(n) : YM2612PicoTick_(n) +#define YM2612PicoStateLoad() { \ + if (PicoOpt&0x200) YM2612PicoStateLoad_940(); \ + else YM2612PicoStateLoad_(); \ +} +#endif /* __GP2X__ */ + + +#endif /* _H_FM_FM_ */ diff --git a/Pico/sound/ym2612.s b/Pico/sound/ym2612.s new file mode 100644 index 00000000..0c630e50 --- /dev/null +++ b/Pico/sound/ym2612.s @@ -0,0 +1,915 @@ +@ this is a rewrite of MAME's ym2612 code, in particular this is only the main sample-generatin loop. +@ it does not seem to give much performance increase (if any at all), so don't use it if it causes trouble. +@ - notaz, 2006 + +.equiv SLOT1, 0 +.equiv SLOT2, 2 +.equiv SLOT3, 1 +.equiv SLOT4, 3 +.equiv SLOT_STRUCT_SIZE, 0x30 + +.equiv TL_TAB_LEN, 0x1A00 + +.equiv EG_ATT, 4 +.equiv EG_DEC, 3 +.equiv EG_SUS, 2 +.equiv EG_REL, 1 +.equiv EG_OFF, 0 + +.equiv EG_SH, 16 @ 16.16 fixed point (envelope generator timing) +.equiv EG_TIMER_OVERFLOW, (3*(1<= (INT32) SLOT->sl ) + movge r3, #EG_SUS + strgeb r3, [r5,#0x17] @ state + b 4f + +2: @ EG_SUS + ldr r2, [r5,#0x28] @ eg_pack_d2r (1ci) + mov r0, r2, lsr #24 + mov r3, r3, lsl r0 + sub r3, r3, #1 + tst r1, r3 + bne 5f @ do smth for tl problem (set on init?) + mov r3, r1, lsr r0 + ldrh r0, [r5,#0x1a] @ volume + and r3, r3, #7 + add r3, r3, r3, lsl #1 + mov r3, r2, lsr r3 + and r3, r3, #7 @ shift for eg_inc calculation + mov r2, #1 + mov r3, r2, lsl r3 + add r0, r0, r3, asr #1 + mov r2, #1024 + sub r2, r2, #1 @ r2 = MAX_ATT_INDEX + cmp r0, r2 @ if ( volume >= MAX_ATT_INDEX ) + movge r0, r2 + b 4f + +3: @ EG_REL + ldr r2, [r5,#0x2c] @ eg_pack_rr (1ci) + mov r0, r2, lsr #24 + mov r3, r3, lsl r0 + sub r3, r3, #1 + tst r1, r3 + bne 5f @ do smth for tl problem (set on init?) + mov r3, r1, lsr r0 + ldrh r0, [r5,#0x1a] @ volume + and r3, r3, #7 + add r3, r3, r3, lsl #1 + mov r3, r2, lsr r3 + and r3, r3, #7 @ shift for eg_inc calculation + mov r2, #1 + mov r3, r2, lsl r3 + add r0, r0, r3, asr #1 + mov r2, #1024 + sub r2, r2, #1 @ r2 = MAX_ATT_INDEX + cmp r0, r2 @ if ( volume >= MAX_ATT_INDEX ) + movge r0, r2 + movge r3, #EG_OFF + strgeb r3, [r5,#0x17] @ state + +4: + ldrh r3, [r5,#0x18] @ tl + strh r0, [r5,#0x1a] @ volume +.if \slot == SLOT1 + mov r6, r6, lsr #16 + add r0, r0, r3 + orr r6, r0, r6, lsl #16 +.elseif \slot == SLOT2 + mov r6, r6, lsl #16 + add r0, r0, r3 + mov r0, r0, lsl #16 + orr r6, r0, r6, lsr #16 +.elseif \slot == SLOT3 + mov r7, r7, lsr #16 + add r0, r0, r3 + orr r7, r0, r7, lsl #16 +.elseif \slot == SLOT4 + mov r7, r7, lsl #16 + add r0, r0, r3 + mov r0, r0, lsl #16 + orr r7, r0, r7, lsr #16 +.endif + +5: +.endm + + +@ r12=lfo_ampm[31:16], r1=lfo_cnt_old, r2=lfo_cnt, r3=scratch +.macro advance_lfo_m + mov r2, r2, lsr #LFO_SH + cmp r2, r1, lsr #LFO_SH + beq 0f + and r3, r2, #0x3f + cmp r2, #0x40 + rsbge r3, r3, #0x3f + bic r12,r12, #0xff000000 @ lfo_ampm &= 0xff + orr r12,r12, r3, lsl #1+24 + + mov r2, r2, lsr #2 + cmp r2, r1, lsr #LFO_SH+2 + bicne r12,r12, #0xff0000 + orrne r12,r12, r2, lsl #16 + +0: +.endm + + +@ result goes to r1, trashes r2 +.macro make_eg_out slot + tst r12, #8 + tstne r12, #(1<<(\slot+8)) +.if \slot == SLOT1 + mov r1, r6, lsl #16 + mov r1, r1, lsr #17 +.elseif \slot == SLOT2 + mov r1, r6, lsr #17 +.elseif \slot == SLOT3 + mov r1, r7, lsl #16 + mov r1, r1, lsr #17 +.elseif \slot == SLOT4 + mov r1, r7, lsr #17 +.endif + andne r2, r12, #0xc0 + movne r2, r2, lsr #6 + addne r2, r2, #24 + addne r1, r1, r12, lsr r2 +.endm + + +.macro lookup_tl r + tst \r, #0x100 + eorne \r, \r, #0xff @ if (sin & 0x100) sin = 0xff - (sin&0xff); + tst \r, #0x200 + and \r, \r, #0xff + orr \r, \r, r1, lsl #8 + mov \r, \r, lsl #1 + ldrh \r, [r3, \r] @ 2ci if ne + rsbne \r, \r, #0 +.endm + + +@ lr=context, r12=pack (stereo, lastchan, disabled, lfo_enabled | pan_r, pan_l, ams[2] | AMmasks[4] | FB[4] | lfo_ampm[16]) +@ r0-r2=scratch, r3=sin_tab, r5=scratch, r6-r7=vol_out[4], r10=op1_out +.macro upd_algo0_m + + @ SLOT3 + make_eg_out SLOT3 + cmp r1, #ENV_QUIET + movcs r0, #0 + bcs 0f + ldr r2, [lr, #0x18] + ldr r0, [lr, #0x38] @ mem (signed) + mov r2, r2, lsr #16 + add r0, r2, r0, lsr #1 + lookup_tl r0 @ r0=c2 + +0: + + @ SLOT4 + make_eg_out SLOT4 + cmp r1, #ENV_QUIET + movcs r0, #0 + bcs 1f + ldr r2, [lr, #0x1c] + mov r0, r0, lsr #1 + add r0, r0, r2, lsr #16 + lookup_tl r0 @ r0=output smp + +1: + @ SLOT2 + make_eg_out SLOT2 + cmp r1, #ENV_QUIET + movcs r2, #0 + bcs 2f + ldr r2, [lr, #0x14] @ 1ci + mov r5, r10, lsr #17 + add r2, r5, r2, lsr #16 + lookup_tl r2 @ r2=mem + +2: + str r2, [lr, #0x38] @ mem +.endm + + +.macro upd_algo1_m + + @ SLOT3 + make_eg_out SLOT3 + cmp r1, #ENV_QUIET + movcs r0, #0 + bcs 0f + ldr r2, [lr, #0x18] + ldr r0, [lr, #0x38] @ mem (signed) + mov r2, r2, lsr #16 + add r0, r2, r0, lsr #1 + lookup_tl r0 @ r0=c2 + +0: + @ SLOT4 + make_eg_out SLOT4 + cmp r1, #ENV_QUIET + movcs r0, #0 + bcs 1f + ldr r2, [lr, #0x1c] + mov r0, r0, lsr #1 + add r0, r0, r2, lsr #16 + lookup_tl r0 @ r0=output smp + +1: + @ SLOT2 + make_eg_out SLOT2 + cmp r1, #ENV_QUIET + movcs r2, #0 + bcs 2f + ldr r2, [lr, #0x14] @ 1ci + mov r2, r2, lsr #16 + lookup_tl r2 @ r2=mem + +2: + add r2, r2, r10, asr #16 + str r2, [lr, #0x38] +.endm + + +.macro upd_algo2_m + + @ SLOT3 + make_eg_out SLOT3 + cmp r1, #ENV_QUIET + movcs r0, #0 + bcs 0f + ldr r2, [lr, #0x18] + ldr r0, [lr, #0x38] @ mem (signed) + mov r2, r2, lsr #16 + add r0, r2, r0, lsr #1 + lookup_tl r0 @ r0=c2 + +0: + add r0, r0, r10, asr #16 + + @ SLOT4 + make_eg_out SLOT4 + cmp r1, #ENV_QUIET + movcs r0, #0 + bcs 1f + ldr r2, [lr, #0x1c] + mov r0, r0, lsr #1 + add r0, r0, r2, lsr #16 + lookup_tl r0 @ r0=output smp + +1: + @ SLOT2 + make_eg_out SLOT2 + cmp r1, #ENV_QUIET + movcs r2, #0 + bcs 2f + ldr r2, [lr, #0x14] + mov r2, r2, lsr #16 @ 1ci + lookup_tl r2 @ r2=mem + +2: + str r2, [lr, #0x38] @ mem +.endm + + +.macro upd_algo3_m + + @ SLOT3 + make_eg_out SLOT3 + cmp r1, #ENV_QUIET + ldr r2, [lr, #0x38] @ mem (for future) + movcs r0, r2 + bcs 0f + ldr r0, [lr, #0x18] @ 1ci + mov r0, r0, lsr #16 + lookup_tl r0 @ r0=c2 + +0: + add r0, r0, r2 + + @ SLOT4 + make_eg_out SLOT4 + cmp r1, #ENV_QUIET + movcs r0, #0 + bcs 1f + ldr r2, [lr, #0x1c] + mov r0, r0, lsr #1 + add r0, r0, r2, lsr #16 + lookup_tl r0 @ r0=output smp + +1: + @ SLOT2 + make_eg_out SLOT2 + cmp r1, #ENV_QUIET + movcs r2, #0 + bcs 2f + ldr r2, [lr, #0x14] + mov r5, r10, lsr #17 + add r2, r5, r2, lsr #16 + lookup_tl r2 @ r2=mem + +2: + str r2, [lr, #0x38] @ mem +.endm + + +.macro upd_algo4_m + + @ SLOT3 + make_eg_out SLOT3 + cmp r1, #ENV_QUIET + movcs r0, #0 + bcs 0f + ldr r0, [lr, #0x18] + mov r0, r0, lsr #16 @ 1ci + lookup_tl r0 @ r0=c2 + +0: + @ SLOT4 + make_eg_out SLOT4 + cmp r1, #ENV_QUIET + movcs r0, #0 + bcs 1f + ldr r2, [lr, #0x1c] + mov r0, r0, lsr #1 + add r0, r0, r2, lsr #16 + lookup_tl r0 @ r0=output smp + +1: + @ SLOT2 + make_eg_out SLOT2 + cmp r1, #ENV_QUIET + bcs 2f + ldr r2, [lr, #0x14] + mov r5, r10, lsr #17 + add r2, r5, r2, lsr #16 + lookup_tl r2 + add r0, r0, r2 @ add to smp + +2: +.endm + + +.macro upd_algo5_m + + @ SLOT3 + make_eg_out SLOT3 + cmp r1, #ENV_QUIET + movcs r0, #0 + bcs 0f + ldr r2, [lr, #0x18] + ldr r0, [lr, #0x38] @ mem (signed) + mov r2, r2, lsr #16 + add r0, r2, r0, lsr #1 + lookup_tl r0 @ r0=output smp + +0: + @ SLOT4 + make_eg_out SLOT4 + cmp r1, #ENV_QUIET + bcs 1f + ldr r2, [lr, #0x1c] + mov r5, r10, lsr #17 + add r2, r5, r2, lsr #16 + lookup_tl r2 + add r0, r0, r2 @ add to smp + +1: @ SLOT2 + make_eg_out SLOT2 + cmp r1, #ENV_QUIET + bcs 2f + ldr r2, [lr, #0x14] + mov r5, r10, lsr #17 + add r2, r5, r2, lsr #16 + lookup_tl r2 + add r0, r0, r2 @ add to smp + +2: + mov r1, r10, asr #16 + str r1, [lr, #0x38] @ mem +.endm + + +.macro upd_algo6_m + + @ SLOT3 + make_eg_out SLOT3 + cmp r1, #ENV_QUIET + movcs r0, #0 + bcs 0f + ldr r0, [lr, #0x18] + mov r0, r0, lsr #16 @ 1ci + lookup_tl r0 @ r0=output smp + +0: + @ SLOT4 + make_eg_out SLOT4 + cmp r1, #ENV_QUIET + bcs 1f + ldr r2, [lr, #0x1c] + mov r2, r2, lsr #16 @ 1ci + lookup_tl r2 + add r0, r0, r2 @ add to smp + +1: @ SLOT2 + make_eg_out SLOT2 + cmp r1, #ENV_QUIET + bcs 2f + ldr r2, [lr, #0x14] + mov r5, r10, lsr #17 + add r2, r5, r2, lsr #16 + lookup_tl r2 + add r0, r0, r2 @ add to smp + +2: +.endm + + +.macro upd_algo7_m + + @ SLOT3 + make_eg_out SLOT3 + cmp r1, #ENV_QUIET + movcs r0, #0 + bcs 0f + ldr r0, [lr, #0x18] + mov r0, r0, lsr #16 @ 1ci + lookup_tl r0 @ r0=output smp + +0: + add r0, r0, r10, asr #16 + + @ SLOT4 + make_eg_out SLOT4 + cmp r1, #ENV_QUIET + bcs 1f + ldr r2, [lr, #0x1c] + mov r2, r2, lsr #16 @ 1ci + lookup_tl r2 + add r0, r0, r2 @ add to smp + +1: @ SLOT2 + make_eg_out SLOT2 + cmp r1, #ENV_QUIET + bcs 2f + ldr r2, [lr, #0x14] + mov r2, r2, lsr #16 @ 1ci + lookup_tl r2 + add r0, r0, r2 @ add to smp + +2: +.endm + + +.macro upd_slot1_m + + make_eg_out SLOT1 + cmp r1, #ENV_QUIET + movcs r10, r10, lsl #16 @ ct->op1_out <<= 16; // op1_out0 = op1_out1; op1_out1 = 0; + bcs 0f + ands r2, r12, #0xf000 + moveq r0, #0 + movne r2, r2, lsr #12 + addne r0, r10, r10, lsl #16 + movne r0, r0, asr #16 + movne r0, r0, lsl r2 + + ldr r2, [lr, #0x10] + mov r0, r0, lsr #16 + add r0, r0, r2, lsr #16 + lookup_tl r0 + mov r10,r10,lsl #16 @ ct->op1_out <<= 16; + mov r0, r0, lsl #16 + orr r10,r10, r0, lsr #16 + +0: +.endm + + +/* +.global update_eg_phase @ FM_SLOT *SLOT, UINT32 eg_cnt + +update_eg_phase: + stmfd sp!, {r5,r6} + mov r5, r0 @ slot + ldrh r3, [r5,#0x18] @ tl + ldrh r6, [r5,#0x1a] @ volume + add r6, r6, r3 + update_eg_phase_slot SLOT1 + mov r0, r6 + ldmfd sp!, {r5,r6} + bx lr +.pool + + +.global advance_lfo @ int lfo_ampm, UINT32 lfo_cnt_old, UINT32 lfo_cnt + +advance_lfo: + mov r12, r0, lsl #16 + advance_lfo_m + mov r0, r12, lsr #16 + bx lr +.pool + + +.global upd_algo0 @ chan_rend_context *c +upd_algo0: + stmfd sp!, {r4-r10,lr} + mov lr, r0 + + ldr r3, =ym_sin_tab + ldr r5, =ym_tl_tab + ldmia lr, {r6-r7} + ldr r10, [lr, #0x54] + ldr r12, [lr, #0x4c] + + upd_algo0_m + + ldmfd sp!, {r4-r10,pc} +.pool + + +.global upd_algo1 @ chan_rend_context *c +upd_algo1: + stmfd sp!, {r4-r10,lr} + mov lr, r0 + + ldr r3, =ym_sin_tab + ldr r5, =ym_tl_tab + ldmia lr, {r6-r7} + ldr r10, [lr, #0x54] + ldr r12, [lr, #0x4c] + + upd_algo1_m + + ldmfd sp!, {r4-r10,pc} +.pool + + +.global upd_algo2 @ chan_rend_context *c +upd_algo2: + stmfd sp!, {r4-r10,lr} + mov lr, r0 + + ldr r3, =ym_sin_tab + ldr r5, =ym_tl_tab + ldmia lr, {r6-r7} + ldr r10, [lr, #0x54] + ldr r12, [lr, #0x4c] + + upd_algo2_m + + ldmfd sp!, {r4-r10,pc} +.pool + + +.global upd_algo3 @ chan_rend_context *c +upd_algo3: + stmfd sp!, {r4-r10,lr} + mov lr, r0 + + ldr r3, =ym_sin_tab + ldr r5, =ym_tl_tab + ldmia lr, {r6-r7} + ldr r10, [lr, #0x54] + ldr r12, [lr, #0x4c] + + upd_algo3_m + + ldmfd sp!, {r4-r10,pc} +.pool + + +.global upd_algo4 @ chan_rend_context *c +upd_algo4: + stmfd sp!, {r4-r10,lr} + mov lr, r0 + + ldr r3, =ym_sin_tab + ldr r5, =ym_tl_tab + ldmia lr, {r6-r7} + ldr r10, [lr, #0x54] + ldr r12, [lr, #0x4c] + + upd_algo4_m + + ldmfd sp!, {r4-r10,pc} +.pool + + +.global upd_algo5 @ chan_rend_context *c +upd_algo5: + stmfd sp!, {r4-r10,lr} + mov lr, r0 + + ldr r3, =ym_sin_tab + ldr r5, =ym_tl_tab + ldmia lr, {r6-r7} + ldr r10, [lr, #0x54] + ldr r12, [lr, #0x4c] + + upd_algo5_m + + ldmfd sp!, {r4-r10,pc} +.pool + + +.global upd_algo6 @ chan_rend_context *c +upd_algo6: + stmfd sp!, {r4-r10,lr} + mov lr, r0 + + ldr r3, =ym_sin_tab + ldr r5, =ym_tl_tab + ldmia lr, {r6-r7} + ldr r10, [lr, #0x54] + ldr r12, [lr, #0x4c] + + upd_algo6_m + + ldmfd sp!, {r4-r10,pc} +.pool + + +.global upd_algo7 @ chan_rend_context *c +upd_algo7: + stmfd sp!, {r4-r10,lr} + mov lr, r0 + + ldr r3, =ym_sin_tab + ldr r5, =ym_tl_tab + ldmia lr, {r6-r7} + ldr r10, [lr, #0x54] + ldr r12, [lr, #0x4c] + + upd_algo7_m + + ldmfd sp!, {r4-r10,pc} +.pool + + +.global upd_slot1 @ chan_rend_context *c +upd_slot1: + stmfd sp!, {r4-r10,lr} + mov lr, r0 + + ldr r3, =ym_sin_tab + ldr r5, =ym_tl_tab + ldmia lr, {r6-r7} + ldr r10, [lr, #0x54] + ldr r12, [lr, #0x4c] + + upd_slot1_m + str r10, [lr, #0x38] + + ldmfd sp!, {r4-r10,pc} +.pool +*/ + + +@ lr=context, r12=pack (stereo, lastchan, disabled, lfo_enabled | pan_r, pan_l, ams[2] | AMmasks[4] | FB[4] | lfo_ampm[16]) +@ r0-r2=scratch, r3=sin_tab/scratch, r4=(length<<8)|algo, r5=tl_tab/slot, +@ r6-r7=vol_out[4], r8=eg_timer, r9=eg_timer_add[31:16], r10=op1_out, r11=buffer +.global chan_render_loop @ chan_rend_context *ct, int *buffer, int length + +chan_render_loop: + stmfd sp!, {r4-r11,lr} + mov lr, r0 + mov r4, r2, lsl #8 @ no more 24 bits here + ldr r12, [lr, #0x4c] + ldr r0, [lr, #0x50] + mov r11, r1 + and r0, r0, #7 + orr r4, r4, r0 @ (length<<8)|algo + add r0, lr, #0x44 + ldmia r0, {r8,r9} @ eg_timer, eg_timer_add + ldr r10, [lr, #0x54] @ op1_out + ldmia lr, {r6,r7} @ load volumes + + tst r12, #8 @ lfo? + beq crl_loop + +crl_loop_lfo: + add r0, lr, #0x30 + ldmia r0, {r1,r2} + add r2, r2, r1 + str r2, [lr, #0x30] + @ r12=lfo_ampm[31:16], r1=lfo_cnt_old, r2=lfo_cnt + advance_lfo_m + +crl_loop: + subs r4, r4, #0x100 + bmi crl_loop_end + + @ -- EG -- + add r8, r8, r9 + cmp r8, #EG_TIMER_OVERFLOW + bcc eg_done + add r0, lr, #0x3c + ldmia r0, {r1,r5} @ eg_cnt, CH +eg_loop: + sub r8, r8, #EG_TIMER_OVERFLOW + add r1, r1, #1 + @ SLOT1 (0) + @ r5=slot, r1=eg_cnt, trashes: r0,r2,r3 + update_eg_phase_slot SLOT1 + add r5, r5, #SLOT_STRUCT_SIZE*2 @ SLOT2 (2) + update_eg_phase_slot SLOT2 + sub r5, r5, #SLOT_STRUCT_SIZE @ SLOT3 (1) + update_eg_phase_slot SLOT3 + add r5, r5, #SLOT_STRUCT_SIZE*2 @ SLOT4 (3) + update_eg_phase_slot SLOT4 + + cmp r8, #EG_TIMER_OVERFLOW + subcs r5, r5, #SLOT_STRUCT_SIZE*3 + bcs eg_loop + str r1, [lr, #0x3c] + +eg_done: + + @ -- disabled? -- + and r0, r12, #0xC + cmp r0, #0xC + beq crl_loop_lfo + cmp r0, #0x4 + beq crl_loop + + @ -- SLOT1 -- + ldr r3, =ym_tl_tab + + @ lr=context, r12=pack (stereo, lastchan, disabled, lfo_enabled | pan_r, pan_l, ams[2] | AMmasks[4] | FB[4] | lfo_ampm[16]) + @ r0-r2=scratch, r3=tl_tab, r5=scratch, r6-r7=vol_out[4], r10=op1_out + upd_slot1_m + + @ -- SLOT2+ -- + and r0, r4, #7 + ldr pc, [pc, r0, lsl #2] + nop + .word crl_algo0 + .word crl_algo1 + .word crl_algo2 + .word crl_algo3 + .word crl_algo4 + .word crl_algo5 + .word crl_algo6 + .word crl_algo7 + .pool + +crl_algo0: + upd_algo0_m + b crl_algo_done + .pool + +crl_algo1: + upd_algo1_m + b crl_algo_done + .pool + +crl_algo2: + upd_algo2_m + b crl_algo_done + .pool + +crl_algo3: + upd_algo3_m + b crl_algo_done + .pool + +crl_algo4: + upd_algo4_m + b crl_algo_done + .pool + +crl_algo5: + upd_algo5_m + b crl_algo_done + .pool + +crl_algo6: + upd_algo6_m + b crl_algo_done + .pool + +crl_algo7: + upd_algo7_m + .pool + + +crl_algo_done: + @ -- WRITE SAMPLE -- + tst r0, r0 + beq ctl_sample_skip + tst r12, #1 + beq ctl_sample_mono + + tst r12, #0x20 @ L + ldrne r1, [r11] + addeq r11, r11, #4 + addne r1, r0, r1 + strne r1, [r11], #4 + tst r12, #0x10 @ R + ldrne r1, [r11] + addeq r11, r11, #4 + addne r1, r0, r1 + strne r1, [r11], #4 + b crl_do_phase + +ctl_sample_skip: + and r1, r12, #1 + add r1, r1, #1 + add r11,r11, r1, lsl #2 + b crl_do_phase + +ctl_sample_mono: + ldr r1, [r11] + add r1, r0, r1 + str r1, [r11], #4 + +crl_do_phase: + @ -- PHASE UPDATE -- + add r5, lr, #0x10 + ldmia r5, {r0-r1} + add r5, lr, #0x20 + ldmia r5, {r2-r3} + add r5, lr, #0x10 + add r0, r0, r2 + add r1, r1, r3 + stmia r5!,{r0-r1} + ldmia r5, {r0-r1} + add r5, lr, #0x28 + ldmia r5, {r2-r3} + add r5, lr, #0x18 + add r0, r0, r2 + add r1, r1, r3 + stmia r5, {r0-r1} + + tst r12, #8 + bne crl_loop_lfo + b crl_loop + + +crl_loop_end: + str r8, [lr, #0x44] @ eg_timer + str r12, [lr, #0x4c] @ pack (for lfo_ampm) + str r10, [lr, #0x54] @ op1_out + ldmfd sp!, {r4-r11,pc} + +.pool + diff --git a/_docs/license_gpl.txt b/_docs/license_gpl.txt new file mode 100644 index 00000000..e77696ae --- /dev/null +++ b/_docs/license_gpl.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/_docs/license_mame.txt b/_docs/license_mame.txt new file mode 100644 index 00000000..69bf6bc8 --- /dev/null +++ b/_docs/license_mame.txt @@ -0,0 +1,32 @@ +Copyright (c) 1997-2005, Nicola Salmoria and the MAME team +All rights reserved. + +Redistribution and use of this code or any derivative works are permitted +provided that the following conditions are met: + +* Redistributions may not be sold, nor may they be used in a commercial +product or activity. + +* Redistributions that are modified from the original source must include the +complete source code, including the source code for all components used by a +binary built from the modified sources. However, as a special exception, the +source code distributed need not include anything that is normally distributed +(in either source or binary form) with the major components (compiler, kernel, +and so on) of the operating system on which the executable runs, unless that +component itself accompanies the executable. + +* Redistributions must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other +materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/_docs/readme.txt b/_docs/readme.txt new file mode 100644 index 00000000..a814bef4 --- /dev/null +++ b/_docs/readme.txt @@ -0,0 +1,70 @@ + + +Compiling Symbian ports +----------------------- +First note: there is no WINS support, because I use assembly code in some +places and I don't think emulator is useful for this project because of it's +too different behaviour compared to real device. If you need wins support, +you will have to add it yourself. In that case, you will have to use a68k +instead of Cyclone and mz80 instead of DrZ80. Emulator does have support +for these, also there is equivalent c code for the asm stuff, but you will +have to dig the sources and figure everything out yourself. + +Exe: +Before building the exe you will need to compile Cyclone, use the included +vc6 project or see Cyclone.txt for more info. + +I don't use standard Symbian build methods for exe, because I use ARM +assembly files (*.s) and different compiler options for different files, +and this is difficult to achieve with .mmp files. Also I use Cylone +patcher, check \cyclone\epoc\ for more info. So I use custom makefile +instead, but to use it, UIQROOT2 environmental variable must be set to +the root of your UIQ SDK. So to build, you need to type something like +this in console window: + > SET UIQROOT2=C:\UIQ_21\ + > make -f picosmall.armi noecompxl=1 +(To use ECompXL, you must rename ECompXL's petran.exe to petran_.exe or +edit the makefile). + +Launcher: +There should be far less problems building that. Simply typing + > makmake PicodriveN.mmp armi + > make -f PicodriveN.armi +in console window with launcher directory set should build it without +problems. + + +Compiling GP2X port +------------------- +If you use devkitGP2X with gcc 4.0.2 and your paths are set correctly, running +'make' should be enough. If you are under Linux, you may need do some +adjustments, like changing case of filenames or setting up paths. I am sure +you will figure out yourself :) + + +License mess +------------ +The launcher for Symbian OS is based on Peter van Sebille's projects, +which are released under GPL (license_gpl.txt). + +YM2612 and sn76496 sound cores were taken from the MAME project, which is +under it's own license (license_mame.txt). + +Dave's Cyclone 68000 core, Pico library are under simple +"Free for non-commercial use, For commercial use, separate licencing +terms must be obtained" license. + +As far as I checked, both "Free for non-commercial use" and MAME licenses +might be incompatible with GPL, because GPL DOES allow commercial distribution. +But I don't think the original copyright holders (Peter, Dave, Reesy or the +MAME devs) would get very upset about this "violation", as this is both free +and open-source project. However, the whole project most likely falls under +GPL now (I don't know for sure as I'm just another coder, not a lawyer). +Alternatively, the launcher and exe can be viewed as separate programs +(technically this is true, they both use separate binaries, only protocol +is shared), so I hope nobody sees a problem here. + + +Contact +------- +My e-mail: notasas(atsymbol)gmail.com diff --git a/cpu/Cyclone/Cyclone.h b/cpu/Cyclone/Cyclone.h new file mode 100644 index 00000000..8913c261 --- /dev/null +++ b/cpu/Cyclone/Cyclone.h @@ -0,0 +1,58 @@ + +// Cyclone 68000 Emulator - Header File + +// Most code (c) Copyright 2004 Dave, All rights reserved. +// Some coding/bugfixing was done by notaz +// Cyclone 68000 is free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + +#ifdef __cplusplus +extern "C" { +#endif + +extern int CycloneVer; // Version number of library + +struct Cyclone +{ + unsigned int d[8]; // [r7,#0x00] + unsigned int a[8]; // [r7,#0x20] + unsigned int pc; // [r7,#0x40] Memory Base+PC + unsigned char srh; // [r7,#0x44] Status Register high (T_S__III) + unsigned char xc; // [r7,#0x45] Extend flag (____??X?) + unsigned char flags; // [r7,#0x46] Flags (ARM order: ____NZCV) [68k order is XNZVC] + unsigned char irq; // [r7,#0x47] IRQ level + unsigned int osp; // [r7,#0x48] Other Stack Pointer (USP/SSP) + unsigned int vector; // [r7,#0x4c] IRQ vector (temporary) + unsigned int pad1[2]; + int stopped; // [r7,#0x58] 1 == processor is in stopped state + int cycles; // [r7,#0x5c] + int membase; // [r7,#0x60] Memory Base (ARM address minus 68000 address) + unsigned int (*checkpc)(unsigned int pc); // [r7,#0x64] - Called to recalc Memory Base+pc + unsigned char (*read8 )(unsigned int a); // [r7,#0x68] + unsigned short (*read16 )(unsigned int a); // [r7,#0x6c] + unsigned int (*read32 )(unsigned int a); // [r7,#0x70] + void (*write8 )(unsigned int a,unsigned char d); // [r7,#0x74] + void (*write16)(unsigned int a,unsigned short d); // [r7,#0x78] + void (*write32)(unsigned int a,unsigned int d); // [r7,#0x7c] + unsigned char (*fetch8 )(unsigned int a); // [r7,#0x80] + unsigned short (*fetch16)(unsigned int a); // [r7,#0x84] + unsigned int (*fetch32)(unsigned int a); // [r7,#0x88] + void (*IrqCallback)(int int_level); // [r7,#0x8c] - optional irq callback function, see config.h + void (*ResetCallback)(); // [r7,#0x90] - if enabled in config.h, calls this whenever RESET opcode is encountered. + int (*UnrecognizedCallback)(); // [r7,#0x94] - if enabled in config.h, calls this whenever unrecognized opcode is encountered. +}; + +// used only if Cyclone was compiled with compressed jumptable, see config.h +void CycloneInit(); + +// run cyclone. Cycles should be specified in context (pcy->cycles) +void CycloneRun(struct Cyclone *pcy); + +// utility functions to get and set SR +void CycloneSetSr(struct Cyclone *pcy, unsigned int sr); // auto-swaps a7<->osp if detects supervisor change +unsigned int CycloneGetSr(struct Cyclone *pcy); + +#ifdef __cplusplus +} // End of extern "C" +#endif diff --git a/cpu/Cyclone/Cyclone.txt b/cpu/Cyclone/Cyclone.txt new file mode 100644 index 00000000..6e4749d8 --- /dev/null +++ b/cpu/Cyclone/Cyclone.txt @@ -0,0 +1,473 @@ + + _____ __ + / ___/__ __ ____ / /___ ___ ___ ___________________ + / /__ / // // __// // _ \ / _ \/ -_) ___________________ + \___/ \_, / \__//_/ \___//_//_/\__/ ___________________ + /___/ + ___________________ ____ ___ ___ ___ ___ + ___________________ / __// _ \ / _ \ / _ \ / _ \ + ___________________ / _ \/ _ // // // // // // / + \___/\___/ \___/ \___/ \___/ + +___________________________________________________________________________ + + Cyclone 68000 (c) Copyright 2004 Dave. Free for non-commercial use + + Homepage: http://www.finalburn.com/ + Dave's e-mail: dev(atsymbol)finalburn.com + Replace (atsymbol) with @ + + Additional coding and bugfixes done by notaz, 2005, 2006 + Homepage: http://mif.vu.lt/~grig2790/Cyclone/ + e-mail: notasas(atsymbol)gmail.com +___________________________________________________________________________ + + +What is it? +----------- + +Cyclone 68000 is an emulator for the 68000 microprocessor, written in ARM 32-bit assembly. +It is aimed at chips such as ARM7 and ARM9 cores, StrongARM and XScale, to interpret 68000 +code as fast as possible. + +Flags are mapped onto ARM flags whenever possible, which speeds up the processing of opcode. + + +What's New +---------- +v0.0086 notaz + + Cyclone now can be customized to better suit your project, see config.h . + + Added an option to compress the jumptable at compile-time. Must call CycloneInit() + at runtime to decompress it if enabled (see config.h). + + Added missing CHK opcode handler (used by SeaQuest DSV). + + Added missing TAS opcode handler (Gargoyles,Bubba N Stix,...). As in real genesis, + memory write-back phase is ignored (but can be enabled in config.h if needed). + + Added missing NBCD and TRAPV opcode handlers. + + Added missing addressing mode for CMP/EOR. + + Added some minor optimizations. + - Removed 216 handlers for 2927 opcodes which were generated for invalid addressing modes. + + Fixed flags for ASL, NEG, NEGX, DIVU, ADDX, SUBX, ROXR. + + Bugs fixed in MOVEP, LINK, ADDQ, DIVS handlers. + * Undocumented flags for CHK, ABCD, SBCD and NBCD are now emulated the same way as in Musashi. + + Added Uninitialized Interrupt emulation. + + Altered timing for about half of opcodes to match Musashi's. + +v0.0082 Reesy + + Change cyclone to clear cycles before returning when halted + + Added Irq call back function. This allows emulators to be notified + when cyclone has taken an interrupt allowing them to set internal flags + which can help fix timing problems. + +v0.0081 notaz + + .asm version was broken and did not compile with armasm. Fixed. + + Finished implementing Stop opcode. Now it really stops the processor. + +v0.0080 notaz + + Added real cmpm opcode, it was using eor handler before this. + Fixes Dune and Sensible Soccer. + +v0.0078 notaz + note: these bugs were actually found Reesy, I reimplemented these by + using his changelog as a guide. + + Fixed a problem with divu which was using long divisor instead of word. + Fixes gear switching in Top Gear 2. + + Fixed btst opcode, The bit to test should shifted a max of 31 or 7 + depending on if a register or memory location is being tested. + + Fixed abcd,sbcd. They did bad decimal correction on invalid BCD numbers + Score counters in Streets of Rage level end work now. + + Changed flag handling of abcd,sbcd,addx,subx,asl,lsl,... + Some ops did not have flag handling at all. + Some ops must not change Z flag when result is zero, but they did. + Shift ops must not change X if shift count is zero, but they did. + There are probably still some flag problems left. + + Patially implemented Stop and Reset opcodes - Fixes Thunderforce IV + +v0.0075 notaz + + Added missing displacement addressing mode for movem (Fantastic Dizzy) + + Added OSP <-> A7 swapping code in opcodes, which change privilege mode + + Implemented privilege violation, line emulator and divide by zero exceptions + + Added negx opcode (Shining Force works!) + + Added overflow detection for divs/divu + +v0.0072 notaz + note: I could only get v0.0069 cyclone, so I had to implement these myself using Dave's + changelog as a guide. + + Fixed a problem with divs - remainder should be negative when divident is negative + + Added movep opcode (Sonic 3 works) + + Fixed a problem with DBcc incorrectly decrementing if the condition is true (Shadow of the Beast) + +v0.0069 + + Added SBCD and the flags for ABCD/SBCD. Score and time now works in games such as + Rolling Thunder 2, Ghouls 'N Ghosts + + Fixed a problem with addx and subx with 8-bit and 16-bit values. + Ghouls 'N' Ghosts now works! + +v0.0068 + + Added ABCD opcode (Streets of Rage works now!) + +v0.0067 + + Added dbCC (After Burner) + + Added asr EA (Sonic 1 Boss/Labyrinth Zone) + + Added andi/ori/eori ccr (Altered Beast) + + Added trap (After Burner) + + Added special case for move.b (a7)+ and -(a7), stepping by 2 + After Burner is playable! Eternal Champions shows more + + Fixed lsr.b/w zero flag (Ghostbusters) + Rolling Thunder 2 now works! + + Fixed N flag for .b and .w arithmetic. Golden Axe works! + +v0.0066 + + Fixed a stupid typo for exg (orr r10,r10, not orr r10,r8), which caused alignment + crashes on Strider + +v0.0065 + + Fixed a problem with immediate values - they weren't being shifted up correctly for some + opcodes. Spiderman works, After Burner shows a bit of graphics. + + Fixed a problem with EA:"110nnn" extension word. 32-bit offsets were being decoded as 8-bit + offsets by mistake. Castlevania Bloodlines seems fine now. + + Added exg opcode + + Fixed asr opcode (Sonic jumping left is fixed) + + Fixed a problem with the carry bit in rol.b (Marble Madness) + +v0.0064 + + Added rtr + + Fixed addq/subq.l (all An opcodes are 32-bit) (Road Rash) + + Fixed various little timings + +v0.0063 + + Added link/unlk opcodes + + Fixed various little timings + + Fixed a problem with dbCC opcode being emitted at set opcodes + + Improved long register access, the EA fetch now does ldr r0,[r7,r0,lsl #2] whenever + possible, saving 1 or 2 cycles on many opcodes, which should give a nice speed up. + + May have fixed N flag on ext opcode? + + Added dasm for link opcode. + +v0.0062 + * I was a bit too keen with the Arithmetic opcodes! Some of them should have been abcd, + exg and addx. Removed the incorrect opcodes, pending re-adding them as abcd, exg and addx. + + Changed unknown opcodes to act as nops. + Not very technical, but fun - a few more games show more graphics ;) + +v0.0060 + + Fixed divu (EA intro) + + Added sf (set false) opcode - SOR2 + * Todo: pea/link/unlk opcodes + +v0.0059: Added remainder to divide opcodes. + + +The new stuff +------------- + +Before using Cyclone, be sure to customize config.h to better suit your project. All options +are documented inside that file. + +IrqCallback has been changed a bit, unlike in previous version, it should not return anything. +If you need to change IRQ level, you can safely do that in your handler. + +Cyclone has changed quite a bit from the time when Dave stopped updating it, but the rest of +documentation still applies, so read it if you haven't done that yet. If you have, check the +"Accessing ..." parts. + + +ARM Register Usage +------------------ + +See source code for up to date of register usage, however a summary is here: + + r0-3: Temporary registers + r4 : Current PC + Memory Base (i.e. pointer to next opcode) + r5 : Cycles remaining + r6 : Pointer to Opcode Jump table + r7 : Pointer to Cpu Context + r8 : Current Opcode + r9 : Flags (NZCV) in highest four bits + (r10 : Temporary source value or Memory Base) + (r11 : Temporary register) + + +How to Compile +-------------- + +Like Starscream and A68K, Cyclone uses a 'Core Creator' program which calculates and outputs +all possible 68000 Opcodes and a jump table into files called Cyclone.s and .asm +It then assembles these files into Cyclone.o and .obj + +Cyclone.o is the GCC assembled version and Cyclone.obj is the Microsoft assembled version. + +First unzip "Cyclone.zip" into a "Cyclone" directory. +If you are compiling for Windows CE, find ARMASM.EXE (the Microsoft ARM assembler) and +put it in the directory as well or put it on your path. + +Open up Cyclone.dsw in Visual Studio 6.0, compile and run the project. +Cyclone.obj and Cyclone.o will be created. + + +Compiling without Visual C++ +---------------------------- +If you aren't using Visual C++, it still shouldn't be too hard to compile, just get a C compiler, +compile all the CPPs and C file, link them into an EXE, and run the exe. + + e.g. gcc Main.cpp OpAny.cpp OpArith.cpp OpBranch.cpp OpLogic.cpp OpMove.cpp Disa.c + Main.exe + + +Adding to your project +---------------------- + +To add Cyclone to you project, add Cyclone.o or obj, and include Cyclone.h +There is one structure: 'struct Cyclone', and one function: CycloneRun + +Don't worry if this seem very minimal - its all you need to run as many 68000s as you want. +It works with both C and C++. + +Byteswapped Memory +------------------ + +If you have used Starscream, A68K or Turbo68K or similar emulators you'll be familiar with this! + +Any memory which the 68000 can access directly must be have every two bytes swapped around. +This is to speed up 16-bit memory accesses, because the 68000 has Big-Endian memory +and ARM has Little-Endian memory. + +Now you may think you only technically have to byteswap ROM, not RAM, because +16-bit RAM reads go through a memory handler and you could just return (mem[a]<<8) | mem[a+1]. + +This would work, but remember some systems can execute code from RAM as well as ROM, and +that would fail. +So it's best to use byteswapped ROM and RAM if the 68000 can access it directly. +It's also faster for the memory handlers, because you can do this: + + return *(unsigned short *)(mem+a) + + +Declaring Memory handlers +------------------------- + +Before you can reset or execute 68000 opcodes you must first set up a set of memory handlers. +There are 7 functions you have to set up per CPU, like this: + + static unsigned int MyCheckPc(unsigned int pc) + static unsigned char MyRead8 (unsigned int a) + static unsigned short MyRead16 (unsigned int a) + static unsigned int MyRead32 (unsigned int a) + static void MyWrite8 (unsigned int a,unsigned char d) + static void MyWrite16(unsigned int a,unsigned short d) + static void MyWrite32(unsigned int a,unsigned int d) + +You can think of these functions representing the 68000's memory bus. +The Read and Write functions are called whenever the 68000 reads or writes memory. +For example you might set MyRead8 like this: + + unsigned char MyRead8(unsigned int a) + { + a&=0xffffff; // Clip address to 24-bits + + if (a=0xe00000) return RamData[(a^1)&0xffff]; + return 0xff; // Out of range memory access + } + +The other 5 read/write functions are similar. I'll describe the CheckPc function later on. + +Declaring a CPU Context +----------------------- + +To declare a CPU simple declare a struct Cyclone in your code. For example to declare +two 68000s: + + struct Cyclone MyCpu; + struct Cyclone MyCpu2; + +It's probably a good idea to initialise the memory to zero: + + memset(&MyCpu, 0,sizeof(MyCpu)); + memset(&MyCpu2,0,sizeof(MyCpu2)); + +Next point to your memory handlers: + + MyCpu.checkpc=MyCheckPc; + MyCpu.read8 =MyRead8; + MyCpu.read16 =MyRead16; + MyCpu.read32 =MyRead32; + MyCpu.write8 =MyWrite8; + MyCpu.write16=MyWrite16; + MyCpu.write32=MyWrite32; + +You also need to point the fetch handlers - for most systems out there you can just +point them at the read handlers: + MyCpu.fetch8 =MyRead8; + MyCpu.fetch16 =MyRead16; + MyCpu.fetch32 =MyRead32; + +( Why a different set of function pointers for fetch? + Well there are some systems, the main one being CPS2, which return different data + depending on whether the 'fetch' line on the 68000 bus is high or low. + If this is the case, you can set up different functions for fetch reads. + Generally though you don't need to. ) + +Now you are nearly ready to reset the 68000, except you need one more function: checkpc(). + +The checkpc() function +---------------------- + +When Cyclone reads opcodes, it doesn't use a memory handler every time, this would be +far too slow, instead it uses a direct pointer to ARM memory. +For example if your Rom image was at 0x3000000 and the program counter was $206, +Cyclone's program counter would be 0x3000206. + +The difference between an ARM address and a 68000 address is also stored in a variable called +'membase'. In the above example it's 0x3000000. To retrieve the real PC, Cyclone just +subtracts 'membase'. + +When a long jump happens, Cyclone calls checkpc(). If the PC is in a different bank, +for example Ram instead of Rom, change 'membase', recalculate the new PC and return it: + +static int MyCheckPc(unsigned int pc) +{ + pc-=MyCpu.membase; // Get the real program counter + + if (pc=0xff0000) MyCpu.membase=(int)RamMem-0xff0000; // Jump to Ram + + return MyCpu.membase+pc; // New program counter +} + +Notice that the membase is always ARM address minus 68000 address. + +The above example doesn't consider mirrored ram, but for an example of what to do see +PicoDrive (in Memory.cpp). + + +Almost there - Reset the 68000! +------------------------------- + +Next we need to Reset the 68000 to get the initial Program Counter and Stack Pointer. This +is obtained from addresses 000000 and 000004. + +Here is code which resets the 68000 (using your memory handlers): + + MyCpu.srh=0x27; // Set supervisor mode + MyCpu.a[7]=MyCpu.read32(0); // Get Stack Pointer + MyCpu.membase=0; + MyCpu.pc=MyCpu.checkpc(MyCpu.read32(4)); // Get Program Counter + +And that's ready to go. + + +Executing the 68000 +------------------- + +To execute the 68000, set the 'cycles' variable to the number of cycles you wish to execute, +and then call CycloneRun with a pointer to the Cyclone structure. + +e.g.: + // Execute 1000 cycles on the 68000: + MyCpu.cycles=1000; CycloneRun(&MyCpu); + +For each opcode, the number of cycles it took is subtracted and the function returns when +it reaches 0. + +e.g. + // Execute one instruction on the 68000: + MyCpu.cycles=0; CycloneRun(&MyCpu); + printf(" The opcode took %d cycles\n", -MyCpu.cycles); + +You should try to execute as many cycles as you can for maximum speed. +The number actually executed may be slightly more than requested, i.e. cycles may come +out with a small negative value: + +e.g. + int todo=12000000/60; // 12Mhz, for one 60hz frame + MyCpu.cycles=todo; CycloneRun(&MyCpu); + printf(" Actually executed %d cycles\n", todo-MyCpu.cycles); + +To calculate the number of cycles executed, use this formula: + Number of cycles requested - Cycle counter at the end + + +Interrupts +---------- + +Causing an interrupt is very simple, simply set the irq variable in the Cyclone structure +to the IRQ number. +To lower the IRQ line, set it to zero. + +e.g: + MyCpu.irq=6; // Interrupt level 6 + MyCpu.cycles=20000; CycloneRun(&MyCpu); + +Note that the interrupt is not actually processed until the next call to CycloneRun, +and the interrupt may not be taken until the 68000 interrupt mask is changed to allow it. + +( The IRQ isn't checked on exiting from a memory handler: I don't think this will cause + me any trouble because I've never needed to trigger an interrupt from a memory handler, + but if someone needs to, let me know...) + + +Accessing Cycle Counter +----------------------- + +The cycle counter in the Cyclone structure is not, by default, updated before +calling a memory handler, only at the end of an execution. + +*update* +Now this is configurable in config.h, there is no 'debug' variable. + + +Accessing Program Counter and registers +--------------------------------------- + +You can read Cyclone's registers directly from the structure at any time (as far as I know). + +The Program Counter, should you need to read or write it, is stored with membase +added on. So use this formula to calculate the real 68000 program counter: + + pc = MyCpu.pc - MyCpu.membase; + +The program counter is stored in r4 during execution, and isn't written back to the +structure until the end of execution, which means you can't read normally real it from +a memory handler. + +*update* +Now this is configurable in config.h, there is no 'debug' variable. You can even enable +access to SR if you need. However changing PC in memhandlers is still not safe, you should +better clear cycles, wait untill CycloneRun() returns and then do whatever you need. + + +Emulating more than one CPU +--------------------------- + +Since everything is based on the structures, emulating more than one cpu at the same time +is just a matter of declaring more than one structures and timeslicing. You can emulate +as many 68000s as you want. +Just set up the memory handlers for each cpu and run each cpu for a certain number of cycles. + +e.g. + // Execute 1000 cycles on 68000 #1: + MyCpu.cycles=1000; CycloneRun(&MyCpu); + + // Execute 1000 cycles on 68000 #2: + MyCpu2.cycles=1000; CycloneRun(&MyCpu2); + + +Thanks to... +------------ + +* All the previous code-generating assembler cpu core guys! + Who are iirc... Neill Corlett, Neil Bradley, Mike Coates, Darren Olafson + and Bart Trzynadlowski + +* Charles Macdonald, for researching just about every console ever +* MameDev+FBA, for keeping on going and going and going + + +------------- + +Dave - 17th April 2004 +notaz - 17th July 2006 + +Homepage: http://www.finalburn.com/ +Dave's e-mail: dev(atsymbol)finalburn.com +Replace (atsymbol) with @ diff --git a/cpu/Cyclone/Disa/Disa.c b/cpu/Cyclone/Disa/Disa.c new file mode 100644 index 00000000..e0d00b5d --- /dev/null +++ b/cpu/Cyclone/Disa/Disa.c @@ -0,0 +1,821 @@ + +// Dave's Disa 68000 Disassembler +#ifndef __GNUC__ +#pragma warning(disable:4115) +#endif +#include +#include +#include "Disa.h" + +unsigned int DisaPc=0; +char *DisaText=NULL; // Text buffer to write in +static char Tasm[]="bwl?"; +static char Comment[64]=""; +unsigned short (CPU_CALL *DisaWord)(unsigned int a)=NULL; + +static unsigned int DisaLong(unsigned int a) +{ + unsigned int d=0; + if (DisaWord==NULL) return d; + + d= DisaWord(a)<<16; + d|=DisaWord(a+2)&0xffff; + return d; +} + +// Get text version of the effective address +int DisaGetEa(char *t,int ea,int size) +{ + ea&=0x3f; t[0]=0; + if ((ea&0x38)==0x00) { sprintf(t,"d%d",ea ); return 0; } // 000rrr + if ((ea&0x38)==0x08) { sprintf(t,"a%d",ea&7); return 0; } // 001rrr + if ((ea&0x38)==0x10) { sprintf(t,"(a%d)",ea&7); return 0; } // 010rrr + if ((ea&0x38)==0x18) { sprintf(t,"(a%d)+",ea&7); return 0; } // 011rrr + if ((ea&0x38)==0x20) { sprintf(t,"-(a%d)",ea&7); return 0; } // 100rrr + if ((ea&0x38)==0x28) { sprintf(t,"($%x,a%d)",DisaWord(DisaPc)&0xffff,ea&7); DisaPc+=2; return 0; } // 101rrr + + if ((ea&0x38)==0x30) + { + // 110nnn - An + Disp + D/An + int areg=0,ext=0,off=0,da=0,reg=0,wol=0,scale=0; + ext=DisaWord(DisaPc)&0xffff; + + areg=ea&7; + off=ext&0xff; da =ext&0x8000?'a':'d'; + reg=(ext>>12)&7; wol=ext&0x0800?'l':'w'; + scale=1<<((ext>>9)&3); + + if (scale<2) sprintf(t,"($%x,a%d,%c%d.%c)", off,areg,da,reg,wol); + else sprintf(t,"($%x,a%d,%c%d.%c*%d)",off,areg,da,reg,wol,scale); // 68020 + + DisaPc+=2; + return 0; + } + + if (ea==0x38) { sprintf(t,"$%x.w",DisaWord(DisaPc)&0xffff); DisaPc+=2; return 0; } // 111000 - Absolute short + if (ea==0x39) { sprintf(t,"$%x.l",DisaLong(DisaPc)); DisaPc+=4; return 0; } // 111001 - Absolute long + + if (ea==0x3a) + { + // 111010 - PC Relative + int ext=DisaWord(DisaPc)&0xffff; + sprintf(t,"($%x,pc)",ext); + sprintf(Comment,"; =%x",DisaPc+(short)ext); // Comment where pc+ext is + DisaPc+=2; + return 0; + } + + if (ea==0x3b) + { + // 111011 - PC Relative + D/An + int ext=0,off=0,da=0,reg=0,wol=0,scale=0; + ext=DisaWord(DisaPc)&0xffff; + + off=ext&0xff; da =ext&0x8000?'a':'d'; + reg=(ext>>12)&7; wol=ext&0x0800?'l':'w'; + scale=1<<((ext>>9)&3); + + if (scale<2) sprintf(t,"($%x,pc,%c%d.%c)", off,da,reg,wol); + else sprintf(t,"($%x,pc,%c%d.%c*%d)",off,da,reg,wol,scale); // 68020 + + sprintf(Comment,"; =%x",DisaPc+(char)off); // Comment where pc+ext is + DisaPc+=2; + return 0; + } + + if (ea==0x3c) + { + // 111100 - Immediate + switch (size) + { + case 0: sprintf(t,"#$%x",DisaWord(DisaPc)&0x00ff); DisaPc+=2; return 0; + case 1: sprintf(t,"#$%x",DisaWord(DisaPc)&0xffff); DisaPc+=2; return 0; + case 2: sprintf(t,"#$%x",DisaLong(DisaPc) ); DisaPc+=4; return 0; + } + return 1; + } + +// Unknown effective address + sprintf(t,"ea=(%d%d%d %d%d%d)", + (ea>>5)&1,(ea>>4)&1,(ea>>3)&1, + (ea>>2)&1,(ea>>1)&1, ea &1); + return 1; +} + +static void GetOffset(char *text) +{ + int off=(short)DisaWord(DisaPc); DisaPc+=2; + + if (off<0) sprintf(text,"-$%x",-off); + else sprintf(text,"$%x", off); +} + +// ================ Opcodes 0x0000+ ================ +static int DisaArithImm(int op) +{ + // Or/And/Sub/Add/Eor/Cmp Immediate 0000ttt0 xxDDDddd (tt=type, xx=size extension, DDDddd=Dest ea) + int dea=0; + char seat[64]="",deat[64]=""; + int type=0,size=0; + char *arith[8]={"or","and","sub","add","?","eor","cmp","?"}; + + type=(op>>9)&7; if (type==4 || type>=7) return 1; + size=(op>>6)&3; if (size>=3) return 1; + dea=op&0x3f; if (dea==0x3c) return 1; + + DisaGetEa(seat,0x3c,size); + DisaGetEa(deat,dea, size); + + sprintf(DisaText,"%si.%c %s, %s",arith[type],Tasm[size],seat,deat); + return 0; +} + +// ================ Opcodes 0x0108+ ================ +static int DisaMovep(int op) +{ + // movep.x (Aa),Dn - 0000nnn1 dx001aaa nn + int dn=0,dir=0,size=0,an=0; + char offset[32]=""; + + dn =(op>>9)&7; + dir =(op>>7)&1; + size=(op>>6)&1; size++; + an = op &7; + + GetOffset(offset); + if (dir) sprintf(DisaText,"movep.%c d%d, (%s,a%d)",Tasm[size],dn,offset,an); + else sprintf(DisaText,"movep.%c (%s,a%d), d%d",Tasm[size],offset,an,dn); + + return 0; +} + +// ================ Opcodes 0x007c+ ================ +static int DisaArithSr(int op) +{ + // Ori/Andi/Eori $nnnn,sr 0000t0tx 0s111100 + char *opcode[6]={"ori","andi","","","","eori"}; + char seat[64]=""; + int type=0,size=0; + + type=(op>>9)&5; + size=(op>>6)&1; + + DisaGetEa(seat,0x3c,size); + sprintf(DisaText,"%s.%c %s, %s", opcode[type], Tasm[size], seat, size?"sr":"ccr"); + + return 0; +} + +// ================ Opcodes 0x0100+ ================ +static int DisaBtstReg(int op) +{ + // Btst/Bchg/Bclr/Bset 0000nnn1 tteeeeee (nn=reg number, eeeeee=Dest ea) + int type=0; + int sea=0,dea=0; + char seat[64]="",deat[64]=""; + char *opcode[4]={"btst","bchg","bclr","bset"}; + + sea =(op>>9)&7; + type=(op>>6)&3; + dea= op&0x3f; + + if ((dea&0x38)==0x08) return 1; // movep + DisaGetEa(seat,sea,0); + DisaGetEa(deat,dea,0); + + sprintf(DisaText,"%s %s, %s",opcode[type],seat,deat); + return 0; +} + +// ================ Opcodes 0x0800+ ================ +static int DisaBtstImm(int op) +{ + // Btst/Bchg/Bclr/Bset 00001000 tteeeeee 00 nn (eeeeee=ea, nn=bit number) + int type=0; + char seat[64]="",deat[64]=""; + char *opcode[4]={"btst","bchg","bclr","bset"}; + + type=(op>>6)&3; + DisaGetEa(seat, 0x3c,0); + DisaGetEa(deat,op&0x3f,0); + + sprintf(DisaText,"%s %s, %s",opcode[type],seat,deat); + return 0; +} + +// ================ Opcodes 0x1000+ ================ +static int DisaMove(int op) +{ + // Move 00xxdddD DDssssss (xx=size extension, ssssss=Source EA, DDDddd=Dest ea) + int sea=0,dea=0; + char inst[64]="",seat[64]="",deat[64]=""; + char *movea=""; + int size=0; + + if ((op&0x01c0)==0x0040) movea="a"; // See if it's a movea opcode + + // Find size extension + switch (op&0x3000) + { + case 0x1000: size=0; break; + case 0x3000: size=1; break; + case 0x2000: size=2; break; + default: return 1; + } + + sea = op&0x003f; + DisaGetEa(seat,sea,size); + + dea =(op&0x01c0)>>3; + dea|=(op&0x0e00)>>9; + DisaGetEa(deat,dea,size); + + sprintf(inst,"move%s.%c",movea,Tasm[size]); + sprintf(DisaText,"%s %s, %s",inst,seat,deat); + return 0; +} + +// ================ Opcodes 0x4000+ ================ +static int DisaNeg(int op) +{ + // 01000tt0 xxeeeeee (tt=negx/clr/neg/not, xx=size, eeeeee=EA) + char eat[64]=""; + int type=0,size=0; + char *opcode[4]={"negx","clr","neg","not"}; + + type=(op>>9)&3; + size=(op>>6)&3; if (size>=3) return 1; + DisaGetEa(eat,op&0x3f,size); + + sprintf(DisaText,"%s.%c %s",opcode[type],Tasm[size],eat); + return 0; +} + +// ================ Opcodes 0x40c0+ ================ +static int DisaMoveSr(int op) +{ + // 01000tt0 11eeeeee (tt=type, xx=size, eeeeee=EA) + int type=0,ea=0; + char eat[64]=""; + + type=(op>>9)&3; + ea=op&0x3f; + DisaGetEa(eat,ea,1); + + switch (type) + { + default: sprintf(DisaText,"move sr, %s", eat); break; + case 1: sprintf(DisaText,"move ccr, %s",eat); break; + case 2: sprintf(DisaText,"move %s, ccr",eat); break; + case 3: sprintf(DisaText,"move %s, sr", eat); break; + } + return 0; +} + +// ================ Opcodes 0x41c0+ ================ +static int DisaLea(int op) +{ + // Lea 0100nnn1 11eeeeee (eeeeee=ea) + int sea=0,dea=0; + char seat[64]="",deat[64]=""; + + sea=op&0x003f; + DisaGetEa(seat,sea,0); + + dea=(op>>9)&7; dea|=8; + DisaGetEa(deat,dea,2); + + sprintf(DisaText,"lea %s, %s",seat,deat); + return 0; +} + +static int MakeRegList(char *list,int mask,int ea) +{ + int reverse=0,i=0,low=0,len=0; + + if ((ea&0x38)==0x20) reverse=1; // -(An), bitfield is reversed + + mask&=0xffff; list[0]=0; + + for (i=0;i<17;i++) + { + int bit=0; + + // Mask off bit i: + if (reverse) bit=0x8000>>i; else bit=1<0) if (list[len-1]=='/') list[len-1]=0; + return 0; +} + +// ================ Opcodes 0x4840+ ================ +static int DisaSwap(int op) +{ + // Swap, 01001000 01000nnn swap Dn + sprintf(DisaText,"swap d%d",op&7); + return 0; +} + +// ================ Opcodes 0x4850+ ================ +static int DisaPea(int op) +{ + // Pea 01001000 01eeeeee (eeeeee=ea) pea + int ea=0; + char eat[64]=""; + + ea=op&0x003f; if (ea<0x10) return 1; // swap opcode + DisaGetEa(eat,ea,2); + + sprintf(DisaText,"pea %s",eat); + return 0; +} + +// ================ Opcodes 0x4880+ ================ +static int DisaExt(int op) +{ + // Ext 01001000 1x000nnn (x=size, eeeeee=EA) + char eat[64]=""; + int size=0; + + size=(op>>6)&1; size++; + DisaGetEa(eat,op&0x3f,size); + + sprintf(DisaText,"ext.%c %s",Tasm[size],eat); + return 0; +} + +// ================ Opcodes 0x4890+ ================ +static int DisaMovem(int op) +{ + // Movem 01001d00 1xeeeeee regmask d=direction, x=size, eeeeee=EA + int dir=0,size=0; + int ea=0,mask=0; + char list[64]="",eat[64]=""; + + dir=(op>>10)&1; + size=((op>>6)&1)+1; + ea=op&0x3f; if (ea<0x10) return 1; // ext opcode + + mask=DisaWord(DisaPc)&0xffff; DisaPc+=2; + + MakeRegList(list,mask,ea); // Turn register mask into text + DisaGetEa(eat,ea,size); + + if (dir) sprintf(DisaText,"movem.%c %s, %s",Tasm[size],eat,list); + else sprintf(DisaText,"movem.%c %s, %s",Tasm[size],list,eat); + return 0; +} + +// ================ Opcodes 0x4e40+ ================ +static int DisaTrap(int op) +{ + sprintf(DisaText,"trap #%d",op&0xf); + return 0; +} + +// ================ Opcodes 0x4e50+ ================ +static int DisaLink(int op) +{ + // Link opcode, 01001110 01010nnn dd link An,#offset + char eat[64]=""; + char offset[32]=""; + + DisaGetEa(eat,(op&7)|8,0); + GetOffset(offset); + + sprintf(DisaText,"link %s,#%s",eat,offset); + + return 0; +} + +// ================ Opcodes 0x4e58+ ================ +static int DisaUnlk(int op) +{ + // Link opcode, 01001110 01011nnn dd unlk An + char eat[64]=""; + + DisaGetEa(eat,(op&7)|8,0); + sprintf(DisaText,"unlk %s",eat); + + return 0; +} + +// ================ Opcodes 0x4e60+ ================ +static int DisaMoveUsp(int op) +{ + // Move USP opcode, 01001110 0110dnnn move An to/from USP (d=direction) + int ea=0,dir=0; + char eat[64]=""; + + dir=(op>>3)&1; + ea=(op&7)|8; + DisaGetEa(eat,ea,0); + + if (dir) sprintf(DisaText,"move usp, %s",eat); + else sprintf(DisaText,"move %s, usp",eat); + return 0; +} + +// ================ Opcodes 0x4e70+ ================ +static int Disa4E70(int op) +{ + char *inst[8]={"reset","nop","stop","rte","rtd","rts","trapv","rtr"}; + int n=0; + + n=op&7; + + sprintf(DisaText,"%s",inst[n]); + + //todo - 'stop' with 16 bit data + + return 0; +} + +// ================ Opcodes 0x4a00+ ================ +static int DisaTst(int op) +{ + // Tst 01001010 xxeeeeee (eeeeee=ea) + int ea=0; + char eat[64]=""; + int size=0; + + ea=op&0x003f; + DisaGetEa(eat,ea,0); + size=(op>>6)&3; if (size>=3) return 1; + + sprintf(DisaText,"tst.%c %s",Tasm[size],eat); + return 0; +} + +// ================ Opcodes 0x4e80+ ================ +static int DisaJsr(int op) +{ + // Jsr/Jmp 0100 1110 1mEE Eeee (eeeeee=ea m=1=jmp) + int sea=0; + char seat[64]=""; + + sea=op&0x003f; + DisaGetEa(seat,sea,0); + + sprintf(DisaText,"j%s %s", op&0x40?"mp":"sr", seat); + return 0; +} + +// ================ Opcodes 0x5000+ ================ +static int DisaAddq(int op) +{ + // 0101nnnt xxeeeeee (nnn=#8,1-7 t=addq/subq xx=size, eeeeee=EA) + int num=0,type=0,size=0,ea=0; + char eat[64]=""; + + num =(op>>9)&7; if (num==0) num=8; + type=(op>>8)&1; + size=(op>>6)&3; if (size>=3) return 1; + ea = op&0x3f; + + DisaGetEa(eat,ea,size); + + sprintf(DisaText,"%s.%c #%d, %s",type?"subq":"addq",Tasm[size],num,eat); + return 0; +} + +// ================ Opcodes 0x50c0+ ================ +static int DisaSet(int op) +{ + // 0101cccc 11eeeeee (sxx ea) + static char *cond[16]= + {"t" ,"f", "hi","ls","cc","cs","ne","eq", + "vc","vs","pl","mi","ge","lt","gt","le"}; + char *cc=""; + int ea=0; + char eat[64]=""; + + cc=cond[(op>>8)&0xf]; // Get condition code + ea=op&0x3f; + if ((ea&0x38)==0x08) return 1; // dbra, not scc + + DisaGetEa(eat,ea,0); + sprintf(DisaText,"s%s %s",cc,eat); + return 0; +} + +// ================ Opcodes 0x50c8+ ================ +static int DisaDbra(int op) +{ + // 0101cccc 11001nnn offset (dbra/dbxx Rn,offset) + int dea=0; char deat[64]=""; + int pc=0,Offset=0; + + static char *BraCode[16]= + {"bt" ,"bra","bhi","bls","bcc","bcs","bne","beq", + "bvc","bvs","bpl","bmi","bge","blt","bgt","ble"}; + char *Bra=""; + + dea=op&7; + DisaGetEa(deat,dea,2); + + // Get condition code + Bra=BraCode[(op>>8)&0xf]; + + // Get offset + pc=DisaPc; + Offset=(short)DisaWord(DisaPc); DisaPc+=2; + + sprintf(DisaText,"d%s %s, %x",Bra,deat,pc+Offset); + return 0; +} + +// ================ Opcodes 0x6000+ ================ +static int DisaBranch(int op) +{ + // Branch 0110cccc nn (cccc=condition) + int pc=0,Offset=0; + + static char *BraCode[16]= + {"bra","bsr","bhi","bls","bcc","bcs","bne","beq", + "bvc","bvs","bpl","bmi","bge","blt","bgt","ble"}; + char *Bra=""; + + // Get condition code + Bra=BraCode[(op>>8)&0x0f]; + + // Get offset + pc=DisaPc; + Offset=(char)(op&0xff); + if (Offset== 0) { Offset=(short)DisaWord(DisaPc); DisaPc+=2; } + else if (Offset==-1) { Offset= DisaLong(DisaPc); DisaPc+=4; } + + sprintf(DisaText,"%s %x",Bra,pc+Offset); + return 0; +} + +// ================ Opcodes 0x7000+ ================ +static int DisaMoveq(int op) +{ + // Moveq 0111rrr0 nn (rrr=Dest register, nn=data) + + int dea=0; char deat[64]=""; + char *inst="moveq"; + int val=0; + + dea=(op>>9)&7; + DisaGetEa(deat,dea,2); + + val=(char)(op&0xff); + sprintf(DisaText,"%s #$%x, %s",inst,val,deat); + return 0; +} + +// ================ Opcodes 0x8000+ ================ +static int DisaArithReg(int op) +{ + // 1t0tnnnd xxeeeeee (tt=type:or/sub/and/add xx=size, eeeeee=EA) + int type=0,size=0,dir=0,rea=0,ea=0; + char reat[64]="",eat[64]=""; + char *opcode[]={"or","sub","","","and","add"}; + + type=(op>>12)&5; + rea =(op>> 9)&7; + dir =(op>> 8)&1; + size=(op>> 6)&3; if (size>=3) return 1; + ea = op&0x3f; + + if (dir && ea<0x10) return 1; // addx opcode + + DisaGetEa(reat,rea,size); + DisaGetEa( eat, ea,size); + + if (dir) sprintf(DisaText,"%s.%c %s, %s",opcode[type],Tasm[size],reat,eat); + else sprintf(DisaText,"%s.%c %s, %s",opcode[type],Tasm[size],eat,reat); + return 0; +} + +// ================ Opcodes 0x8100+ ================ +static int DisaAbcd(int op) +{ + // 1t00ddd1 0000asss - sbcd/abcd Ds,Dd or -(As),-(Ad) + int type=0; + int dn=0,addr=0,sn=0; + char *opcode[]={"sbcd","abcd"}; + + type=(op>>14)&1; + dn =(op>> 9)&7; + addr=(op>> 3)&1; + sn = op &7; + + if (addr) sprintf(DisaText,"%s -(a%d), -(a%d)",opcode[type],sn,dn); + else sprintf(DisaText,"%s d%d, d%d", opcode[type],sn,dn); + + return 0; +} + +// ================ Opcodes 0x80c0+ ================ +static int DisaMul(int op) +{ + // Div/Mul: 1m00nnns 11eeeeee (m=Mul, nnn=Register Dn, s=signed, eeeeee=EA) + int type=0,rea=0,sign=0,ea=0,size=1; + char reat[64]="",eat[64]=""; + char *opcode[2]={"div","mul"}; + + type=(op>>14)&1; // div/mul + rea =(op>> 9)&7; + sign=(op>> 8)&1; + ea = op&0x3f; + + DisaGetEa(reat,rea,size); + DisaGetEa( eat, ea,size); + + sprintf(DisaText,"%s%c.%c %s, %s",opcode[type],sign?'s':'u',Tasm[size],eat,reat); + return 0; +} + +// ================ Opcodes 0x90c0+ ================ +static int DisaAritha(int op) +{ + // Suba/Cmpa/Adda 1tt1nnnx 11eeeeee (tt=type, x=size, eeeeee=Source EA) + int type=0,size=0,sea=0,dea=0; + char seat[64]="",deat[64]=""; + char *aritha[4]={"suba","cmpa","adda",""}; + + type=(op>>13)&3; if (type>=3) return 1; + size=(op>>8)&1; size++; + dea =(op>>9)&7; dea|=8; // Dest=An + sea = op&0x003f; // Source + + DisaGetEa(seat,sea,size); + DisaGetEa(deat,dea,size); + + sprintf(DisaText,"%s.%c %s, %s",aritha[type],Tasm[size],seat,deat); + return 0; +} + +// ================ Opcodes 0xb000+ ================ +static int DisaCmpEor(int op) +{ + // Cmp/Eor 1011rrrt xxeeeeee (rrr=Dn, t=cmp/eor, xx=size extension, eeeeee=ea) + char reat[64]="",eat[64]=""; + int type=0,size=0; + + type=(op>>8)&1; + size=(op>>6)&3; if (size>=3) return 1; + DisaGetEa(reat,(op>>9)&7,size); + DisaGetEa(eat, op&0x3f, size); + + if (type) sprintf(DisaText,"eor.%c %s, %s",Tasm[size],reat,eat); + else sprintf(DisaText,"cmp.%c %s, %s",Tasm[size],eat,reat); + return 0; +} + +// ================ Opcodes 0xc140+ ================ +// 1100ttt1 01000sss exg ds,dt +// 1100ttt1 01001sss exg as,at +// 1100ttt1 10001sss exg as,dt +static int DisaExg(int op) +{ + int tr=0,type=0,sr=0; + + tr =(op>>9)&7; + type= op&0xf8; + sr = op&7; + + if (type==0x40) sprintf(DisaText,"exg d%d, d%d",sr,tr); + else if (type==0x48) sprintf(DisaText,"exg a%d, a%d",sr,tr); + else if (type==0x88) sprintf(DisaText,"exg a%d, d%d",sr,tr); + else return 1; + + return 0; +} + +// ================ Opcodes 0xd100+ ================ +static int DisaAddx(int op) +{ + // 1t01ddd1 xx000sss addx + int type=0,size=0,dea=0,sea=0; + char deat[64]="",seat[64]=""; + char *opcode[6]={"","subx","","","","addx"}; + + type=(op>>12)&5; + dea =(op>> 9)&7; + size=(op>> 6)&3; if (size>=3) return 1; + sea = op&0x3f; + + DisaGetEa(deat,dea,size); + DisaGetEa(seat,sea,size); + + sprintf(DisaText,"%s.%c %s, %s",opcode[type],Tasm[size],seat,deat); + return 0; +} + +// ================ Opcodes 0xe000+ ================ +static char *AsrName[4]={"as","ls","rox","ro"}; +static int DisaAsr(int op) +{ + // Asr/l/Ror/l etc - 1110cccd xxuttnnn + // (ccc=count, d=direction xx=size extension, u=use reg for count, tt=type, nnn=register Dn) + int count=0,dir=0,size=0,usereg=0,type=0,num=0; + + count =(op>>9)&7; + dir =(op>>8)&1; + size =(op>>6)&3; if (size>=3) return 1; // todo Asr EA + usereg=(op>>5)&1; + type =(op>>3)&3; + num = op &7; // Register number + + if (usereg==0) count=((count-1)&7)+1; // because ccc=000 means 8 + + sprintf(DisaText,"%s%c.%c %c%d, d%d", + AsrName[type], dir?'l':'r', Tasm[size], + usereg?'d':'#', count, num); + return 0; +} + +static int DisaAsrEa(int op) +{ + // Asr/l/Ror/l etc EA - 11100ttd 11eeeeee + int type=0,dir=0,size=1; + char eat[64]=""; + + type=(op>>9)&3; + dir =(op>>8)&1; + DisaGetEa(eat,op&0x3f,size); + + sprintf(DisaText,"%s%c.w %s", AsrName[type], dir?'l':'r', eat); + return 0; +} + +// ================================================================= + +static int TryOp(int op) +{ + if ((op&0xf100)==0x0000) DisaArithImm(op); // Ori/And/Sub/Add/Eor/Cmp Immediate + if ((op&0xf5bf)==0x003c) DisaArithSr(op); // Ori/Andi/Eori $nnnn,sr + if ((op&0xf100)==0x0100) DisaBtstReg(op); + if ((op&0xf138)==0x0108) DisaMovep(op); + if ((op&0xff00)==0x0800) DisaBtstImm(op); // Btst/Bchg/Bclr/Bset + if ((op&0xc000)==0x0000) DisaMove(op); + if ((op&0xf900)==0x4000) DisaNeg(op); // Negx/Clr/Neg/Not + if ((op&0xf1c0)==0x41c0) DisaLea(op); + if ((op&0xf9c0)==0x40c0) DisaMoveSr(op); + if ((op&0xfff8)==0x4840) DisaSwap(op); + if ((op&0xffc0)==0x4840) DisaPea(op); + if ((op&0xffb8)==0x4880) DisaExt(op); + if ((op&0xfb80)==0x4880) DisaMovem(op); + if ((op&0xff00)==0x4a00) DisaTst(op); + if ((op&0xfff0)==0x4e40) DisaTrap(op); + if ((op&0xfff8)==0x4e50) DisaLink(op); + if ((op&0xfff8)==0x4e58) DisaUnlk(op); + if ((op&0xfff0)==0x4e60) DisaMoveUsp(op); + if ((op&0xfff8)==0x4e70) Disa4E70(op); + if ((op&0xff80)==0x4e80) DisaJsr(op); + if ((op&0xf000)==0x5000) DisaAddq(op); + if ((op&0xf0c0)==0x50c0) DisaSet(op); + if ((op&0xf0f8)==0x50c8) DisaDbra(op); + if ((op&0xf000)==0x6000) DisaBranch(op); + if ((op&0xa000)==0x8000) DisaArithReg(op); // Or/Sub/And/Add + if ((op&0xb1f0)==0x8100) DisaAbcd(op); + if ((op&0xb130)==0x9100) DisaAddx(op); + if ((op&0xb0c0)==0x80c0) DisaMul(op); + if ((op&0xf100)==0x7000) DisaMoveq(op); + if ((op&0x90c0)==0x90c0) DisaAritha(op); + if ((op&0xf000)==0xb000) DisaCmpEor(op); + if ((op&0xf130)==0xc100) DisaExg(op); + if ((op&0xf000)==0xe000) DisaAsr(op); + if ((op&0xf8c0)==0xe0c0) DisaAsrEa(op); + + // Unknown opcoode + return 0; +} + +int DisaGet() +{ + int op=0; + if (DisaWord==NULL) return 1; + + Comment[0]=0; + DisaText[0]=0; // Assume opcode unknown + + op=DisaWord(DisaPc)&0xffff; DisaPc+=2; + TryOp(op); + strcat(DisaText,Comment); + + // Unknown opcoode + return 0; +} diff --git a/cpu/Cyclone/Disa/Disa.h b/cpu/Cyclone/Disa/Disa.h new file mode 100644 index 00000000..9d45611f --- /dev/null +++ b/cpu/Cyclone/Disa/Disa.h @@ -0,0 +1,24 @@ + +// Dave's Disa 68000 Disassembler + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(ARM) || defined(GP32) || !defined (__WINS__) +#define CPU_CALL +#else +#define CPU_CALL __fastcall +#endif + +extern unsigned int DisaPc; +extern char *DisaText; // Text buffer to write in + +extern unsigned short (CPU_CALL *DisaWord)(unsigned int a); +int DisaGetEa(char *t,int ea,int size); + +int DisaGet(); + +#ifdef __cplusplus +} // End of extern "C" +#endif diff --git a/cpu/Cyclone/Ea.cpp b/cpu/Cyclone/Ea.cpp new file mode 100644 index 00000000..32a8cf78 --- /dev/null +++ b/cpu/Cyclone/Ea.cpp @@ -0,0 +1,414 @@ + +#include "app.h" + +// some ops use non-standard cycle counts for EAs, so are listed here. +// all constants borrowed from the MUSASHI core by Karl Stenerud. + +/* Extra cycles for JMP instruction (000, 010) */ +int g_jmp_cycle_table[8] = +{ + 4, /* EA_MODE_AI */ + 6, /* EA_MODE_DI */ + 10, /* EA_MODE_IX */ + 6, /* EA_MODE_AW */ + 8, /* EA_MODE_AL */ + 6, /* EA_MODE_PCDI */ + 10, /* EA_MODE_PCIX */ + 0, /* EA_MODE_I */ +}; + +/* Extra cycles for JSR instruction (000, 010) */ +int g_jsr_cycle_table[8] = +{ + 4, /* EA_MODE_AI */ + 6, /* EA_MODE_DI */ + 10, /* EA_MODE_IX */ + 6, /* EA_MODE_AW */ + 8, /* EA_MODE_AL */ + 6, /* EA_MODE_PCDI */ + 10, /* EA_MODE_PCIX */ + 0, /* EA_MODE_I */ +}; + +/* Extra cycles for LEA instruction (000, 010) */ +int g_lea_cycle_table[8] = +{ + 4, /* EA_MODE_AI */ + 8, /* EA_MODE_DI */ + 12, /* EA_MODE_IX */ + 8, /* EA_MODE_AW */ + 12, /* EA_MODE_AL */ + 8, /* EA_MODE_PCDI */ + 12, /* EA_MODE_PCIX */ + 0, /* EA_MODE_I */ +}; + +/* Extra cycles for PEA instruction (000, 010) */ +int g_pea_cycle_table[8] = +{ + 6, /* EA_MODE_AI */ + 10, /* EA_MODE_DI */ + 14, /* EA_MODE_IX */ + 10, /* EA_MODE_AW */ + 14, /* EA_MODE_AL */ + 10, /* EA_MODE_PCDI */ + 14, /* EA_MODE_PCIX */ + 0, /* EA_MODE_I */ +}; + +/* Extra cycles for MOVEM instruction (000, 010) */ +int g_movem_cycle_table[8] = +{ + 0, /* EA_MODE_AI */ + 4, /* EA_MODE_DI */ + 6, /* EA_MODE_IX */ + 4, /* EA_MODE_AW */ + 8, /* EA_MODE_AL */ + 0, /* EA_MODE_PCDI */ + 0, /* EA_MODE_PCIX */ + 0, /* EA_MODE_I */ +}; + +// add nonstandard EA +int Ea_add_ns(int *tab, int ea) +{ + if(ea<0x10) return 0; + if((ea&0x38)==0x10) return tab[0]; // (An) (ai) + if(ea<0x28) return 0; + if(ea<0x30) return tab[1]; // ($nn,An) (di) + if(ea<0x38) return tab[2]; // ($nn,An,Rn) (ix) + if(ea==0x38) return tab[3]; // (aw) + if(ea==0x39) return tab[4]; // (al) + if(ea==0x3a) return tab[5]; // ($nn,PC) (pcdi) + if(ea==0x3b) return tab[6]; // ($nn,pc,Rn) (pcix) + if(ea==0x3c) return tab[7]; // #$nnnn (i) + return 0; +} + + +// --------------------------------------------------------------------------- +// Gets the offset of a register for an ea, and puts it in 'r' +// Shifted left by 'shift' +// Doesn't trash anything +static int EaCalcReg(int r,int ea,int mask,int forceor,int shift,int noshift=0) +{ + int i=0,low=0,needor=0; + int lsl=0; + + for (i=mask|0x8000; (i&1)==0; i>>=1) low++; // Find out how high up the EA mask is + mask&=0xf<=8) needor=1; // Need to OR to access A0-7 + + if ((mask>>low)&8) if (ea&8) needor=0; // Ah - no we don't actually need to or, since the bit is high in r8 + + if (forceor) needor=1; // Special case for 0x30-0x38 EAs ;) + + ot(" and r%d,r8,#0x%.4x\n",r,mask); + if (needor) ot(" orr r%d,r%d,#0x%x ;@ A0-7\n",r,r,8<0) ot("lsl #%d\n", lsl); + else ot("lsr #%d\n",-lsl); + } + + return 0; +} + +// EaCalc - ARM Register 'a' = Effective Address +// Trashes r0,r2 and r3 +// size values 0, 1, 2 ~ byte, word, long +int EaCalc(int a,int mask,int ea,int size,int top) +{ + char text[32]=""; + int func=0; + + DisaPc=2; DisaGetEa(text,ea,size); // Get text version of the effective address + func=0x68+(size<<2); // Get correct read handler + + if (ea<0x10) + { + int noshift=0; + if (size>=2||(size==0&&top)) noshift=1; // Saves one opcode + + ot(";@ EaCalc : Get register index into r%d:\n",a); + + EaCalcReg(a,ea,mask,0,2,noshift); + return 0; + } + + ot(";@ EaCalc : Get '%s' into r%d:\n",text,a); + // (An), (An)+, -(An) + if (ea<0x28) + { + int step=1<>=1) low++; // Find out how high up the EA mask is + lsl=2-low; // Having a lsl #x here saves one opcode + if (lsl>=0) ot(" ldr r%d,[r7,r2,lsl #%i]\n",a,lsl); + else if (lsl<0) ot(" ldr r%d,[r7,r2,lsr #%i]\n",a,-lsl); + + if ((ea&0x38)==0x18) // (An)+ + { + ot(" add r3,r%d,#%d ;@ Post-increment An\n",a,step); + strr=3; + } + + if ((ea&0x38)==0x20) // -(An) + ot(" sub r%d,r%d,#%d ;@ Pre-decrement An\n",a,a,step); + + if ((ea&0x38)==0x18||(ea&0x38)==0x20) + { + if (lsl>=0) ot(" str r%d,[r7,r2,lsl #%i]\n",strr,lsl); + else if (lsl<0) ot(" str r%d,[r7,r2,lsr #%i]\n",strr,-lsl); + } + + if ((ea&0x38)==0x20) Cycles+=size<2 ? 6:10; // -(An) Extra cycles + else Cycles+=size<2 ? 4:8; // (An),(An)+ Extra cycles + return 0; + } + + if (ea<0x30) // ($nn,An) (di) + { + EaCalcReg(2,8,mask,0,0); + ot(" ldrsh r0,[r4],#2 ;@ Fetch offset\n"); + ot(" ldr r2,[r7,r2,lsl #2]\n"); + ot(" add r%d,r0,r2 ;@ Add on offset\n",a); + Cycles+=size<2 ? 8:12; // Extra cycles + return 0; + } + + if (ea<0x38) // ($nn,An,Rn) (ix) + { + ot(";@ Get extension word into r3:\n"); + ot(" ldrh r3,[r4],#2 ;@ ($Disp,PC,Rn)\n"); + ot(" mov r2,r3,lsr #10\n"); + ot(" tst r3,#0x0800 ;@ Is Rn Word or Long\n"); + ot(" and r2,r2,#0x3c ;@ r2=Index of Rn\n"); + ot(" ldreqsh r2,[r7,r2] ;@ r2=Rn.w\n"); + ot(" ldrne r2,[r7,r2] ;@ r2=Rn.l\n"); + ot(" mov r0,r3,asl #24 ;@ r0=Get 8-bit signed Disp\n"); + ot(" add r3,r2,r0,asr #24 ;@ r3=Disp+Rn\n"); + + EaCalcReg(2,8,mask,1,0); + ot(" ldr r2,[r7,r2,lsl #2]\n"); + ot(" add r%d,r2,r3 ;@ r%d=Disp+An+Rn\n",a,a); + Cycles+=size<2 ? 10:14; // Extra cycles + return 0; + } + + if (ea==0x38) // (aw) + { + ot(" ldrsh r%d,[r4],#2 ;@ Fetch Absolute Short address\n",a); + Cycles+=size<2 ? 8:12; // Extra cycles + return 0; + } + + if (ea==0x39) // (al) + { + ot(" ldrh r2,[r4],#2 ;@ Fetch Absolute Long address\n"); + ot(" ldrh r0,[r4],#2\n"); + ot(" orr r%d,r0,r2,lsl #16\n",a); + Cycles+=size<2 ? 12:16; // Extra cycles + return 0; + } + + if (ea==0x3a) // ($nn,PC) (pcdi) + { + ot(" ldr r0,[r7,#0x60] ;@ Get Memory base\n"); + ot(" sub r0,r4,r0 ;@ Real PC\n"); + ot(" ldrsh r2,[r4],#2 ;@ Fetch extension\n"); + ot(" mov r0,r0,lsl #8\n"); + ot(" add r%d,r2,r0,asr #8 ;@ ($nn,PC)\n",a); + Cycles+=size<2 ? 8:12; // Extra cycles + return 0; + } + + if (ea==0x3b) // ($nn,pc,Rn) (pcix) + { + ot(" ldr r0,[r7,#0x60] ;@ Get Memory base\n"); + ot(" ldrh r3,[r4] ;@ Get extension word\n"); + ot(" sub r0,r4,r0 ;@ r0=PC\n"); + ot(" add r4,r4,#2\n"); + ot(" mov r0,r0,asl #8 ;@ use only 24bits of PC\n"); + ot(" mov r2,r3,lsr #10\n"); + ot(" tst r3,#0x0800 ;@ Is Rn Word or Long\n"); + ot(" and r2,r2,#0x3c ;@ r2=Index of Rn\n"); + ot(" ldreqsh r2,[r7,r2] ;@ r2=Rn.w\n"); + ot(" ldrne r2,[r7,r2] ;@ r2=Rn.l\n"); + ot(" mov r3,r3,asl #24 ;@ r3=Get 8-bit signed Disp\n"); + ot(" add r2,r2,r3,asr #24 ;@ r2=Disp+Rn\n"); + ot(" add r%d,r2,r0,asr #8 ;@ r%d=Disp+PC+Rn\n",a,a); + Cycles+=size<2 ? 10:14; // Extra cycles + return 0; + } + + if (ea==0x3c) // #$nnnn (i) + { + if (size<2) + { + ot(" ldr%s r%d,[r4],#2 ;@ Fetch immediate value\n",Sarm[size&3],a); + Cycles+=4; // Extra cycles + return 0; + } + + ot(" ldrh r2,[r4],#2 ;@ Fetch immediate value\n"); + ot(" ldrh r0,[r4],#2\n"); + ot(" orr r%d,r0,r2,lsl #16\n",a); + Cycles+=8; // Extra cycles + return 0; + } + + return 1; +} + +// --------------------------------------------------------------------------- +// Read effective address in (ARM Register 'a') to ARM register 'v' +// 'a' and 'v' can be anything but 0 is generally best (for both) +// If (ea<0x10) nothing is trashed, else r0-r3 is trashed +// If 'top' is given, the ARM register v shifted to the top, e.g. 0xc000 -> 0xc0000000 +// Otherwise the ARM register v is sign extended, e.g. 0xc000 -> 0xffffc000 + +int EaRead(int a,int v,int ea,int size,int mask,int top) +{ + char text[32]=""; + int shift=0; + + shift=32-(8<=2||(size==0&&top)) { + if(mask) + for (i=mask|0x8000; (i&1)==0; i>>=1) low++; // Find out how high up the EA mask is + lsl=2-low; // Having a lsl #2 here saves one opcode + } + + ot(";@ EaRead : Read register[r%d] into r%d:\n",a,v); + + if (lsl>0) ot(" ldr%s r%d,[r7,r%d,lsl #%i]\n",Narm[size&3],v,a,lsl); + else if (lsl<0) ot(" ldr%s r%d,[r7,r%d,lsr #%i]\n",Narm[size&3],v,a,-lsl); + else ot(" ldr%s r%d,[r7,r%d]\n",Sarm[size&3],v,a); + + if (top && shift) ot(" mov r%d,r%d,asl #%d\n",v,v,shift); + + ot("\n"); return 0; + } + + ot(";@ EaRead : Read '%s' (address in r%d) into r%d:\n",text,a,v); + + if (ea==0x3c) + { + int asl=0; + + if (top) asl=shift; + + if (v!=a || asl) ot(" mov r%d,r%d,asl #%d\n",v,a,asl); + ot("\n"); return 0; + } + + if (a!=0) ot(" mov r0,r%d\n",a); + + if (ea>=0x3a && ea<=0x3b) MemHandler(2,size); // Fetch + else MemHandler(0,size); // Read + + if (v!=0 || shift) { + if (shift) ot(" mov r%d,r0,asl #%d\n",v,shift); + else ot(" mov r%d,r0\n",v); + } + if (top==0 && shift) ot(" mov r%d,r%d,asr #%d\n",v,v,shift); + + ot("\n"); return 0; +} + +// Return 1 if we can read this ea +int EaCanRead(int ea,int size) +{ + if (size<0) + { + // LEA: + // These don't make sense?: + if (ea< 0x10) return 0; // Register + if (ea==0x3c) return 0; // Immediate + if (ea>=0x18 && ea<0x28) return 0; // Pre/Post inc/dec An + } + + if (ea<=0x3c) return 1; + return 0; +} + +// --------------------------------------------------------------------------- +// Write effective address (ARM Register 'a') with ARM register 'v' +// Trashes r0-r3,r12,lr; 'a' can be 0 or 2+, 'v' can be 1 or higher +// If a==0 and v==1 it's faster though. +int EaWrite(int a,int v,int ea,int size,int mask,int top) +{ + char text[32]=""; + int shift=0; + + if(a == 1) { printf("Error! EaWrite a==1 !\n"); return 1; } + + if (top) shift=32-(8<=2||(size==0&&top)) { + if(mask) + for (i=mask|0x8000; (i&1)==0; i>>=1) low++; // Find out how high up the EA mask is + lsl=2-low; // Having a lsl #x here saves one opcode + } + + ot(";@ EaWrite: r%d into register[r%d]:\n",v,a); + if (shift) ot(" mov r%d,r%d,asr #%d\n",v,v,shift); + + if (lsl>0) ot(" str%s r%d,[r7,r%d,lsl #%i]\n",Narm[size&3],v,a,lsl); + else if (lsl<0) ot(" str%s r%d,[r7,r%d,lsr #%i]\n",Narm[size&3],v,a,-lsl); + else ot(" str%s r%d,[r7,r%d]\n",Narm[size&3],v,a); + + ot("\n"); return 0; + } + + ot(";@ EaWrite: Write r%d into '%s' (address in r%d):\n",v,text,a); + + if (ea==0x3c) { ot("Error! Write EA=0x%x\n\n",ea); return 1; } + + if (a!=0 && v!=0) ot(" mov r0,r%d\n",a); + if (v!=1 || shift) ot(" mov r1,r%d,asr #%d\n",v,shift); + if (a!=0 && v==0) ot(" mov r0,r%d\n",a); + + MemHandler(1,size); // Call write handler + + ot("\n"); return 0; +} + +// Return 1 if we can write this ea +int EaCanWrite(int ea) +{ + if (ea<=0x39) return 1; // 3b? + return 0; +} +// --------------------------------------------------------------------------- + +// Return 1 if EA is An reg +int EaAn(int ea) +{ + if((ea&0x38)==8) return 1; + return 0; +} + diff --git a/cpu/Cyclone/Main.cpp b/cpu/Cyclone/Main.cpp new file mode 100644 index 00000000..2f92c5cf --- /dev/null +++ b/cpu/Cyclone/Main.cpp @@ -0,0 +1,648 @@ + +#include "app.h" + +static FILE *AsmFile=NULL; + +static int CycloneVer=0x0086; // Version number of library +int *CyJump=NULL; // Jump table +int ms=USE_MS_SYNTAX; // If non-zero, output in Microsoft ARMASM format +char *Narm[4]={ "b", "h","",""}; // Normal ARM Extensions for operand sizes 0,1,2 +char *Sarm[4]={"sb","sh","",""}; // Sign-extend ARM Extensions for operand sizes 0,1,2 +int Cycles; // Current cycles for opcode + + +void ot(const char *format, ...) +{ + va_list valist=NULL; + int i, len; + + // notaz: stop me from leaving newlines in the middle of format string + // and generating bad code + for(i=0, len=strlen(format); i < len && format[i] != '\n'; i++); + if(i < len-1 && format[len-1] != '\n') printf("\nWARNING: possible improper newline placement:\n%s\n", format); + + va_start(valist,format); + if (AsmFile) vfprintf(AsmFile,format,valist); + va_end(valist); +} + +void ltorg() +{ + if (ms) ot(" LTORG\n"); + else ot(" .ltorg\n"); +} + +// trashes all temp regs +static void PrintException(int ints) +{ + if(!ints) { + ot(" ;@ Cause an Exception - Vector address in r0\n"); + ot(" mov r11,r0\n"); + } + + ot(";@ swap OSP <-> A7?\n"); + ot(" ldr r0,[r7,#0x44] ;@ Get SR high\n"); + ot(" tst r0,#0x20\n"); + ot(" bne no_sp_swap%i\n",ints); + ot(";@ swap OSP and A7:\n"); + ot(" ldr r0,[r7,#0x3C] ;@ Get A7\n"); + ot(" ldr r1,[r7,#0x48] ;@ Get OSP\n"); + ot(" str r0,[r7,#0x48]\n"); + ot(" str r1,[r7,#0x3C]\n"); + ot("no_sp_swap%i%s\n",ints,ms?"":":"); + + ot(" ldr r10,[r7,#0x60] ;@ Get Memory base\n"); + ot(" mov r1,r4,lsl #8\n"); + ot(" sub r1,r1,r10,lsl #8 ;@ r1 = Old PC\n"); + ot(" mov r1,r1,asr #8 ;@ push sign extended\n"); + OpPush32(); + OpPushSr(1); + ot(" mov r0,r11\n"); + ot(";@ Read IRQ Vector:\n"); + MemHandler(0,2); + if(ints) { + ot(" tst r0,r0 ;@ uninitialized int vector?\n"); + ot(" moveq r0,#0x3c\n"); + ot(" moveq lr,pc\n"); + ot(" ldreq pc,[r7,#0x70] ;@ Call read32(r0) handler\n"); + } +#if USE_CHECKPC_CALLBACK + ot(" add r0,r0,r10 ;@ r0 = Memory Base + New PC\n"); + ot(" mov lr,pc\n"); + ot(" ldr pc,[r7,#0x64] ;@ Call checkpc()\n"); + ot(" mov r4,r0\n"); +#endif + ot("\n"); + + if(!ints) { + ot(" ldr r0,[r7,#0x44] ;@ Get SR high\n"); + ot(" bic r0,r0,#0xd8 ;@ clear trace and unused flags\n"); + ot(" orr r0,r0,#0x20 ;@ set supervisor mode\n"); + ot(" strb r0,[r7,#0x44]\n"); + } +} + +// Trashes r0,r1 +void CheckInterrupt(int op) +{ + ot(";@ CheckInterrupt:\n"); + ot(" ldr r0,[r7,#0x44]\n"); // same as ldrb r0,[r7,#0x47] + ot(" movs r0,r0,lsr #24 ;@ Get IRQ level (loading word is faster)\n"); + ot(" beq NoInts%x\n",op); + ot(" cmp r0,#6 ;@ irq>6 ?\n"); + ot(" ldrleb r1,[r7,#0x44] ;@ Get SR high: T_S__III\n"); + ot(" andle r1,r1,#7 ;@ Get interrupt mask\n"); + ot(" cmple r0,r1 ;@ irq<=6: Is irq<=mask ?\n"); + ot(" blgt DoInterrupt\n"); + ot("NoInts%x%s\n", op,ms?"":":"); + ot("\n"); +} + +static void PrintFramework() +{ + ot(";@ --------------------------- Framework --------------------------\n"); + if (ms) ot("CycloneRun\n"); + else ot("CycloneRun:\n"); + + ot(" stmdb sp!,{r4-r11,lr}\n"); + + ot(" mov r7,r0 ;@ r7 = Pointer to Cpu Context\n"); + ot(" ;@ r0-3 = Temporary registers\n"); + ot(" ldrb r9,[r7,#0x46] ;@ r9 = Flags (NZCV)\n"); + ot(" ldr r6,=JumpTab ;@ r6 = Opcode Jump table\n"); + ot(" ldr r5,[r7,#0x5c] ;@ r5 = Cycles\n"); + ot(" ldr r4,[r7,#0x40] ;@ r4 = Current PC + Memory Base\n"); + ot(" ;@ r8 = Current Opcode\n"); + ot(" ldr r0,[r7,#0x44]\n"); + ot(" mov r9,r9,lsl #28 ;@ r9 = Flags 0xf0000000, cpsr format\n"); + ot(" ;@ r10 = Source value / Memory Base\n"); + ot("\n"); + ot(";@ CheckInterrupt:\n"); + ot(" movs r0,r0,lsr #24 ;@ Get IRQ level\n"); // same as ldrb r0,[r7,#0x47] + ot(" beq NoInts0\n"); + ot(" cmp r0,#6 ;@ irq>6 ?\n"); + ot(" ldrleb r1,[r7,#0x44] ;@ Get SR high: T_S__III\n"); + ot(" andle r1,r1,#7 ;@ Get interrupt mask\n"); + ot(" cmple r0,r1 ;@ irq<=6: Is irq<=mask ?\n"); + ot(" blgt DoInterrupt\n"); + ot(";@ Check if interrupt used up all the cycles:\n"); + ot(" subs r5,r5,#0\n"); + ot(" blt CycloneEndNoBack\n"); + ot("NoInts0%s\n", ms?"":":"); + ot("\n"); + ot(";@ Check if our processor is in stopped state and jump to opcode handler if not\n"); + ot(" ldr r0,[r7,#0x58]\n"); + ot(" ldrh r8,[r4],#2 ;@ Fetch first opcode\n"); + ot(" tst r0,r0 ;@ stopped?\n"); + ot(" bne CycloneStopped\n"); + ot(" ldr pc,[r6,r8,asl #2] ;@ Jump to opcode handler\n"); + ot("\n"); + ot("\n"); + + ot(";@ We come back here after execution\n"); + ot("CycloneEnd%s\n", ms?"":":"); + ot(" sub r4,r4,#2\n"); + ot("CycloneEndNoBack%s\n", ms?"":":"); + ot(" mov r9,r9,lsr #28\n"); + ot(" str r4,[r7,#0x40] ;@ Save Current PC + Memory Base\n"); + ot(" str r5,[r7,#0x5c] ;@ Save Cycles\n"); + ot(" strb r9,[r7,#0x46] ;@ Save Flags (NZCV)\n"); + ot(" ldmia sp!,{r4-r11,pc}\n"); + ot("\n"); + ot("CycloneStopped%s\n", ms?"":":"); + ot(" mov r5,#0\n"); + ot(" str r5,[r7,#0x5C] ;@ eat all cycles\n"); + ot(" ldmia sp!,{r4-r11,pc} ;@ we are stopped, do nothing!\n"); + ot("\n"); + + ltorg(); + +#if COMPRESS_JUMPTABLE + ot(";@ uncompress jump table\n"); + if (ms) ot("CycloneInit\n"); + else ot("CycloneInit:\n"); + ot(" ldr r12,=JumpTab\n"); + ot(" add r0,r12,#0xe000*4 ;@ ctrl code pointer\n"); + ot(" ldr r1,[r0,#-4]\n"); + ot(" tst r1,r1\n"); + ot(" movne pc,lr ;@ already uncompressed\n"); + ot(" add r3,r12,#0xa000*4 ;@ handler table pointer, r12=dest\n"); + ot("unc_loop%s\n", ms?"":":"); + ot(" ldrh r1,[r0],#2\n"); + ot(" and r2,r1,#0xf\n"); + ot(" bic r1,r1,#0xf\n"); + ot(" ldr r1,[r3,r1,lsr #2] ;@ r1=handler\n"); + ot(" cmp r2,#0xf\n"); + ot(" addeq r2,r2,#1 ;@ 0xf is really 0x10\n"); + ot(" tst r2,r2\n"); + ot(" ldreqh r2,[r0],#2 ;@ counter is in next word\n"); + ot(" tst r2,r2\n"); + ot(" beq unc_finish ;@ done decompressing\n"); + ot(" tst r1,r1\n"); + ot(" addeq r12,r12,r2,lsl #2 ;@ 0 handler means we should skip those bytes\n"); + ot(" beq unc_loop\n"); + ot("unc_loop_in%s\n", ms?"":":"); + ot(" subs r2,r2,#1\n"); + ot(" str r1,[r12],#4\n"); + ot(" bgt unc_loop_in\n"); + ot(" b unc_loop\n"); + ot("unc_finish%s\n", ms?"":":"); + ot(" ldr r12,=JumpTab\n"); + ot(" ;@ set a-line and f-line handlers\n"); + ot(" add r0,r12,#0xa000*4\n"); + ot(" ldr r1,[r0,#4] ;@ a-line handler\n"); + ot(" ldr r3,[r0,#8] ;@ f-line handler\n"); + ot(" mov r2,#0x1000\n"); + ot("unc_fill3%s\n", ms?"":":"); + ot(" subs r2,r2,#1\n"); + ot(" str r1,[r0],#4\n"); + ot(" bgt unc_fill3\n"); + ot(" add r0,r12,#0xf000*4\n"); + ot(" mov r2,#0x1000\n"); + ot("unc_fill4%s\n", ms?"":":"); + ot(" subs r2,r2,#1\n"); + ot(" str r3,[r0],#4\n"); + ot(" bgt unc_fill4\n"); + ot(" bx lr\n"); + ltorg(); + ot("\n"); +#else + ot(";@ do nothing\n"); + if (ms) ot("CycloneInit\n"); + else ot("CycloneInit:\n"); + ot(" bx lr\n"); + ot("\n"); +#endif + if (ms) ot("CycloneSetSr\n"); + else ot("CycloneSetSr:\n"); + ot(" mov r2,r1,lsr #8\n"); + ot(" ldrb r3,[r0,#0x44] ;@ get SR high\n"); + ot(" eor r3,r3,r2\n"); + ot(" tst r3,#0x20\n"); + ot(" and r2,r2,#0xa7 ;@ only nonzero bits\n"); + ot(" strb r2,[r0,#0x44] ;@ set SR high\n"); + ot(" bne setsr_noswap\n"); + ot(" ldr r2,[r0,#0x3C] ;@ Get A7\n"); + ot(" ldr r3,[r0,#0x48] ;@ Get OSP\n"); + ot(" str r3,[r0,#0x3C]\n"); + ot(" str r2,[r0,#0x48]\n"); + ot("setsr_noswap%s\n",ms?"":":"); + ot(" mov r2,r1,lsr #3\n"); + ot(" strb r2,[r0,#0x45] ;@ the X flag\n"); + ot(" bic r2,r1,#0xf3\n"); + ot(" tst r1,#1\n"); + ot(" orrne r2,r2,#2\n"); + ot(" tst r1,#2\n"); + ot(" orrne r2,r2,#1\n"); + ot(" strb r2,[r0,#0x46] ;@ flags\n"); + ot(" bx lr\n"); + ot("\n"); + + if (ms) ot("CycloneGetSr\n"); + else ot("CycloneGetSr:\n"); + ot(" ldrb r1,[r0,#0x46] ;@ flags\n"); + ot(" bic r2,r1,#0xf3\n"); + ot(" tst r1,#1\n"); + ot(" orrne r2,r2,#2\n"); + ot(" tst r1,#2\n"); + ot(" orrne r2,r2,#1\n"); + ot(" ldrb r1,[r0,#0x45] ;@ the X flag\n"); + ot(" tst r1,#2\n"); + ot(" orrne r2,r2,#0x10\n"); + ot(" ldrb r1,[r0,#0x44] ;@ the SR high\n"); + ot(" orr r0,r2,r1,lsl #8\n"); + ot(" bx lr\n"); + ot("\n"); + + ot(";@ DoInterrupt - r0=IRQ number\n"); + ot("DoInterrupt%s\n", ms?"":":"); + ot(" stmdb sp!,{lr} ;@ Push ARM return address\n"); + + ot(";@ Get IRQ Vector address:\n"); + ot(" mov r0,r0,asl #2\n"); + ot(" add r11,r0,#0x60\n"); + PrintException(1); + + ot(" ldrb r0,[r7,#0x47] ;@ IRQ\n"); + ot(" mov r2,#0\n"); + ot(" orr r1,r0,#0x20 ;@ Supervisor mode + IRQ number\n"); + ot(" strb r1,[r7,#0x44] ;@ Put SR high\n"); + + ot(";@ Clear stopped states:\n"); + ot(" str r2,[r7,#0x58]\n"); + ot(" sub r5,r5,#%d ;@ Subtract cycles\n",44); + ot("\n"); +#if USE_INT_ACK_CALLBACK +#if INT_ACK_NEEDS_STUFF + ot(" str r4,[r7,#0x40] ;@ Save PC\n"); + ot(" mov r1,r9,lsr #28\n"); + ot(" strb r1,[r7,#0x46] ;@ Save Flags (NZCV)\n"); + ot(" str r5,[r7,#0x5c] ;@ Save Cycles\n"); +#endif + ot(" ldr r11,[r7,#0x8c] ;@ IrqCallback\n"); + ot(" tst r11,r11\n"); + ot(" movne lr,pc\n"); + ot(" movne pc,r11 ;@ call IrqCallback if it is defined\n"); +#if INT_ACK_CHANGES_STUFF + ot(" ldr r5,[r7,#0x5c] ;@ Load Cycles\n"); + ot(" ldrb r9,[r7,#0x46] ;@ r9 = Load Flags (NZCV)\n"); + ot(" mov r9,r9,lsl #28\n"); + ot(" ldr r4,[r7,#0x40] ;@ Load PC\n"); +#endif +#else // not USE_INT_ACK_CALLBACK + ot(";@ Clear irq:\n"); + ot(" strb r1,[r7,#0x47]\n"); +#endif + ot(" ldmia sp!,{pc} ;@ Return\n"); + ot("\n"); + + ot("Exception%s\n", ms?"":":"); + ot("\n"); + ot(" stmdb sp!,{lr} ;@ Preserve ARM return address\n"); + PrintException(0); + ot(" ldmia sp!,{pc} ;@ Return\n"); + ot("\n"); +} + +// --------------------------------------------------------------------------- +// Call Read(r0), Write(r0,r1) or Fetch(r0) +// Trashes r0-r3,r12,lr +int MemHandler(int type,int size) +{ + int func=0; + func=0x68+type*0xc+(size<<2); // Find correct offset + +#if MEMHANDLERS_NEED_PC + ot(" str r4,[r7,#0x40] ;@ Save PC\n"); +#endif +#if MEMHANDLERS_NEED_FLAGS + ot(" mov r3,r9,lsr #28\n"); + ot(" strb r3,[r7,#0x46] ;@ Save Flags (NZCV)\n"); +#endif +#if MEMHANDLERS_NEED_CYCLES + ot(" str r5,[r7,#0x5c] ;@ Save Cycles\n"); +#endif + + ot(" mov lr,pc\n"); + ot(" ldr pc,[r7,#0x%x] ;@ Call ",func); + + // Document what we are calling: + if (type==0) ot("read"); + if (type==1) ot("write"); + if (type==2) ot("fetch"); + + if (type==1) ot("%d(r0,r1)",8<>12); fflush(stdout); } // Update progress + + OpAny(op); + } + + ot("\n"); + + printf("]\n"); +} + +// helper +static void ott(const char *str, int par, const char *nl, int nlp, int counter, int size) +{ + switch(size) { + case 0: if((counter&7)==0) ot(ms?" dcb ":" .byte "); break; + case 1: if((counter&7)==0) ot(ms?" dcw ":" .hword "); break; + case 2: if((counter&7)==0) ot(ms?" dcd ":" .long "); break; + } + ot(str, par); + if((counter&7)==7) ot(nl,nlp); else ot(","); +} + +static void PrintJumpTable() +{ + int i=0,op=0,len=0; + + ot(";@ -------------------------- Jump Table --------------------------\n"); + +#if COMPRESS_JUMPTABLE + int handlers=0,reps=0,*indexes,ip,u,out; + // use some weird compression on the jump table + indexes=(int *)malloc(0x10000*4); + if(!indexes) { printf("ERROR: out of memory\n"); exit(1); } + len=0x10000; + + // space for decompressed table + ot(ms?" area |.data|, data\n":" .data\n .align 4\n\n"); + + ot("JumpTab%s\n", ms?"":":"); + if(ms) { + for(i = 0; i < 0xa000/8; i++) + ot(" dcd 0,0,0,0,0,0,0,0\n"); + } else + ot(" .rept 0x%x\n .long 0,0,0,0,0,0,0,0\n .endr\n", 0xa000/8); + + // hanlers live in "a-line" part of the table + // first output nop,a-line,f-line handlers + ot(ms?" dcd Op____,Op__al,Op__fl,":" .long Op____,Op__al,Op__fl,"); + handlers=3; + + for(i=0;i=0; u--) if(op == CyJump[u]) break; // already done with this op? + if(u==-1 && op >= 0) { + ott("Op%.4x",op," ;@ %.4x\n",i,handlers,2); + indexes[op] = handlers; + handlers++; + } + } + if(handlers&7) { + fseek(AsmFile, -1, SEEK_CUR); // remove last comma + for(i = 8-(handlers&7); i > 0; i--) + ot(",000000"); + ot("\n"); + } + if(ms) { + for(i = (0x4000-handlers)/8; i > 0; i--) + ot(" dcd 0,0,0,0,0,0,0,0\n"); + } else { + ot(ms?"":" .rept 0x%x\n .long 0,0,0,0,0,0,0,0\n .endr\n", (0x4000-handlers)/8); + } + printf("total distinct hanlers: %i\n",handlers); + // output data + for(i=0,ip=0; i < 0xf000; i++, ip++) { + op=CyJump[i]; + if(op == -2) { + // it must skip a-line area, because we keep our data there + ott("0x%.4x", handlers<<4, "\n",0,ip++,1); + ott("0x%.4x", 0x1000, "\n",0,ip,1); + i+=0xfff; + continue; + } + for(reps=1; i < 0xf000; i++, reps++) if(op != CyJump[i+1]) break; + if(op>=0) out=indexes[op]<<4; else out=0; // unrecognised + if(reps <= 0xe || reps==0x10) { + if(reps!=0x10) out|=reps; else out|=0xf; // 0xf means 0x10 (0xf appeared to be unused anyway) + ott("0x%.4x", out, "\n",0,ip,1); + } else { + ott("0x%.4x", out, "\n",0,ip++,1); + ott("0x%.4x", reps,"\n",0,ip,1); + } + } + if(ip&1) ott("0x%.4x", 0, "\n",0,ip++,1); + if(ip&7) fseek(AsmFile, -1, SEEK_CUR); // remove last comma + ot("\n"); + if(ip&7) { + for(i = 8-(ip&7); i > 0; i--) + ot(",0x0000"); + ot("\n"); + } + if(ms) { + for(i = (0x2000-ip/2)/8+1; i > 0; i--) + ot(" dcd 0,0,0,0,0,0,0,0\n"); + } else { + ot(" .rept 0x%x\n .long 0,0,0,0,0,0,0,0\n .endr\n", (0x2000-ip/2)/8+1); + } + ot("\n"); + free(indexes); +#else + ot("JumpTab%s\n", ms?"":":"); + len=0xfffe; // Hmmm, armasm 2.50.8684 messes up with a 0x10000 long jump table + // notaz: same thing with GNU as 2.9-psion-98r2 (reloc overflow) + // this is due to COFF objects using only 2 bytes for reloc count + + for (i=0;i=0) ott("Op%.4x",op," ;@ %.4x\n",i-7,i,2); + else if(op==-2) ott("Op__al",0, " ;@ %.4x\n",i-7,i,2); + else if(op==-3) ott("Op__fl",0, " ;@ %.4x\n",i-7,i,2); + else ott("Op____",0, " ;@ %.4x\n",i-7,i,2); + } + if(i&7) fseek(AsmFile, -1, SEEK_CUR); // remove last comma + + ot("\n"); + ot(";@ notaz: we don't want to crash if we run into those 2 missing opcodes\n"); + ot(";@ so we leave this pattern to patch it later\n"); + ot("%s 0x78563412\n", ms?" dcd":" .long"); + ot("%s 0x56341290\n", ms?" dcd":" .long"); +#endif +} + +static int CycloneMake() +{ + int i; + char *name="Cyclone.s"; + + // Open the assembly file + if (ms) name="Cyclone.asm"; + AsmFile=fopen(name,"wt"); if (AsmFile==NULL) return 1; + + printf("Making %s...\n",name); + + ot("\n;@ Dave's Cyclone 68000 Emulator v%x.%.3x - Assembler Output\n\n",CycloneVer>>12,CycloneVer&0xfff); + + ot(";@ (c) Copyright 2003 Dave, All rights reserved.\n"); + ot(";@ some code (c) Copyright 2005-2006 notaz, All rights reserved.\n"); + ot(";@ Cyclone 68000 is free for non-commercial use.\n\n"); + ot(";@ For commercial use, separate licencing terms must be obtained.\n\n"); + + CyJump=(int *)malloc(0x40000); if (CyJump==NULL) return 1; + memset(CyJump,0xff,0x40000); // Init to -1 + for(i=0xa000; i<0xb000; i++) CyJump[i] = -2; // a-line emulation + for(i=0xf000; i<0x10000; i++) CyJump[i] = -3; // f-line emulation + + if (ms) + { + ot(" area |.text|, code\n"); + ot(" export CycloneInit\n"); + ot(" export CycloneRun\n"); + ot(" export CycloneSetSr\n"); + ot(" export CycloneGetSr\n"); + ot(" export CycloneVer\n"); + ot("\n"); + ot("CycloneVer dcd 0x%.4x\n",CycloneVer); + } + else + { + ot(" .global CycloneInit\n"); + ot(" .global CycloneRun\n"); + ot(" .global CycloneSetSr\n"); + ot(" .global CycloneGetSr\n"); + ot(" .global CycloneVer\n"); + ot("CycloneVer: .long 0x%.4x\n",CycloneVer); + } + ot("\n"); + + PrintFramework(); + PrintOpcodes(); + PrintJumpTable(); + + if (ms) ot(" END\n"); + + fclose(AsmFile); AsmFile=NULL; + +#if 0 + printf("Assembling...\n"); + // Assemble the file + if (ms) system("armasm Cyclone.asm"); + else system("as -o Cyclone.o Cyclone.s"); + printf("Done!\n\n"); +#endif + + free(CyJump); + return 0; +} + +int main() +{ + printf("\n Dave's Cyclone 68000 Emulator v%x.%.3x - Core Creator\n\n",CycloneVer>>12,CycloneVer&0xfff); + + // Make GAS or ARMASM version + CycloneMake(); + return 0; +} + diff --git a/cpu/Cyclone/OpAny.cpp b/cpu/Cyclone/OpAny.cpp new file mode 100644 index 00000000..946ecba8 --- /dev/null +++ b/cpu/Cyclone/OpAny.cpp @@ -0,0 +1,119 @@ + +#include "app.h" + +static unsigned char OpData[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + +static unsigned short CPU_CALL OpRead16(unsigned int a) +{ + return (unsigned short)( (OpData[a&15]<<8) | OpData[(a+1)&15] ); +} + +// For opcode 'op' use handler 'use' +void OpUse(int op,int use) +{ + char text[64]=""; + CyJump[op]=use; + + if (op!=use) return; + + // Disassemble opcode + DisaPc=0; + DisaText=text; + DisaWord=OpRead16; + + DisaGet(); + ot(";@ ---------- [%.4x] %s uses Op%.4x ----------\n",op,text,use); +} + +void OpStart(int op) +{ + Cycles=0; + OpUse(op,op); // This opcode obviously uses this handler + ot("Op%.4x%s\n", op, ms?"":":"); +} + +void OpEnd() +{ + ot(" ldrh r8,[r4],#2 ;@ Fetch next opcode\n"); + ot(" subs r5,r5,#%d ;@ Subtract cycles\n",Cycles); + ot(" ldrge pc,[r6,r8,asl #2] ;@ Jump to opcode handler\n"); + ot(" b CycloneEnd\n"); + ot("\n"); +} + +int OpBase(int op,int sepa) +{ + int ea=op&0x3f; // Get Effective Address + if (ea<0x10) return sepa?(op&~0x7):(op&~0xf); // Use 1 handler for d0-d7 and a0-a7 + if (ea>=0x18 && ea<0x28 && (ea&7)==7) return op; // Specific handler for (a7)+ and -(a7) + if (ea<0x38) return op&~7; // Use 1 handler for (a0)-(a7), etc... + return op; +} + +// Get flags, trashes r2 +int OpGetFlags(int subtract,int xbit,int specialz) +{ + if (specialz) ot(" orr r2,r9,#0xb0000000 ;@ for old Z\n"); + + ot(" mrs r9,cpsr ;@ r9=flags\n"); + + if (specialz) ot(" andeq r9,r9,r2 ;@ fix Z\n"); + + if (subtract) ot(" eor r9,r9,#0x20000000 ;@ Invert carry\n"); + + if (xbit) + { + ot(" mov r2,r9,lsr #28\n"); + ot(" strb r2,[r7,#0x45] ;@ Save X bit\n"); + } + return 0; +} + +// ----------------------------------------------------------------- + +void OpAny(int op) +{ + memset(OpData,0x33,sizeof(OpData)); + OpData[0]=(unsigned char)(op>>8); + OpData[1]=(unsigned char)op; + + if ((op&0xf100)==0x0000) OpArith(op); + if ((op&0xc000)==0x0000) OpMove(op); + if ((op&0xf5bf)==0x003c) OpArithSr(op); // Ori/Andi/Eori $nnnn,sr + if ((op&0xf100)==0x0100) OpBtstReg(op); + if ((op&0xf138)==0x0108) OpMovep(op); + if ((op&0xff00)==0x0800) OpBtstImm(op); + if ((op&0xf900)==0x4000) OpNeg(op); + if ((op&0xf140)==0x4100) OpChk(op); + if ((op&0xf1c0)==0x41c0) OpLea(op); + if ((op&0xf9c0)==0x40c0) OpMoveSr(op); + if ((op&0xffc0)==0x4800) OpNbcd(op); + if ((op&0xfff8)==0x4840) OpSwap(op); + if ((op&0xffc0)==0x4840) OpPea(op); + if ((op&0xffb8)==0x4880) OpExt(op); + if ((op&0xfb80)==0x4880) OpMovem(op); + if ((op&0xff00)==0x4a00) OpTst(op); + if ((op&0xffc0)==0x4ac0) OpTas(op); + if ((op&0xfff0)==0x4e40) OpTrap(op); + if ((op&0xfff8)==0x4e50) OpLink(op); + if ((op&0xfff8)==0x4e58) OpUnlk(op); + if ((op&0xfff0)==0x4e60) OpMoveUsp(op); + if ((op&0xfff8)==0x4e70) Op4E70(op); // Reset/Rts etc + if ((op&0xfffd)==0x4e70) OpStopReset(op); + if ((op&0xff80)==0x4e80) OpJsr(op); + if ((op&0xf000)==0x5000) OpAddq(op); + if ((op&0xf0c0)==0x50c0) OpSet(op); + if ((op&0xf0f8)==0x50c8) OpDbra(op); + if ((op&0xf000)==0x6000) OpBranch(op); + if ((op&0xf100)==0x7000) OpMoveq(op); + if ((op&0xa000)==0x8000) OpArithReg(op); // Or/Sub/And/Add + if ((op&0xb1f0)==0x8100) OpAbcd(op); + if ((op&0xb0c0)==0x80c0) OpMul(op); + if ((op&0x90c0)==0x90c0) OpAritha(op); + if ((op&0xb130)==0x9100) OpAddx(op); + if ((op&0xf000)==0xb000) OpCmpEor(op); + if ((op&0xf138)==0xb108) OpCmpm(op); + if ((op&0xf130)==0xc100) OpExg(op); + if ((op&0xf000)==0xe000) OpAsr(op); // Asr/l/Ror/l etc + if ((op&0xf8c0)==0xe0c0) OpAsrEa(op); +} diff --git a/cpu/Cyclone/OpArith.cpp b/cpu/Cyclone/OpArith.cpp new file mode 100644 index 00000000..33cdf870 --- /dev/null +++ b/cpu/Cyclone/OpArith.cpp @@ -0,0 +1,758 @@ + +#include "app.h" + +// --------------------- Opcodes 0x0000+ --------------------- +// Emit an Ori/And/Sub/Add/Eor/Cmp Immediate opcode, 0000ttt0 ssaaaaaa +int OpArith(int op) +{ + int type=0,size=0; + int sea=0,tea=0; + int use=0; + + // Get source and target EA + type=(op>>9)&7; if (type==4 || type>=7) return 1; + size=(op>>6)&3; if (size>=3) return 1; + sea= 0x003c; + tea=op&0x003f; + + // See if we can do this opcode: + if (EaCanRead(tea,size)==0) return 1; + if (EaCanWrite(tea)==0 || EaAn(tea)) return 1; + + use=OpBase(op); + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); Cycles=4; + + EaCalc(10,0x0000, sea,size,1); + EaRead(10, 10, sea,size,0,1); + + EaCalc(11,0x003f, tea,size,1); + EaRead(11, 0, tea,size,0x003f,1); + + ot(";@ Do arithmetic:\n"); + + if (type==0) ot(" orr r1,r0,r10\n"); + if (type==1) ot(" and r1,r0,r10\n"); + if (type==2) ot(" subs r1,r0,r10 ;@ Defines NZCV\n"); + if (type==3) ot(" adds r1,r0,r10 ;@ Defines NZCV\n"); + if (type==5) ot(" eor r1,r0,r10\n"); + if (type==6) ot(" cmp r0,r10 ;@ Defines NZCV\n"); + + if (type<2 || type==5) ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); // 0,1,5 + + if (type< 2) OpGetFlags(0,0); // Ori/And + if (type==2) OpGetFlags(1,1); // Sub: Subtract/X-bit + if (type==3) OpGetFlags(0,1); // Add: X-bit + if (type==5) OpGetFlags(0,0); // Eor + if (type==6) OpGetFlags(1,0); // Cmp: Subtract + ot("\n"); + + if (type!=6) + { + EaWrite(11, 1, tea,size,0x003f,1); + } + + // Correct cycles: + if (type==6) + { + if (size>=2 && tea<0x10) Cycles+=2; + } + else + { + if (size>=2) Cycles+=4; + if (tea>=8) Cycles+=4; + if (type==1 && size>=2 && tea<8) Cycles-=2; + } + + OpEnd(); + + return 0; +} + +// --------------------- Opcodes 0x5000+ --------------------- +int OpAddq(int op) +{ + // 0101nnnt xxeeeeee (nnn=#8,1-7 t=addq/subq xx=size, eeeeee=EA) + int num=0,type=0,size=0,ea=0; + int use=0; + char count[16]=""; + int shift=0; + + num =(op>>9)&7; if (num==0) num=8; + type=(op>>8)&1; + size=(op>>6)&3; if (size>=3) return 1; + ea = op&0x3f; + + // See if we can do this opcode: + if (EaCanRead (ea,size)==0) return 1; + if (EaCanWrite(ea) ==0) return 1; + if (size == 0 && EaAn(ea) ) return 1; + + use=OpBase(op,1); + + if (num!=8) use|=0x0e00; // If num is not 8, use same handler + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); + Cycles=ea<8?4:8; + if(type==0&&size==1) Cycles=ea<0x10?4:8; + if(size>=2) Cycles=ea<0x10?8:12; + + if (size>0 && (ea&0x38)==0x08) size=2; // addq.w #n,An is also 32-bit + + EaCalc(10,0x003f, ea,size,1); + EaRead(10, 0, ea,size,0x003f,1); + + shift=32-(8<=0) ot(" mov r2,r8,lsr #%d ;@ Get quick value\n", lsr); + else ot(" mov r2,r8,lsl #%d ;@ Get quick value\n",-lsr); + + ot(" and r2,r2,#0x%.4x\n",7<>12)&5; + rea =(op>> 9)&7; + dir =(op>> 8)&1; // er,re + size=(op>> 6)&3; if (size>=3) return 1; + ea = op&0x3f; + + if (dir && ea<0x10) return 1; // addx/subx opcode + + // See if we can do this opcode: + if (dir==0 && EaCanRead (ea,size)==0) return 1; + if (dir && EaCanWrite(ea)==0) return 1; + if ((size==0||!(type&1))&&EaAn(ea)) return 1; + + use=OpBase(op); + use&=~0x0e00; // Use same opcode for Dn + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); Cycles=4; + + ot(";@ Get r10=EA r11=EA value\n"); + EaCalc(10,0x003f, ea,size,1); + EaRead(10, 11, ea,size,0x003f,1); + ot(";@ Get r0=Register r1=Register value\n"); + EaCalc( 0,0x0e00,rea,size,1); + EaRead( 0, 1,rea,size,0x0e00,1); + + ot(";@ Do arithmetic:\n"); + if (type==0) ot(" orr "); + if (type==1) ot(" subs "); + if (type==4) ot(" and "); + if (type==5) ot(" adds "); + if (dir) ot("r1,r11,r1\n"); + else ot("r1,r1,r11\n"); + + if ((type&1)==0) ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); + + OpGetFlags(type==1,type&1); // 1==subtract + ot("\n"); + + ot(";@ Save result:\n"); + if (dir) EaWrite(10, 1, ea,size,0x003f,1); + else EaWrite( 0, 1,rea,size,0x0e00,1); + + if(rea==ea) { + if(ea<8) Cycles=(size>=2)?8:4; else Cycles+=(size>=2)?26:14; + } else if(dir) { + Cycles+=4; + if(size>=2) Cycles+=4; + } else { + if(size>=2) { + Cycles+=2; + if(ea<0x10||ea==0x3c) Cycles+=2; + } + } + + OpEnd(); + + return 0; +} + +// --------------------- Opcodes 0x80c0+ --------------------- +int OpMul(int op) +{ + // Div/Mul: 1m00nnns 11eeeeee (m=Mul, nnn=Register Dn, s=signed, eeeeee=EA) + int type=0,rea=0,sign=0,ea=0; + int use=0; + + type=(op>>14)&1; // div/mul + rea =(op>> 9)&7; + sign=(op>> 8)&1; + ea = op&0x3f; + + // See if we can do this opcode: + if (EaCanRead(ea,1)==0||EaAn(ea)) return 1; + + use=OpBase(op); + use&=~0x0e00; // Use same for all registers + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); + if(type) Cycles=54; + else Cycles=sign?158:140; + + EaCalc(10,0x003f, ea, 1); + EaRead(10, 10, ea, 1,0x003f); + + EaCalc (0,0x0e00,rea, 2,1); + EaRead (0, 2,rea, 2,0x0e00,1); + + if (type==0) // div + { + // the manual says C is always cleared, but neither Musashi nor FAME do that + //ot(" bic r9,r9,#0x20000000 ;@ always clear C\n"); + ot(" tst r10,r10\n"); + ot(" beq divzero%.4x ;@ division by zero\n",op); + ot("\n"); + + if (sign) + { + ot(" mov r11,#0 ;@ r11 = 1 or 2 if the result is negative\n"); + ot(" orrmi r11,r11,#1\n"); + ot(" rsbmi r10,r10,#0 ;@ Make r10 positive\n"); + ot("\n"); + ot(" tst r2,r2\n"); + ot(" orrmi r11,r11,#2\n"); + ot(" rsbmi r2,r2,#0 ;@ Make r2 positive\n"); + ot("\n"); + } + else + { + ot(" mov r10,r10,lsl #16 ;@ use only 16 bits of divisor\n"); + ot(" mov r10,r10,lsr #16\n"); + } + + ot(";@ Divide r2 by r10\n"); + ot(" mov r3,#0\n"); + ot(" mov r1,r10\n"); + ot("\n"); + ot(";@ Shift up divisor till it's just less than numerator\n"); + ot("Shift%.4x%s\n",op,ms?"":":"); + ot(" cmp r1,r2,lsr #1\n"); + ot(" movls r1,r1,lsl #1\n"); + ot(" bcc Shift%.4x\n",op); + ot("\n"); + + ot("Divide%.4x%s\n",op,ms?"":":"); + ot(" cmp r2,r1\n"); + ot(" adc r3,r3,r3 ;@ Double r3 and add 1 if carry set\n"); + ot(" subcs r2,r2,r1\n"); + ot(" teq r1,r10\n"); + ot(" movne r1,r1,lsr #1\n"); + ot(" bne Divide%.4x\n",op); + ot("\n"); + ot(";@r3==quotient,r2==remainder\n"); + + if (sign) + { + // sign correction + ot(" and r1,r11,#1\n"); + ot(" teq r1,r11,lsr #1\n"); + ot(" rsbne r3,r3,#0 ;@ negate if quotient is negative\n"); + ot(" tst r11,#2\n"); + ot(" rsbne r2,r2,#0 ;@ negate the remainder if divident was negative\n"); + ot("\n"); + + // signed overflow check + ot(" mov r1,r3,asl #16\n"); + ot(" cmp r3,r1,asr #16 ;@ signed overflow?\n"); + ot(" orrne r9,r9,#0x10000000 ;@ set overflow flag\n"); + ot(" bne endofop%.4x ;@ overflow!\n",op); + } + else + { + // overflow check + ot(" movs r1,r3,lsr #16 ;@ check for overflow condition\n"); + ot(" orrne r9,r9,#0x10000000 ;@ set overflow flag\n"); + ot(" bne endofop%.4x ;@ overflow!\n",op); + } + + ot(" mov r1,r3,lsl #16 ;@ Clip to 16-bits\n"); + ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); + OpGetFlags(0,0); + + ot(" mov r1,r1,lsr #16\n"); + ot(" orr r1,r1,r2,lsl #16 ;@ Insert remainder\n"); + } + + if (type==1) + { + char *shift="asr"; + + ot(";@ Get 16-bit signs right:\n"); + if (sign==0) { ot(" mov r10,r10,lsl #16\n"); shift="lsr"; } + ot(" mov r2,r2,lsl #16\n"); + + if (sign==0) ot(" mov r10,r10,lsr #16\n"); + ot(" mov r2,r2,%s #16\n",shift); + ot("\n"); + + ot(" mul r1,r2,r10\n"); + ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); + OpGetFlags(0,0); + } + ot("\n"); + + EaWrite(0, 1,rea, 2,0x0e00,1); + + ot("endofop%.4x%s\n",op,ms?"":":"); + OpEnd(); + + ot("divzero%.4x%s\n",op,ms?"":":"); + ot(" mov r0,#0x14 ;@ Divide by zero\n"); + ot(" bl Exception\n"); + Cycles+=38; + OpEnd(); + ot("\n"); + + return 0; +} + +// Get X Bit into carry - trashes r2 +int GetXBit(int subtract) +{ + ot(";@ Get X bit:\n"); + ot(" ldrb r2,[r7,#0x45]\n"); + if (subtract) ot(" mvn r2,r2,lsl #28 ;@ Invert it\n"); + else ot(" mov r2,r2,lsl #28\n"); + ot(" msr cpsr_flg,r2 ;@ Get into Carry\n"); + ot("\n"); + return 0; +} + +// --------------------- Opcodes 0x8100+ --------------------- +// 1t00ddd1 0000asss - sbcd/abcd Ds,Dd or -(As),-(Ad) +int OpAbcd(int op) +{ + int use=0; + int type=0,sea=0,addr=0,dea=0; + + type=(op>>14)&1; // sbcd/abcd + dea =(op>> 9)&7; + addr=(op>> 3)&1; + sea = op &7; + + if (addr) { sea|=0x20; dea|=0x20; } + + use=op&~0x0e07; // Use same opcode for all registers.. + if (sea==0x27||dea==0x27) use=op; // ..except -(a7) + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); Cycles=6; + + EaCalc( 0,0x0007, sea,0,1); + EaRead( 0, 10, sea,0,0x0007,1); + EaCalc(11,0x0e00, dea,0,1); + EaRead(11, 1, dea,0,0x0e00,1); + + ot(" bic r9,r9,#0xb1000000 ;@ clear all flags except old Z\n"); + + if (type) + { + ot(" ldrb r0,[r7,#0x45] ;@ Get X bit\n"); + ot(" mov r3,#0x00f00000\n"); + ot(" and r2,r3,r1,lsr #4\n"); + ot(" tst r0,#2\n"); + ot(" and r0,r3,r10,lsr #4\n"); + ot(" add r0,r0,r2\n"); + ot(" addne r0,r0,#0x00100000\n"); +// ot(" tst r0,#0x00800000\n"); +// ot(" orreq r9,r9,#0x01000000 ;@ Undefined V behavior\n"); + ot(" cmp r0,#0x00900000\n"); + ot(" addhi r0,r0,#0x00600000 ;@ Decimal adjust units\n"); + + ot(" mov r2,r1,lsr #28\n"); + ot(" add r0,r0,r2,lsl #24\n"); + ot(" mov r2,r10,lsr #28\n"); + ot(" add r0,r0,r2,lsl #24\n"); + ot(" cmp r0,#0x09900000\n"); + ot(" orrhi r9,r9,#0x20000000 ;@ C\n"); + ot(" subhi r0,r0,#0x0a000000\n"); +// ot(" and r3,r9,r0,lsr #3 ;@ Undefined V behavior part II\n"); +// ot(" orr r9,r9,r3,lsl #4 ;@ V\n"); + ot(" movs r0,r0,lsl #4\n"); + ot(" orrmi r9,r9,#0x90000000 ;@ Undefined N+V behavior\n"); // this is what Musashi really does + ot(" bicne r9,r9,#0x40000000 ;@ Z flag\n"); + } + else + { + ot(" ldrb r0,[r7,#0x45] ;@ Get X bit\n"); + ot(" mov r3,#0x00f00000\n"); + ot(" and r2,r3,r10,lsr #4\n"); + ot(" tst r0,#2\n"); + ot(" and r0,r3,r1,lsr #4\n"); + ot(" sub r0,r0,r2\n"); + ot(" subne r0,r0,#0x00100000\n"); +// ot(" tst r0,#0x00800000\n"); +// ot(" orreq r9,r9,#0x01000000 ;@ Undefined V behavior\n"); + ot(" cmp r0,#0x00900000\n"); + ot(" subhi r0,r0,#0x00600000 ;@ Decimal adjust units\n"); + + ot(" mov r2,r1,lsr #28\n"); + ot(" add r0,r0,r2,lsl #24\n"); + ot(" mov r2,r10,lsr #28\n"); + ot(" sub r0,r0,r2,lsl #24\n"); + ot(" cmp r0,#0x09900000\n"); + ot(" orrhi r9,r9,#0xa0000000 ;@ N and C\n"); + ot(" addhi r0,r0,#0x0a000000\n"); +// ot(" and r3,r9,r0,lsr #3 ;@ Undefined V behavior part II\n"); +// ot(" orr r9,r9,r3,lsl #4 ;@ V\n"); + ot(" movs r0,r0,lsl #4\n"); +// ot(" orrmi r9,r9,#0x80000000 ;@ Undefined N behavior\n"); + ot(" bicne r9,r9,#0x40000000 ;@ Z flag\n"); + } + + ot(" mov r2,r9,lsr #28\n"); + ot(" strb r2,[r7,#0x45] ;@ Save X bit\n"); + + EaWrite(11, 0, dea,0,0x0e00,1); + OpEnd(); + + return 0; +} + +// 01008000 00eeeeee - nbcd +int OpNbcd(int op) +{ + int use=0; + int ea=0; + + ea=op&0x3f; + + if(EaCanWrite(ea)==0||EaAn(ea)) return 1; + + use=OpBase(op); + if(op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); Cycles=6; + if(ea >= 8) Cycles+=2; + + EaCalc(10,0x3f, ea,0,1); + EaRead(10, 0, ea,0,0x3f,1); + + // this is rewrite of Musashi's code + ot(" ldrb r2,[r7,#0x45]\n"); + ot(" tst r2,#2\n"); + ot(" mov r2,r0\n"); + ot(" addne r2,r0,#0x01000000 ;@ add X\n"); + ot(" rsbs r1,r2,#0x9a000000 ;@ do arithmetic\n"); + + ot(" bic r9,r9,#0xb0000000 ;@ clear all flags, except Z\n"); + ot(" orrmi r9,r9,#0x80000000 ;@ N\n"); + ot(" cmp r1,#0x9a000000\n"); + ot(" beq finish%.4x\n",op); + ot("\n"); + + ot(" mvn r3,r9,lsr #3 ;@ Undefined V behavior\n",op); + ot(" and r2,r1,#0x0f000000\n"); + ot(" cmp r2,#0x0a000000\n"); + ot(" andeq r1,r1,#0xf0000000\n"); + ot(" addeq r1,r1,#0x10000000\n"); + ot(" and r3,r3,r1,lsr #3 ;@ Undefined V behavior part II\n",op); + ot(" tst r1,r1\n"); + ot(" orr r9,r9,r3 ;@ save V\n",op); + ot(" bicne r9,r9,#0x40000000 ;@ Z\n"); + ot(" orr r9,r9,#0x20000000 ;@ C\n"); + ot("\n"); + + EaWrite(10, 1, ea,0,0x3f,1); + + ot("finish%.4x%s\n",op,ms?"":":"); + ot(" mov r2,r9,lsr #28\n"); + ot(" strb r2, [r7,#0x45]\n"); + + OpEnd(); + + return 0; +} + +// --------------------- Opcodes 0x90c0+ --------------------- +// Suba/Cmpa/Adda 1tt1nnnx 11eeeeee (tt=type, x=size, eeeeee=Source EA) +int OpAritha(int op) +{ + int use=0; + int type=0,size=0,sea=0,dea=0; + + // Suba/Cmpa/Adda/(invalid): + type=(op>>13)&3; if (type>=3) return 1; + + size=(op>>8)&1; size++; + dea=(op>>9)&7; dea|=8; // Dest=An + sea=op&0x003f; // Source + + // See if we can do this opcode: + if (EaCanRead(sea,size)==0) return 1; + + use=OpBase(op); + use&=~0x0e00; // Use same opcode for An + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); Cycles=(size==2)?6:8; + if(size==2&&(sea<0x10||sea==0x3c)) Cycles+=2; + if(type==1) Cycles=6; + + + EaCalc ( 0,0x003f, sea,size); + EaRead ( 0, 10, sea,size,0x003f); + + EaCalc ( 0,0x0e00, dea,2,1); + EaRead ( 0, 1, dea,2,0x0e00); + + if (type==0) ot(" sub r1,r1,r10\n"); + if (type==1) ot(" cmp r1,r10 ;@ Defines NZCV\n"); + if (type==1) OpGetFlags(1,0); // Get Cmp flags + if (type==2) ot(" add r1,r1,r10\n"); + ot("\n"); + + if (type!=1) EaWrite( 0, 1, dea,2,0x0e00,1); + + OpEnd(); + + return 0; +} + +// --------------------- Opcodes 0x9100+ --------------------- +// Emit a Subx/Addx opcode, 1t01ddd1 zz00rsss addx.z Ds,Dd +int OpAddx(int op) +{ + int use=0; + int type=0,size=0,dea=0,sea=0,mem=0; + + type=(op>>12)&5; + dea =(op>> 9)&7; + size=(op>> 6)&3; if (size>=3) return 1; + sea = op&7; + mem =(op>> 3)&1; + + // See if we can do this opcode: + if (EaCanRead(sea,size)==0) return 1; + if (EaCanWrite(dea)==0) return 1; + + if(mem) { sea+=0x20; dea+=0x20; } + + use=op&~0x0e07; // Use same opcode for Dn + if (size==0&&(sea==0x27||dea==0x27)) use=op; // ___x.b -(a7) + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); Cycles=4; + if(size>=2) Cycles+=4; + if(sea>=0x10) Cycles+=2; + + ot(";@ Get r10=EA r11=EA value\n"); + EaCalc( 0,0x0007,sea,size,1); + EaRead( 0, 11,sea,size,0x0007,1); + ot(";@ Get r0=Register r1=Register value\n"); + EaCalc( 0,0x0e00,dea,size,1); + EaRead( 0, 1,dea,size,0x0e00,1); + + ot(";@ Do arithmetic:\n"); + GetXBit(type==1); + + if (type==5 && size<2) + { + ot(";@ Make sure the carry bit will tip the balance:\n"); + ot(" mvn r2,#0\n"); + ot(" orr r11,r11,r2,lsr #%i\n",(size==0)?8:16); + ot("\n"); + } + + if (type==1) ot(" sbcs r1,r1,r11\n"); + if (type==5) ot(" adcs r1,r1,r11\n"); + ot(" orr r3,r9,#0xb0000000 ;@ for old Z\n"); + OpGetFlags(type==1,1,0); // subtract + if (size<2) { + ot(" movs r2,r1,lsr #%i\n", size?16:24); + ot(" orreq r9,r9,#0x40000000 ;@ add potentially missed Z\n"); + } + ot(" andeq r9,r9,r3 ;@ fix Z\n"); + ot("\n"); + + ot(";@ Save result:\n"); + EaWrite( 0, 1, dea,size,0x0e00,1); + + OpEnd(); + + return 0; +} + +// --------------------- Opcodes 0xb000+ --------------------- +// Emit a Cmp/Eor opcode, 1011rrrt xxeeeeee (rrr=Dn, t=cmp/eor, xx=size extension, eeeeee=ea) +int OpCmpEor(int op) +{ + int rea=0,eor=0; + int size=0,ea=0,use=0; + + // Get EA and register EA + rea=(op>>9)&7; + eor=(op>>8)&1; + size=(op>>6)&3; if (size>=3) return 1; + ea=op&0x3f; + + if (eor && (ea>>3) == 1) return 1; // not a valid mode for eor + + // See if we can do this opcode: + if (EaCanRead(ea,size)==0) return 1; + if (eor && EaCanWrite(ea)==0) return 1; + if (EaAn(ea)&&(eor||size==0)) return 1; + + use=OpBase(op); + use&=~0x0e00; // Use 1 handler for register d0-7 + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); Cycles=4; + if(eor) { + if(ea>8) Cycles+=4; + if(size>=2) Cycles+=4; + } else { + if(size>=2) Cycles+=2; + } + + ot(";@ Get EA into r10 and value into r0:\n"); + EaCalc (10,0x003f, ea,size,1); + EaRead (10, 0, ea,size,0x003f,1); + + ot(";@ Get register operand into r1:\n"); + EaCalc (1, 0x0e00, rea,size,1); + EaRead (1, 1, rea,size,0x0e00,1); + + ot(";@ Do arithmetic:\n"); + if (eor==0) ot(" cmp r1,r0\n"); + if (eor) + { + ot(" eor r1,r0,r1\n"); + ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); + } + + OpGetFlags(eor==0,0); // Cmp like subtract + ot("\n"); + + if (eor) EaWrite(10, 1,ea,size,0x003f,1); + + OpEnd(); + return 0; +} + +// Emit a Cmpm opcode, 1011ddd1 xx001sss (rrr=Adst, xx=size extension, sss=Asrc) +int OpCmpm(int op) +{ + int size=0,sea=0,dea=0,use=0; + + // get size, get EAs + size=(op>>6)&3; if (size>=3) return 1; + sea=(op&7)|0x18; + dea=(op>>9)&0x3f; + + use=op&~0x0e07; // Use 1 handler for all registers.. + if (size==0&&(sea==0x1f||dea==0x1f)) use=op; // ..except (a7)+ + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); Cycles=4; + + ot(";@ Get src operand into r10:\n"); + EaCalc (0,0x000f, sea,size,1); + EaRead (0, 10, sea,size,0x000f,1); + + ot(";@ Get dst operand into r0:\n"); + EaCalc (0,0x1e00, dea,size,1); + EaRead (0, 0, dea,size,0x1e00,1); + + ot(" cmp r0,r10\n"); + OpGetFlags(1,0); // Cmp like subtract + + OpEnd(); + return 0; +} + + +// Emit a Chk opcode, 0100ddd1 x0eeeeee (rrr=Dn, x=size extension, eeeeee=ea) +int OpChk(int op) +{ + int rea=0; + int size=0,ea=0,use=0; + + // Get EA and register EA + rea=(op>>9)&7; + if((op>>7)&1) + size=1; // word operation + else size=2; // long + ea=op&0x3f; + + if (EaAn(ea)) return 1; // not a valid mode + if (size!=1) return 1; // 000 variant only supports word + + // See if we can do this opcode: + if (EaCanRead(ea,size)==0) return 1; + + use=OpBase(op); + use&=~0x0e00; // Use 1 handler for register d0-7 + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); Cycles=10; + + ot(";@ Get EA into r10 and value into r0:\n"); + EaCalc (10,0x003f, ea,size,1); + EaRead (10, 0, ea,size,0x003f,1); + + ot(";@ Get register operand into r1:\n"); + EaCalc (1, 0x0e00, rea,size,1); + EaRead (1, 1, rea,size,0x0e00,1); + + ot(";@ get flags, including undocumented ones\n"); + ot(" and r3,r9,#0x80000000\n"); + ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); + OpGetFlags(0,0); + + ot(";@ is reg negative?\n"); + ot(" bmi chktrap%.4x\n",op); + + ot(";@ Do arithmetic:\n"); + ot(" cmp r1,r0\n"); + ot(" bicgt r9,r9,#0x80000000 ;@ N\n"); + ot(" bgt chktrap%.4x\n",op); + + ot(";@ old N remains\n"); + ot(" bic r9,r9,#0x80000000 ;@ N\n"); + ot(" orr r9,r9,r3\n"); + OpEnd(); + + ot("chktrap%.4x%s ;@ CHK exception:\n",op,ms?"":":"); + ot(" mov r0,#0x18\n"); + ot(" bl Exception\n"); + Cycles+=40; + OpEnd(); + + return 0; +} + diff --git a/cpu/Cyclone/OpBranch.cpp b/cpu/Cyclone/OpBranch.cpp new file mode 100644 index 00000000..71f97858 --- /dev/null +++ b/cpu/Cyclone/OpBranch.cpp @@ -0,0 +1,434 @@ + +#include "app.h" + +#if USE_CHECKPC_CALLBACK +static void CheckPc() +{ + ot(";@ Check Memory Base+pc (r4)\n"); + ot(" add lr,pc,#4\n"); + ot(" mov r0,r4\n"); + ot(" ldr pc,[r7,#0x64] ;@ Call checkpc()\n"); + ot(" mov r4,r0\n"); + ot("\n"); +} +#endif + +// Push 32-bit value in r1 - trashes r0-r3,r12,lr +void OpPush32() +{ + ot(";@ Push r1 onto stack\n"); + ot(" ldr r0,[r7,#0x3c]\n"); + ot(" sub r0,r0,#4 ;@ Predecrement A7\n"); + ot(" str r0,[r7,#0x3c] ;@ Save A7\n"); + MemHandler(1,2); + ot("\n"); +} + +// Push SR - trashes r0-r3,r12,lr +void OpPushSr(int high) +{ + ot(";@ Push SR:\n"); + OpFlagsToReg(high); + ot(" ldr r0,[r7,#0x3c]\n"); + ot(" sub r0,r0,#2 ;@ Predecrement A7\n"); + ot(" str r0,[r7,#0x3c] ;@ Save A7\n"); + MemHandler(1,1); + ot("\n"); +} + +// Pop SR - trashes r0-r3 +static void PopSr(int high) +{ + ot(";@ Pop SR:\n"); + ot(" ldr r0,[r7,#0x3c]\n"); + ot(" add r1,r0,#2 ;@ Postincrement A7\n"); + ot(" str r1,[r7,#0x3c] ;@ Save A7\n"); + MemHandler(0,1); + ot("\n"); + OpRegToFlags(high); +} + +// Pop PC - assumes r10=Memory Base - trashes r0-r3 +static void PopPc() +{ + ot(";@ Pop PC:\n"); + ot(" ldr r0,[r7,#0x3c]\n"); + ot(" add r1,r0,#4 ;@ Postincrement A7\n"); + ot(" str r1,[r7,#0x3c] ;@ Save A7\n"); + MemHandler(0,2); + ot(" add r4,r0,r10 ;@ r4=Memory Base+PC\n"); + ot("\n"); + CheckPc(); +} + +int OpTrap(int op) +{ + int use=0; + + use=op&~0xf; + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); + ot(" and r0,r8,#0xf ;@ Get trap number\n"); + ot(" orr r0,r0,#0x20\n"); + ot(" mov r0,r0,asl #2\n"); + ot(" bl Exception\n"); + ot("\n"); + + Cycles=38; OpEnd(); + + return 0; +} + +// --------------------- Opcodes 0x4e50+ --------------------- +int OpLink(int op) +{ + int use=0,reg; + + use=op&~7; + reg=op&7; + if (reg==7) use=op; + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); + + if(reg!=7) { + ot(";@ Get An\n"); + EaCalc(10, 7, 8, 2, 1); + EaRead(10, 1, 8, 2, 7, 1); + } + + ot(" ldr r0,[r7,#0x3c] ;@ Get A7\n"); + ot(" sub r0,r0,#4 ;@ A7-=4\n"); + ot(" mov r11,r0\n"); + if(reg==7) ot(" mov r1,r0\n"); + ot("\n"); + + ot(";@ Write An to Stack\n"); + MemHandler(1,2); + + ot(";@ Save to An\n"); + if(reg!=7) + EaWrite(10,11, 8, 2, 7, 1); + + ot(";@ Get offset:\n"); + EaCalc(0,0,0x3c,1); + EaRead(0,0,0x3c,1,0); + + ot(" add r11,r11,r0 ;@ Add offset to A7\n"); + ot(" str r11,[r7,#0x3c]\n"); + ot("\n"); + + Cycles=16; + OpEnd(); + return 0; +} + +// --------------------- Opcodes 0x4e58+ --------------------- +int OpUnlk(int op) +{ + int use=0; + + use=op&~7; + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); + + ot(";@ Get An\n"); + EaCalc(10, 7, 8, 2, 1); + EaRead(10, 0, 8, 2, 7, 1); + + ot(" add r11,r0,#4 ;@ A7+=4\n"); + ot("\n"); + ot(";@ Pop An from stack:\n"); + MemHandler(0,2); + ot("\n"); + ot(" str r11,[r7,#0x3c] ;@ Save A7\n"); + ot("\n"); + ot(";@ An = value from stack:\n"); + EaWrite(10, 0, 8, 2, 7, 1); + + Cycles=12; + OpEnd(); + return 0; +} + +// --------------------- Opcodes 0x4e70+ --------------------- +int Op4E70(int op) +{ + int type=0; + + type=op&7; // 01001110 01110ttt, reset/nop/stop/rte/rtd/rts/trapv/rtr + + switch (type) + { + case 1: // nop + OpStart(op); + Cycles=4; + OpEnd(); + return 0; + + case 3: // rte + OpStart(op); Cycles=20; + SuperCheck(op); + PopSr(1); + ot(" ldr r10,[r7,#0x60] ;@ Get Memory base\n"); + PopPc(); + SuperChange(op); + CheckInterrupt(op); + OpEnd(); + SuperEnd(op); + return 0; + + case 5: // rts + OpStart(op); Cycles=16; + ot(" ldr r10,[r7,#0x60] ;@ Get Memory base\n"); + PopPc(); + OpEnd(); + return 0; + + case 6: // trapv + OpStart(op); Cycles=4; + ot(" tst r9,#0x10000000\n"); + ot(" subne r5,r5,#%i\n",30); + ot(" movne r0,#0x1c ;@ TRAPV exception\n"); + ot(" blne Exception\n"); + OpEnd(); + return 0; + + case 7: // rtr + OpStart(op); Cycles=20; + PopSr(0); + ot(" ldr r10,[r7,#0x60] ;@ Get Memory base\n"); + PopPc(); + OpEnd(); + return 0; + + default: + return 1; + } +} + +// --------------------- Opcodes 0x4e80+ --------------------- +// Emit a Jsr/Jmp opcode, 01001110 1meeeeee +int OpJsr(int op) +{ + int use=0; + int sea=0; + + sea=op&0x003f; + + // See if we can do this opcode: + if (EaCanRead(sea,-1)==0) return 1; + + use=OpBase(op); + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); + + ot(" ldr r10,[r7,#0x60] ;@ Get Memory base\n"); + ot("\n"); + EaCalc(0,0x003f,sea,0); + + ot(";@ Jump - Get new PC from r0\n"); + if (op&0x40) + { + // Jmp - Get new PC from r0 + ot(" add r4,r0,r10 ;@ r4 = Memory Base + New PC\n"); + ot("\n"); + } + else + { + ot(";@ Jsr - Push old PC first\n"); + ot(" sub r1,r4,r10 ;@ r1 = Old PC\n"); + ot(" add r4,r0,r10 ;@ r4 = Memory Base + New PC\n"); + ot(" mov r1,r1,lsl #8\n"); + ot(" ldr r0,[r7,#0x3c]\n"); + ot(" mov r1,r1,asr #8\n"); + ot(";@ Push r1 onto stack\n"); + ot(" sub r0,r0,#4 ;@ Predecrement A7\n"); + ot(" str r0,[r7,#0x3c] ;@ Save A7\n"); + MemHandler(1,2); + ot("\n"); + } + +#if USE_CHECKPC_CALLBACK + CheckPc(); +#endif + + Cycles=(op&0x40) ? 4 : 12; + Cycles+=Ea_add_ns((op&0x40) ? g_jmp_cycle_table : g_jsr_cycle_table, sea); + + OpEnd(); + + return 0; +} + +// --------------------- Opcodes 0x50c8+ --------------------- + +// ARM version of 68000 condition codes: +static char *Cond[16]= +{ + "", "", "hi","ls","cc","cs","ne","eq", + "vc","vs","pl","mi","ge","lt","gt","le" +}; + +// Emit a Dbra opcode, 0101cccc 11001nnn vv +int OpDbra(int op) +{ + int use=0; + int cc=0; + + use=op&~7; // Use same handler + cc=(op>>8)&15; + + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + OpStart(op); + + if (cc>=2) + { + ot(";@ Is the condition true?\n"); + if ((cc&~1)==2) ot(" eor r9,r9,#0x20000000 ;@ Invert carry for hi/ls\n"); + ot(" msr cpsr_flg,r9 ;@ ARM flags = 68000 flags\n"); + if ((cc&~1)==2) ot(" eor r9,r9,#0x20000000\n"); + ot(";@ If so, don't dbra\n"); + ot(" b%s DbraTrue%.4x\n",Cond[cc],op); + ot("\n"); + } + + ot(";@ Decrement Dn.w\n"); + ot(" and r1,r8,#0x0007\n"); + ot(" mov r1,r1,lsl #2\n"); + ot(" ldrsh r0,[r7,r1]\n"); + ot(" sub r0,r0,#1\n"); + ot(" strh r0,[r7,r1]\n"); + ot("\n"); + + ot(";@ Check if Dn.w is -1\n"); + ot(" cmps r0,#-1\n"); + ot(" beq DbraMin1%.4x\n",op); + ot("\n"); + + ot(";@ Get Branch offset:\n"); + ot(" ldrsh r0,[r4]\n"); + ot(" add r4,r4,r0 ;@ r4 = New PC\n"); + ot("\n"); + Cycles=12-2; + OpEnd(); + + ot(";@ Dn.w is -1:\n"); + ot("DbraMin1%.4x%s\n", op, ms?"":":"); + ot(" add r4,r4,#2 ;@ Skip branch offset\n"); + ot("\n"); + Cycles=12+2; + OpEnd(); + + ot(";@ condition true:\n"); + ot("DbraTrue%.4x%s\n", op, ms?"":":"); + ot(" add r4,r4,#2 ;@ Skip branch offset\n"); + ot("\n"); + Cycles=12; + OpEnd(); + + return 0; +} + +// --------------------- Opcodes 0x6000+ --------------------- +// Emit a Branch opcode 0110cccc nn (cccc=condition) +int OpBranch(int op) +{ + int size=0,use=0; + int offset=0; + int cc=0; + + offset=(char)(op&0xff); + cc=(op>>8)&15; + + // Special offsets: + if (offset==0) size=1; + if (offset==-1) size=2; + + if (size) use=op; // 16-bit or 32-bit + else use=(op&0xff00)+1; // Use same opcode for all 8-bit branches + + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + OpStart(op); + + ot(";@ Get Branch offset:\n"); + if (size) + { + EaCalc(0,0,0x3c,size); + EaRead(0,0,0x3c,size,0); + } + + // above code messes cycles + Cycles=10; // Assume branch taken + + if (size==0) ot(" mov r0,r8,asl #24 ;@ Shift 8-bit signed offset up...\n\n"); + + if (cc==1) ot(" ldr r10,[r7,#0x60] ;@ Get Memory base\n"); + + if (cc>=2) + { + ot(";@ Is the condition true?\n"); + if ((cc&~1)==2) ot(" eor r9,r9,#0x20000000 ;@ Invert carry for hi/ls\n"); + ot(" msr cpsr_flg,r9 ;@ ARM flags = 68000 flags\n"); + if ((cc&~1)==2) ot(" eor r9,r9,#0x20000000\n"); + + if (size==0) ot(" mov r0,r0,asr #24 ;@ ...shift down\n\n"); + + ot(" b%s DontBranch%.4x\n",Cond[cc^1],op); + + ot("\n"); + } + else + { + if (size==0) ot(" mov r0,r0,asr #24 ;@ ...shift down\n\n"); + } + + ot(";@ Branch taken - Add on r0 to PC\n"); + + if (cc==1) + { + ot(";@ Bsr - remember old PC\n"); + ot(" sub r1,r4,r10 ;@ r1 = Old PC\n"); + ot(" mov r1,r1, lsl #8\n"); + ot(" mov r1,r1, asr #8\n"); + ot("\n"); + if (size) ot(" sub r4,r4,#%d ;@ (Branch is relative to Opcode+2)\n",1<=2) + { + ot("DontBranch%.4x%s\n", op, ms?"":":"); + Cycles+=(size==1)? 2 : -2; // Branch not taken + OpEnd(); + } + + return 0; +} + diff --git a/cpu/Cyclone/OpLogic.cpp b/cpu/Cyclone/OpLogic.cpp new file mode 100644 index 00000000..4a795e40 --- /dev/null +++ b/cpu/Cyclone/OpLogic.cpp @@ -0,0 +1,672 @@ +#include "app.h" + +// --------------------- Opcodes 0x0100+ --------------------- +// Emit a Btst (Register) opcode 0000nnn1 ttaaaaaa +int OpBtstReg(int op) +{ + int use=0; + int type=0,sea=0,tea=0; + int size=0; + + type=(op>>6)&3; // Btst/Bchg/Bclr/Bset + // Get source and target EA + sea=(op>>9)&7; + tea=op&0x003f; + if (tea<0x10) size=2; // For registers, 32-bits + + if ((tea&0x38)==0x08) return 1; // movep + + // See if we can do this opcode: + if (EaCanRead(tea,0)==0) return 1; + if (type>0) + { + if (EaCanWrite(tea)==0) return 1; + } + + use=OpBase(op); + use&=~0x0e00; // Use same handler for all registers + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); + + if(type==1||type==3) { + Cycles=8; + } else { + Cycles=type?8:4; + if(size>=2) Cycles+=2; + } + + EaCalc (0,0x0e00,sea,0); + EaRead (0, 0,sea,0,0x0e00); + if (tea>=0x10) + ot(" and r10,r0,#7 ;@ mem - do mod 8\n"); + else ot(" and r10,r0,#31 ;@ reg - do mod 32\n"); + ot("\n"); + + EaCalc(11,0x003f,tea,size); + EaRead(11, 0,tea,size,0x003f); + ot(" mov r1,#1\n"); + ot(" tst r0,r1,lsl r10 ;@ Do arithmetic\n"); + ot(" bicne r9,r9,#0x40000000\n"); + ot(" orreq r9,r9,#0x40000000 ;@ Get Z flag\n"); + ot("\n"); + + if (type>0) + { + if (type==1) ot(" eor r1,r0,r1,lsl r10 ;@ Toggle bit\n"); + if (type==2) ot(" bic r1,r0,r1,lsl r10 ;@ Clear bit\n"); + if (type==3) ot(" orr r1,r0,r1,lsl r10 ;@ Set bit\n"); + ot("\n"); + EaWrite(11, 1,tea,size,0x003f); + } + OpEnd(); + + return 0; +} + +// --------------------- Opcodes 0x0800+ --------------------- +// Emit a Btst/Bchg/Bclr/Bset (Immediate) opcode 00001000 ttaaaaaa nn +int OpBtstImm(int op) +{ + int type=0,sea=0,tea=0; + int use=0; + int size=0; + + type=(op>>6)&3; + // Get source and target EA + sea= 0x003c; + tea=op&0x003f; + if (tea<0x10) size=2; // For registers, 32-bits + + // See if we can do this opcode: + if (EaCanRead(tea,0)==0||EaAn(tea)||tea==0x3c) return 1; + if (type>0) + { + if (EaCanWrite(tea)==0) return 1; + } + + use=OpBase(op); + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); + + ot(" mov r10,#1\n"); + ot("\n"); + EaCalc ( 0,0x0000,sea,0); + EaRead ( 0, 0,sea,0,0); + ot(" bic r9,r9,#0x40000000 ;@ Blank Z flag\n"); + if (tea>=0x10) + ot(" and r0,r0,#7 ;@ mem - do mod 8\n"); + else ot(" and r0,r0,#0x1F ;@ reg - do mod 32\n"); + ot(" mov r10,r10,lsl r0 ;@ Make bit mask\n"); + ot("\n"); + + if(type==1||type==3) { + Cycles=12; + } else { + Cycles=type?12:8; + if(size>=2) Cycles+=2; + } + + EaCalc (11,0x003f,tea,size); + EaRead (11, 0,tea,size,0x003f); + ot(" tst r0,r10 ;@ Do arithmetic\n"); + ot(" orreq r9,r9,#0x40000000 ;@ Get Z flag\n"); + ot("\n"); + + if (type>0) + { + if (type==1) ot(" eor r1,r0,r10 ;@ Toggle bit\n"); + if (type==2) ot(" bic r1,r0,r10 ;@ Clear bit\n"); + if (type==3) ot(" orr r1,r0,r10 ;@ Set bit\n"); + ot("\n"); + EaWrite(11, 1,tea,size,0x003f); + } + + OpEnd(); + + return 0; +} + +// --------------------- Opcodes 0x4000+ --------------------- +int OpNeg(int op) +{ + // 01000tt0 xxeeeeee (tt=negx/clr/neg/not, xx=size, eeeeee=EA) + int type=0,size=0,ea=0,use=0; + + type=(op>>9)&3; + ea =op&0x003f; + size=(op>>6)&3; if (size>=3) return 1; + + // See if we can do this opcode: + if (EaCanRead (ea,size)==0||EaAn(ea)) return 1; + if (EaCanWrite(ea )==0) return 1; + + use=OpBase(op); + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); Cycles=size<2?4:6; + if(ea >= 0x10) { + Cycles*=2; +#ifdef CYCLONE_FOR_GENESIS + // This is same as in Starscream core, CLR uses only 6 cycles for memory EAs. + // May be this is similar case as with TAS opcode, but this time the dummy + // read is ignored somehow? Without this hack Fatal Rewind hangs even in Gens. + if(type==1&&size<2) Cycles-=2; +#endif + } + + EaCalc (10,0x003f,ea,size); + + if (type!=1) EaRead (10,0,ea,size,0x003f); // Don't need to read for 'clr' + if (type==1) ot("\n"); + + if (type==0) + { + ot(";@ Negx:\n"); + GetXBit(1); + if(size!=2) ot(" mov r0,r0,lsl #%i\n",size?16:24); + ot(" rscs r1,r0,#0 ;@ do arithmetic\n"); + ot(" orr r3,r9,#0xb0000000 ;@ for old Z\n"); + OpGetFlags(1,1,0); + if(size!=2) { + ot(" movs r1,r1,asr #%i\n",size?16:24); + ot(" orreq r9,r9,#0x40000000 ;@ possily missed Z\n"); + } + ot(" andeq r9,r9,r3 ;@ fix Z\n"); + ot("\n"); + } + + if (type==1) + { + ot(";@ Clear:\n"); + ot(" mov r1,#0\n"); + ot(" mov r9,#0x40000000 ;@ NZCV=0100\n"); + ot("\n"); + } + + if (type==2) + { + ot(";@ Neg:\n"); + if(size!=2) ot(" mov r0,r0,lsl #%i\n",size?16:24); + ot(" rsbs r1,r0,#0\n"); + OpGetFlags(1,1); + if(size!=2) ot(" mov r1,r1,asr #%i\n",size?16:24); + ot("\n"); + } + + if (type==3) + { + ot(";@ Not:\n"); + ot(" mvn r1,r0\n"); + ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); + OpGetFlags(0,0); + ot("\n"); + } + + EaWrite(10, 1,ea,size,0x003f); + + OpEnd(); + + return 0; +} + +// --------------------- Opcodes 0x4840+ --------------------- +// Swap, 01001000 01000nnn swap Dn +int OpSwap(int op) +{ + int ea=0,use=0; + + ea=op&7; + use=op&~0x0007; // Use same opcode for all An + + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); Cycles=4; + + EaCalc (10,0x0007,ea,2,1); + EaRead (10, 0,ea,2,0x0007,1); + + ot(" mov r1,r0,ror #16\n"); + ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); + OpGetFlags(0,0); + + EaWrite(10, 1,8,2,0x0007,1); + + OpEnd(); + + return 0; +} + +// --------------------- Opcodes 0x4a00+ --------------------- +// Emit a Tst opcode, 01001010 xxeeeeee +int OpTst(int op) +{ + int sea=0; + int size=0,use=0; + + sea=op&0x003f; + size=(op>>6)&3; if (size>=3) return 1; + + // See if we can do this opcode: + if (EaCanWrite(sea)==0||EaAn(sea)) return 1; + + use=OpBase(op); + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); Cycles=4; + + EaCalc ( 0,0x003f,sea,size,1); + EaRead ( 0, 0,sea,size,0x003f,1); + + ot(" adds r0,r0,#0 ;@ Defines NZ, clears CV\n"); + ot(" mrs r9,cpsr ;@ r9=flags\n"); + ot("\n"); + + OpEnd(); + return 0; +} + +// --------------------- Opcodes 0x4880+ --------------------- +// Emit an Ext opcode, 01001000 1x000nnn +int OpExt(int op) +{ + int ea=0; + int size=0,use=0; + int shift=0; + + ea=op&0x0007; + size=(op>>6)&1; + shift=32-(8<>8)&15; + ea=op&0x003f; + + if ((ea&0x38)==0x08) return 1; // dbra, not scc + + // See if we can do this opcode: + if (EaCanWrite(ea)==0) return 1; + + use=OpBase(op); + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); Cycles=8; + if (ea<8) Cycles=4; + + ot(" mov r1,#0\n"); + + if (cc!=1) + { + ot(";@ Is the condition true?\n"); + if ((cc&~1)==2) ot(" eor r9,r9,#0x20000000 ;@ Invert carry for hi/ls\n"); + ot(" msr cpsr_flg,r9 ;@ ARM flags = 68000 flags\n"); + if ((cc&~1)==2) ot(" eor r9,r9,#0x20000000 ;@ Invert carry for hi/ls\n"); + ot(" mvn%s r1,r1\n",cond[cc]); + } + + if (cc!=1 && ea<8) ot(" sub%s r5,r5,#2 ;@ Extra cycles\n",cond[cc]); + ot("\n"); + + EaCalc (0,0x003f, ea,size); + EaWrite(0, 1, ea,size,0x003f); + + OpEnd(); + return 0; +} + +// Emit a Asr/Lsr/Roxr/Ror opcode +static int EmitAsr(int op,int type,int dir,int count,int size,int usereg) +{ + char pct[8]=""; // count + int shift=32-(8<=1) sprintf(pct,"#%d",count); // Fixed count + + if (usereg) + { + ot(";@ Use Dn for count:\n"); + ot(" and r2,r8,#7<<9\n"); + ot(" ldr r2,[r7,r2,lsr #7]\n"); + ot(" and r2,r2,#63\n"); + ot("\n"); + strcpy(pct,"r2"); + } + else if (count<0) + { + ot(" mov r2,r8,lsr #9 ;@ Get 'n'\n"); + ot(" and r2,r2,#7\n\n"); strcpy(pct,"r2"); + } + + // Take 2*n cycles: + if (count<0) ot(" sub r5,r5,r2,asl #1 ;@ Take 2*n cycles\n\n"); + else Cycles+=count<<1; + + if (type<2) + { + // Asr/Lsr + if (dir==0 && size<2) + { + ot(";@ For shift right, use loworder bits for the operation:\n"); + ot(" mov r0,r0,%s #%d\n",type?"lsr":"asr",32-(8<>9)&7; + dir =(op>>8)&1; + size =(op>>6)&3; + if (size>=3) return 1; // use OpAsrEa() + usereg=(op>>5)&1; + type =(op>>3)&3; + + if (usereg==0) count=((count-1)&7)+1; // because ccc=000 means 8 + + // Use the same opcode for target registers: + use=op&~0x0007; + + // As long as count is not 8, use the same opcode for all shift counts:: + if (usereg==0 && count!=8 && !(count==1&&type==2)) { use|=0x0e00; count=-1; } + if (usereg) { use&=~0x0e00; count=-1; } // Use same opcode for all Dn + + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); Cycles=size<2?6:8; + + EaCalc(10,0x0007, ea,size,1); + EaRead(10, 0, ea,size,0x0007,1); + + EmitAsr(op,type,dir,count, size,usereg); + + EaWrite(10, 0, ea,size,0x0007,1); + + OpEnd(); + + return 0; +} + +// Asr/Lsr/Roxr/Ror etc EA - 11100ttd 11eeeeee +int OpAsrEa(int op) +{ + int use=0,type=0,dir=0,ea=0,size=1; + + type=(op>>9)&3; + dir =(op>>8)&1; + ea = op&0x3f; + + if (ea<0x10) return 1; + // See if we can do this opcode: + if (EaCanRead(ea,0)==0) return 1; + if (EaCanWrite(ea)==0) return 1; + + use=OpBase(op); + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); Cycles=6; // EmitAsr() will add 2 + + EaCalc (10,0x003f,ea,size,1); + EaRead (10, 0,ea,size,0x003f,1); + + EmitAsr(op,type,dir,1,size,0); + + EaWrite(10, 0,ea,size,0x003f,1); + + OpEnd(); + return 0; +} + +int OpTas(int op) +{ + int ea=0; + int use=0; + + ea=op&0x003f; + + // See if we can do this opcode: + if (EaCanWrite(ea)==0 || EaAn(ea)) return 1; + + use=OpBase(op); + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); Cycles=4; + if(ea>=8) Cycles+=10; + + EaCalc (10,0x003f,ea,0,1); + EaRead (10, 1,ea,0,0x003f,1); + + ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); + OpGetFlags(0,0); + ot("\n"); + +#if CYCLONE_FOR_GENESIS + // the original Sega hardware ignores write-back phase (to memory only) + if (ea < 0x10) { +#endif + ot(" orr r1,r1,#0x80000000 ;@ set bit7\n"); + + EaWrite(10, 1,ea,0,0x003f,1); +#if CYCLONE_FOR_GENESIS + } +#endif + + OpEnd(); + return 0; +} + diff --git a/cpu/Cyclone/OpMove.cpp b/cpu/Cyclone/OpMove.cpp new file mode 100644 index 00000000..5d3459b9 --- /dev/null +++ b/cpu/Cyclone/OpMove.cpp @@ -0,0 +1,616 @@ + +#include "app.h" + + +// Pack our flags into r1, in SR/CCR register format +// trashes r0,r2 +void OpFlagsToReg(int high) +{ + ot(" ldrb r0,[r7,#0x45] ;@ X bit\n"); + ot(" mov r1,r9,lsr #28 ;@ ____NZCV\n"); + ot(" eor r2,r1,r1,ror #1 ;@ Bit 0=C^V\n"); + ot(" tst r2,#1 ;@ 1 if C!=V\n"); + ot(" eorne r1,r1,#3 ;@ ____NZVC\n"); + ot("\n"); + if (high) ot(" ldrb r2,[r7,#0x44] ;@ Include SR high\n"); + ot(" and r0,r0,#0x02\n"); + ot(" orr r1,r1,r0,lsl #3 ;@ ___XNZVC\n"); + if (high) ot(" orr r1,r1,r2,lsl #8\n"); + ot("\n"); +} + +// Convert SR/CRR register in r0 to our flags +// trashes r0,r1 +void OpRegToFlags(int high) +{ + ot(" eor r1,r0,r0,ror #1 ;@ Bit 0=C^V\n"); + ot(" mov r2,r0,lsr #3 ;@ r2=___XN\n"); + ot(" tst r1,#1 ;@ 1 if C!=V\n"); + ot(" eorne r0,r0,#3 ;@ ___XNZCV\n"); + ot(" strb r2,[r7,#0x45] ;@ Store X bit\n"); + ot(" mov r9,r0,lsl #28 ;@ r9=NZCV...\n"); + + if (high) + { + ot(" mov r0,r0,ror #8\n"); + ot(" and r0,r0,#0xa7 ;@ only take defined bits\n"); + ot(" strb r0,[r7,#0x44] ;@ Store SR high\n"); + } + ot("\n"); +} + +// checks for supervisor bit, if not set, jumps to SuperEnd() +// also sets r11 to SR high value, SuperChange() uses this +void SuperCheck(int op) +{ + ot(" ldr r11,[r7,#0x44] ;@ Get SR high\n"); + ot(" tst r11,#0x20 ;@ Check we are in supervisor mode\n"); + ot(" beq WrongMode%.4x ;@ No\n",op); + ot("\n"); +} + +void SuperEnd(int op) +{ + ot("WrongMode%.4x%s\n",op,ms?"":":"); + ot(" sub r4,r4,#2 ;@ this opcode wasn't executed - go back\n"); + ot(" mov r0,#0x20 ;@ privilege violation\n"); + ot(" bl Exception\n"); + Cycles=34; + OpEnd(); +} + +// does OSP and A7 swapping if needed +// new or old SR (not the one already in [r7,#0x44]) should be passed in r11 +// trashes r1,r11 +void SuperChange(int op) +{ + ot(";@ A7 <-> OSP?\n"); + ot(" ldr r1,[r7,#0x44] ;@ Get other SR high\n"); + ot(" and r11,r11,#0x20\n"); + ot(" and r1,r1,#0x20\n"); + ot(" teq r11,r1 ;@ r11 xor r1\n"); + ot(" beq no_sp_swap%.4x\n",op); + ot(" ;@ swap OSP and A7:\n"); + ot(" ldr r11,[r7,#0x3C] ;@ Get A7\n"); + ot(" ldr r1, [r7,#0x48] ;@ Get OSP\n"); + ot(" str r11,[r7,#0x48]\n"); + ot(" str r1, [r7,#0x3C]\n"); + ot("no_sp_swap%.4x%s\n", op, ms?"":":"); +} + + + +// --------------------- Opcodes 0x1000+ --------------------- +// Emit a Move opcode, 00xxdddd ddssssss +int OpMove(int op) +{ + int sea=0,tea=0; + int size=0,use=0; + int movea=0; + + // Get source and target EA + sea = op&0x003f; + tea =(op&0x01c0)>>3; + tea|=(op&0x0e00)>>9; + + if (tea>=8 && tea<0x10) movea=1; + + // Find size extension + switch (op&0x3000) + { + default: return 1; + case 0x1000: size=0; break; + case 0x3000: size=1; break; + case 0x2000: size=2; break; + } + + if (size<1 && (movea || EaAn(sea))) return 1; // move.b An,* and movea.b * are invalid + + // See if we can do this opcode: + if (EaCanRead (sea,size)==0) return 1; + if (EaCanWrite(tea )==0) return 1; + + use=OpBase(op); + if (tea<0x38) use&=~0x0e00; // Use same handler for register ?0-7 + + if (tea>=0x18 && tea<0x28 && (tea&7)==7) use|=0x0e00; // Specific handler for (a7)+ and -(a7) + + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); Cycles=4; + + EaCalc(0,0x003f,sea,size); + EaRead(0, 1,sea,size,0x003f); + + if (movea==0) { + ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); + ot(" mrs r9,cpsr ;@ r9=NZCV flags\n"); + ot("\n"); + } + + if (movea) size=2; // movea always expands to 32-bits + + EaCalc (0,0x0e00,tea,size); +#if SPLIT_MOVEL_PD + if ((tea&0x38)==0x20 && size==2) { // -(An) + ot(" mov r10,r0\n"); + ot(" mov r11,r1\n"); + ot(" add r0,r0,#2\n"); + EaWrite(0, 1,tea,1,0x0e00); + EaWrite(10, 11,tea,1,0x0e00,1); + } else { + EaWrite(0, 1,tea,size,0x0e00); + } +#else + EaWrite(0, 1,tea,size,0x0e00); +#endif + +#if CYCLONE_FOR_GENESIS && !MEMHANDLERS_CHANGE_CYCLES + // this is a bit hacky + if ((tea==0x39||(tea&0x38)==0x10)&&size>=1) + ot(" ldr r5,[r7,#0x5c] ;@ Load Cycles\n"); +#endif + + if((tea&0x38)==0x20) Cycles-=2; // less cycles when dest is -(An) + + OpEnd(); + return 0; +} + +// --------------------- Opcodes 0x41c0+ --------------------- +// Emit an Lea opcode, 0100nnn1 11aaaaaa +int OpLea(int op) +{ + int use=0; + int sea=0,tea=0; + + sea= op&0x003f; + tea=(op&0x0e00)>>9; tea|=8; + + if (EaCanRead(sea,-1)==0) return 1; // See if we can do this opcode + + use=OpBase(op); + use&=~0x0e00; // Also use 1 handler for target ?0-7 + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); + + EaCalc (1,0x003f,sea,0); // Lea + EaCalc (0,0x0e00,tea,2,1); + EaWrite(0, 1,tea,2,0x0e00,1); + + Cycles=Ea_add_ns(g_lea_cycle_table,sea); + + OpEnd(); + + return 0; +} + +// --------------------- Opcodes 0x40c0+ --------------------- +// Move SR opcode, 01000tt0 11aaaaaa move SR +int OpMoveSr(int op) +{ + int type=0,ea=0; + int use=0,size=1; + + type=(op>>9)&3; // from SR, from CCR, to CCR, to SR + ea=op&0x3f; + + if(EaAn(ea)) return 1; // can't use An regs + + switch(type) + { + case 0: + if (EaCanWrite(ea)==0) return 1; // See if we can do this opcode: + break; + + case 1: + return 1; // no such op in 68000 + + case 2: case 3: + if (EaCanRead(ea,size)==0) return 1; // See if we can do this opcode: + break; + } + + use=OpBase(op); + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); + Cycles=12; + if (type==0) Cycles=(ea>=8)?8:6; + + if (type==3) SuperCheck(op); // 68000 model allows reading whole SR in user mode (but newer models don't) + + if (type==0 || type==1) + { + OpFlagsToReg(type==0); + EaCalc (0,0x003f,ea,size); + EaWrite(0, 1,ea,size,0x003f); + } + + if (type==2 || type==3) + { + EaCalc(0,0x003f,ea,size); + EaRead(0, 0,ea,size,0x003f); + OpRegToFlags(type==3); + if (type==3) { + SuperChange(op); + CheckInterrupt(op); + } + } + + OpEnd(); + + if (type==3) SuperEnd(op); + + return 0; +} + + +// Ori/Andi/Eori $nnnn,sr 0000t0t0 01111100 +int OpArithSr(int op) +{ + int type=0,ea=0; + int use=0,size=0; + + type=(op>>9)&5; if (type==4) return 1; + size=(op>>6)&1; // ccr or sr? + ea=0x3c; + + use=OpBase(op); + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); Cycles=16; + + if (size) SuperCheck(op); + + EaCalc(0,0x003f,ea,size); + EaRead(0, 10,ea,size,0x003f); + + OpFlagsToReg(size); + if (type==0) ot(" orr r0,r1,r10\n"); + if (type==1) ot(" and r0,r1,r10\n"); + if (type==5) ot(" eor r0,r1,r10\n"); + OpRegToFlags(size); + if (size) { + SuperChange(op); + CheckInterrupt(op); + } + + OpEnd(); + if (size) SuperEnd(op); + + return 0; +} + +// --------------------- Opcodes 0x4850+ --------------------- +// Emit an Pea opcode, 01001000 01aaaaaa +int OpPea(int op) +{ + int use=0; + int ea=0; + + ea=op&0x003f; if (ea<0x10) return 1; // Swap opcode + if (EaCanRead(ea,-1)==0) return 1; // See if we can do this opcode: + + use=OpBase(op); + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); + + ot(" ldr r10,[r7,#0x3c]\n"); + EaCalc (1,0x003f, ea,0); + ot("\n"); + ot(" sub r0,r10,#4 ;@ Predecrement A7\n"); + ot(" str r0,[r7,#0x3c] ;@ Save A7\n"); + ot("\n"); + MemHandler(1,2); // Write 32-bit + ot("\n"); + + Cycles=6+Ea_add_ns(g_pea_cycle_table,ea); + + OpEnd(); + + return 0; +} + +// --------------------- Opcodes 0x4880+ --------------------- +// Emit a Movem opcode, 01001d00 1xeeeeee regmask +int OpMovem(int op) +{ + int size=0,ea=0,cea=0,dir=0; + int use=0,decr=0,change=0; + + size=((op>>6)&1)+1; // word, long + ea=op&0x003f; + dir=(op>>10)&1; // Direction (1==ea2reg) + + if (dir) { + if (ea<0x10 || ea>0x3b || (ea&0x38)==0x20) return 1; // Invalid EA + } else { + if (ea<0x10 || ea>0x39 || (ea&0x38)==0x18) return 1; + } + + if ((ea&0x38)==0x18 || (ea&0x38)==0x20) change=1; + if ((ea&0x38)==0x20) decr=1; // -(An), bitfield is decr + + cea=ea; if (change) cea=0x10; + + use=OpBase(op); + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); + + ot(" stmdb sp!,{r9} ;@ Push r9\n"); // can't just use r12 or lr here, because memhandlers touch them + ot(" ldrh r11,[r4],#2 ;@ r11=register mask\n"); + + ot("\n"); + ot(";@ Get the address into r9:\n"); + EaCalc(9,0x003f,cea,size); + + ot(";@ r10=Register Index*4:\n"); + if (decr) ot(" mov r10,#0x3c ;@ order reversed for -(An)\n"); + else ot(" mov r10,#0\n"); + + ot("\n"); + ot("MoreReg%.4x%s\n",op, ms?"":":"); + + ot(" tst r11,#1\n"); + ot(" beq SkipReg%.4x\n",op); + ot("\n"); + + if (decr) ot(" sub r9,r9,#%d ;@ Pre-decrement address\n",1<>3)&1; // Direction + use=op&~0x0007; // Use same opcode for all An + + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); Cycles=4; + + SuperCheck(op); + + if (dir) + { + ot(" ldr r1,[r7,#0x48] ;@ Get from USP\n\n"); + EaCalc (0,0x0007,8,2,1); + EaWrite(0, 1,8,2,0x0007,1); + } + else + { + EaCalc (0,0x0007,8,2,1); + EaRead (0, 0,8,2,0x0007,1); + ot(" str r0,[r7,#0x48] ;@ Put in USP\n\n"); + } + + OpEnd(); + + SuperEnd(op); + + return 0; +} + +// --------------------- Opcodes 0x7000+ --------------------- +// Emit a Move Quick opcode, 0111nnn0 dddddddd moveq #dd,Dn +int OpMoveq(int op) +{ + int use=0; + + use=op&0xf100; // Use same opcode for all values + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); Cycles=4; + + ot(" movs r0,r8,asl #24\n"); + ot(" and r1,r8,#0x0e00\n"); + ot(" mov r0,r0,asr #24 ;@ Sign extended Quick value\n"); + ot(" mrs r9,cpsr ;@ r9=NZ flags\n"); + ot(" str r0,[r7,r1,lsr #7] ;@ Store into Dn\n"); + ot("\n"); + + OpEnd(); + + return 0; +} + +// --------------------- Opcodes 0xc140+ --------------------- +// Emit a Exchange opcode: +// 1100ttt1 01000sss exg ds,dt +// 1100ttt1 01001sss exg as,at +// 1100ttt1 10001sss exg as,dt +int OpExg(int op) +{ + int use=0,type=0; + + type=op&0xf8; + + if (type!=0x40 && type!=0x48 && type!=0x88) return 1; // Not an exg opcode + + use=op&0xf1f8; // Use same opcode for all values + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + OpStart(op); Cycles=6; + + ot(" and r10,r8,#0x0e00 ;@ Find T register\n"); + ot(" and r11,r8,#0x000f ;@ Find S register\n"); + if (type==0x48) ot(" orr r10,r10,#0x1000 ;@ T is an address register\n"); + ot("\n"); + ot(" ldr r0,[r7,r10,lsr #7] ;@ Get T\n"); + ot(" ldr r1,[r7,r11,lsl #2] ;@ Get S\n"); + ot("\n"); + ot(" str r0,[r7,r11,lsl #2] ;@ T->S\n"); + ot(" str r1,[r7,r10,lsr #7] ;@ S->T\n"); + ot("\n"); + + OpEnd(); + + return 0; +} + +// ------------------------- movep ------------------------------- +// 0000ddd1 0z001sss +// 0000sss1 1z001ddd (to mem) +int OpMovep(int op) +{ + int ea=0; + int size=1,use=0,dir; + + use=op&0xf1f8; + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler (for all dests, srcs) + + // Get EA + ea = (op&0x0007)|0x28; + dir = (op>>7)&1; + + // Find size extension + if(op&0x0040) size=2; + + OpStart(op); + + if(dir) { // reg to mem + EaCalc(11,0x0e00,0,size); // reg number -> r11 + EaRead(11,11,0,size,0x0e00); // regval -> r11 + EaCalc(10,0x0007,ea,size); + if(size==2) { // if operand is long + ot(" mov r1,r11,lsr #24 ;@ first byte\n"); + EaWrite(10,1,ea,0,0x0007); // store first byte + ot(" add r10,r10,#2\n"); + ot(" mov r1,r11,lsr #16 ;@ second byte\n"); + EaWrite(10,1,ea,0,0x0007); // store second byte + ot(" add r10,r10,#2\n"); + } + ot(" mov r1,r11,lsr #8 ;@ first or third byte\n"); + EaWrite(10,1,ea,0,0x0007); + ot(" add r10,r10,#2\n"); + ot(" and r1,r11,#0xff\n"); + EaWrite(10,1,ea,0,0x0007); + } else { // mem to reg + EaCalc(10,0x0007,ea,size,1); + EaRead(10,11,ea,0,0x0007,1); // read first byte + ot(" add r10,r10,#2\n"); + EaRead(10,1,ea,0,0x0007,1); // read second byte + if(size==2) { // if operand is long + ot(" orr r11,r11,r1,lsr #8 ;@ second byte\n"); + ot(" add r10,r10,#2\n"); + EaRead(10,1,ea,0,0x0007,1); + ot(" orr r11,r11,r1,lsr #16 ;@ third byte\n"); + ot(" add r10,r10,#2\n"); + EaRead(10,1,ea,0,0x0007,1); + ot(" orr r0,r11,r1,lsr #24 ;@ fourth byte\n"); + } else { + ot(" orr r0,r11,r1,lsr #8 ;@ second byte\n"); + } + // store the result + EaCalc(11,0x0e00,0,size,1); // reg number -> r11 + EaWrite(11,0,0,size,0x0e00,1); + } + + Cycles=(size==2)?24:16; + OpEnd(); + + return 0; +} + +// Emit a Stop/Reset opcodes, 01001110 011100t0 imm +int OpStopReset(int op) +{ + int type=(op>>1)&1; // reset/stop + + OpStart(op); + + SuperCheck(op); + + if(type) { + // copy immediate to SR, stop the CPU and eat all remaining cycles. + ot(" ldrh r0,[r4],#2 ;@ Fetch the immediate\n"); + SuperChange(op); + OpRegToFlags(1); + + ot("\n"); + + ot(" mov r0,#1\n"); + ot(" str r0,[r7,#0x58] ;@ stopped\n"); + ot("\n"); + + ot(" mov r5,#0 ;@ eat cycles\n"); + Cycles = 4; + ot("\n"); + } + else + { + Cycles = 132; +#if USE_RESET_CALLBACK + ot(" str r4,[r7,#0x40] ;@ Save PC\n"); + ot(" mov r1,r9,lsr #28\n"); + ot(" strb r1,[r7,#0x46] ;@ Save Flags (NZCV)\n"); + ot(" str r5,[r7,#0x5c] ;@ Save Cycles\n"); + ot(" ldr r11,[r7,#0x90] ;@ ResetCallback\n"); + ot(" tst r11,r11\n"); + ot(" movne lr,pc\n"); + ot(" movne pc,r11 ;@ call ResetCallback if it is defined\n"); + ot(" ldrb r9,[r7,#0x46] ;@ r9 = Load Flags (NZCV)\n"); + ot(" ldr r5,[r7,#0x5c] ;@ Load Cycles\n"); + ot(" ldr r4,[r7,#0x40] ;@ Load PC\n"); + ot(" mov r9,r9,lsl #28\n"); +#endif + } + + OpEnd(); + SuperEnd(op); + + return 0; +} diff --git a/cpu/Cyclone/app.h b/cpu/Cyclone/app.h new file mode 100644 index 00000000..c260c2f7 --- /dev/null +++ b/cpu/Cyclone/app.h @@ -0,0 +1,100 @@ + +#include +#include +#include +#include + +#include "config.h" + +// Disa.c +#include "Disa/Disa.h" + +// Ea.cpp +extern int g_jmp_cycle_table[]; +extern int g_jsr_cycle_table[]; +extern int g_lea_cycle_table[]; +extern int g_pea_cycle_table[]; +extern int g_movem_cycle_table[]; +int Ea_add_ns(int *tab, int ea); // add nonstandard EA cycles +int EaCalc(int a,int mask,int ea,int size,int top=0); +int EaRead(int a,int v,int ea,int size,int mask,int top=0); +int EaCanRead(int ea,int size); +int EaWrite(int a,int v,int ea,int size,int mask,int top=0); +int EaCanWrite(int ea); +int EaAn(int ea); + +// Main.cpp +extern int *CyJump; // Jump table +extern int ms; // If non-zero, output in Microsoft ARMASM format +extern char *Narm[4]; // Normal ARM Extensions for operand sizes 0,1,2 +extern char *Sarm[4]; // Sign-extend ARM Extensions for operand sizes 0,1,2 +extern int Cycles; // Current cycles for opcode +void ot(const char *format, ...); +void ltorg(); +void CheckInterrupt(int op); +int MemHandler(int type,int size); + +// OpAny.cpp +int OpGetFlags(int subtract,int xbit,int sprecialz=0); +void OpUse(int op,int use); +void OpStart(int op); +void OpEnd(); +int OpBase(int op,int sepa=0); +void OpAny(int op); + +//---------------------- +// OpArith.cpp +int OpArith(int op); +int OpLea(int op); +int OpAddq(int op); +int OpArithReg(int op); +int OpMul(int op); +int OpAbcd(int op); +int OpNbcd(int op); +int OpAritha(int op); +int OpAddx(int op); +int OpCmpEor(int op); +int OpCmpm(int op); +int OpChk(int op); +int GetXBit(int subtract); + +// OpBranch.cpp +void OpPush32(); +void OpPushSr(int high); +int OpTrap(int op); +int OpLink(int op); +int OpUnlk(int op); +int Op4E70(int op); +int OpJsr(int op); +int OpBranch(int op); +int OpDbra(int op); + +// OpLogic.cpp +int OpBtstReg(int op); +int OpBtstImm(int op); +int OpNeg(int op); +int OpSwap(int op); +int OpTst(int op); +int OpExt(int op); +int OpSet(int op); +int OpAsr(int op); +int OpAsrEa(int op); +int OpTas(int op); + +// OpMove.cpp +int OpMove(int op); +int OpLea(int op); +void OpFlagsToReg(int high); +void OpRegToFlags(int high); +int OpMoveSr(int op); +int OpArithSr(int op); +int OpPea(int op); +int OpMovem(int op); +int OpMoveq(int op); +int OpMoveUsp(int op); +int OpExg(int op); +int OpMovep(int op); // notaz +int OpStopReset(int op); +void SuperCheck(int op); +void SuperEnd(int op); +void SuperChange(int op); diff --git a/cpu/Cyclone/config.h b/cpu/Cyclone/config.h new file mode 100644 index 00000000..bcea68d2 --- /dev/null +++ b/cpu/Cyclone/config.h @@ -0,0 +1,101 @@ + + +/** + * Cyclone 68000 configuration file +**/ + + +/* + * If this option is enabled, Microsoft ARMASM compatible output is generated. + * Otherwise GNU as syntax is used. + */ +#define USE_MS_SYNTAX 0 + +/* + * Enable this option if you are going to use Cyclone to emulate Genesis / + * Mega Drive system. As VDP chip in these systems had control of the bus, + * several instructions were acting differently, for example TAS did'n have + * the write-back phase. That will be emulated, if this option is enebled. + * This option also alters timing slightly. + */ +#define CYCLONE_FOR_GENESIS 1 + +/* + * This option compresses Cyclone's jumptable. Because of this the executable + * will be smaller and load slightly faster and less relocations will be needed. + * This also fixes the crash problem with 0xfffe and 0xffff opcodes. + * Warning: if you enable this, you MUST call CycloneInit() before calling + * CycloneRun(), or else it will crash. + */ +#define COMPRESS_JUMPTABLE 1 + +/* + * Cyclone keeps the 4 least significant bits of SR, PC+membase and it's cycle + * count in ARM registers instead of the context for performance reasons. If you for + * any reason need to access them in your memory handlers, enable the options below, + * otherwise disable them to improve performance. + * Warning: the PC value will not point to start of instruction (it will be middle or + * end), also updating PC is dangerous, as Cyclone may internally increment the PC + * before fetching the next instruction and continue executing at wrong location. + */ +#define MEMHANDLERS_NEED_PC 0 +#define MEMHANDLERS_NEED_FLAGS 0 +#define MEMHANDLERS_NEED_CYCLES 1 +#define MEMHANDLERS_CHANGE_PC 0 +#define MEMHANDLERS_CHANGE_FLAGS 0 +#define MEMHANDLERS_CHANGE_CYCLES 0 + +/* + * If enabled, Cyclone will call IrqCallback routine from it's context whenever it + * acknowledges an IRQ. IRQ level is not cleared automatically, do this in your + * hadler if needed. PC, flags and cycles are valid in the context and can be read. + * If disabled, it simply clears the IRQ level and continues execution. + */ +#define USE_INT_ACK_CALLBACK 1 + +/* + * Enable this if you need/change PC, flags or cycles in your IrqCallback function. + */ +#define INT_ACK_NEEDS_STUFF 0 +#define INT_ACK_CHANGES_STUFF 0 + +/* + * If enabled, ResetCallback is called from the context, whenever RESET opcode is + * encountered. All context members are valid and can be changed. + * If disabled, RESET opcode acts as an NOP. + */ +#define USE_RESET_CALLBACK 1 + +/* + * If enabled, UnrecognizedCallback is called if an invalid opcode is + * encountered. All context members are valid and can be changed. The handler + * should return zero if you want Cyclone to gererate "Illegal Instruction" + * exception after this, or nonzero if not. In the later case you shuold change + * the PC by yourself, or else Cyclone will keep executing that opcode all over + * again. + * If disabled, "Illegal Instruction" exception is generated and execution is + * continued. + */ +#define USE_UNRECOGNIZED_CALLBACK 1 + +/* + * This option will also call UnrecognizedCallback for a-line and f-line + * (0xa*** and 0xf***) opcodes the same way as described above, only appropriate + * exceptions will be generated. + */ +#define USE_AFLINE_CALLBACK 1 + +/* + * This makes Cyclone to call checkpc from it's context whenever it changes the PC + * by a large value. It takes and should return the PC value in PC+membase form. + * The flags and cycle counter are not valid in this function. + */ +#define USE_CHECKPC_CALLBACK 1 + +/* + * When this option is enabled Cyclone will do two word writes instead of one + * long write when handling MOVE.L with pre-decrementing destination, as described in + * Bart Trzynadlowski's doc (http://www.trzy.org/files/68knotes.txt). + * Enable this if you are emulating a 16 bit system. + */ +#define SPLIT_MOVEL_PD 1 diff --git a/cpu/Cyclone/epoc/crash_cyclone.bin b/cpu/Cyclone/epoc/crash_cyclone.bin new file mode 100644 index 00000000..04c6bb2f Binary files /dev/null and b/cpu/Cyclone/epoc/crash_cyclone.bin differ diff --git a/cpu/Cyclone/epoc/patchtable_symb.c b/cpu/Cyclone/epoc/patchtable_symb.c new file mode 100644 index 00000000..6d6fd26d --- /dev/null +++ b/cpu/Cyclone/epoc/patchtable_symb.c @@ -0,0 +1,150 @@ +#include +#include +#include + + +typedef struct { + unsigned long _dontcare1[4]; + char signature[4]; // 'EPOC' + unsigned long iCpu; // 0x1000 = X86, 0x2000 = ARM, 0x4000 = M*Core + unsigned long iCheckSumCode; // sum of all 32 bit words in .text + unsigned long _dontcare3[5]; + unsigned long iCodeSize; // size of code, import address table, constant data and export dir |+30 + unsigned long _dontcare4[12]; + unsigned long iCodeOffset; // file offset to code section |+64 + unsigned long _dontcare5[2]; + unsigned long iCodeRelocOffset; // relocations for code and const |+70 + unsigned long iDataRelocOffset; // relocations for data + unsigned long iPriority; // priority of this process (EPriorityHigh=450) +} E32ImageHeader; + + +typedef struct { + unsigned long iSize; // size of this relocation section + unsigned long iNumberOfRelocs; // number of relocations in this section +} E32RelocSection; + + +typedef struct { + unsigned long base; + unsigned long size; +} reloc_page_header; + + +// E32Image relocation section consists of a number of pages +// every page has 8 byte header and a number or 16bit relocation entries +// entry format: +// 0x3000 | <12bit_reloc_offset> +// +// if we have page_header.base == 0x1000 and a reloc entry 0x3110, +// it means that 32bit value at offset 0x1110 of .text section +// is relocatable + +int main(int argc, char *argv[]) +{ + FILE *f = 0; + unsigned char pattern[8] = { 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56 }; + unsigned char *buff, *p; + unsigned long patt_offset; // pattern offset in .text section + unsigned long size = 0, i, symbols, insert_pos, *handler; + unsigned short reloc_entry; + E32ImageHeader *header; + E32RelocSection *reloc_section; + reloc_page_header *reloc_page; + + if(argc != 3) { + printf("usage: %s \n\n", argv[0]); + printf("note: this was written to fix a problem caused by as v.2.9-psion-98r2 and shouldn't be used for anything else.\n", argv[0]); + return 1; + } + + f = fopen(argv[1], "rb+"); + if(!f) { + printf("%s: couldn't open %s\n", argv[0], argv[1]); + return 2; + } + + symbols = atoi(argv[2]); + + // read the file + fseek(f,0,SEEK_END); size=ftell(f); fseek(f,0,SEEK_SET); + buff = (unsigned char *) malloc(size); + fread(buff,1,size,f); + + header = (E32ImageHeader *) buff; + + if(strncmp(header->signature, "EPOC", 4) || header->iCpu != 0x2000) { + printf("%s: not a E32 executable image for ARM target.\n", argv[0]); + fclose(f); + free(buff); + return 2; + } + + // find the pattern + for(i = 0; i < size-8; i++) + if(memcmp(buff+i, pattern, 8) == 0) break; + if(i == size-8 || i < 4) { + printf("%s: failed to find the pattern.\n", argv[0]); + fclose(f); + free(buff); + return 3; + } + patt_offset = i - header->iCodeOffset; + + // find suitable reloc section + reloc_section = (E32RelocSection *) (buff + header->iCodeRelocOffset); + for(i = 0, p = buff+header->iCodeRelocOffset+8; i < reloc_section->iSize; ) { + reloc_page = (reloc_page_header *) p; + if(patt_offset - reloc_page->base >= 0 && patt_offset - reloc_page->base < 0x1000 - symbols*4) break; + i += reloc_page->size; + p += reloc_page->size; + } + + if(i >= reloc_section->iSize) { + printf("%s: suitable reloc section not found.\n", argv[0]); + fclose(f); + free(buff); + return 4; + } + + // now find the insert pos and update everything + insert_pos = p + reloc_page->size - buff; + reloc_page->size += symbols*2; + reloc_section->iSize += symbols*2; + reloc_section->iNumberOfRelocs += symbols; + header->iDataRelocOffset += symbols*2; // data reloc section is now also pushed a little + header->iPriority = 450; // let's boost our priority :) + + // replace the placeholders themselves + handler = (unsigned long *) (buff + patt_offset + header->iCodeOffset - 4); + for(i = 1; i <= symbols; i++) + *(handler+i) = *handler; + + // recalculate checksum + header->iCheckSumCode = 0; + for(i = 0, p = buff+header->iCodeOffset; i < header->iCodeSize; i+=4, p+=4) + header->iCheckSumCode += *(unsigned long *) p; + + // check for possible padding + if(!*(buff+insert_pos-1)) insert_pos -= 2; + + // write all this joy + fseek(f,0,SEEK_SET); + fwrite(buff, 1, insert_pos, f); + + // write new reloc entries + for(i = 0; i < symbols; i++) { + handler++; + reloc_entry = ((unsigned char *) handler - buff - reloc_page->base - header->iCodeOffset) | 0x3000; + fwrite(&reloc_entry, 1, 2, f); + } + + // write the remaining data + fwrite(buff+insert_pos, 1, size-insert_pos, f); + + // done at last! + fclose(f); + free(buff); + + return 0; +} diff --git a/cpu/Cyclone/epoc/patchtable_symb2.c b/cpu/Cyclone/epoc/patchtable_symb2.c new file mode 100644 index 00000000..28a16568 --- /dev/null +++ b/cpu/Cyclone/epoc/patchtable_symb2.c @@ -0,0 +1,133 @@ +#include +#include +#include + +#include + +#define symbols 2 + +int main(int argc, char *argv[]) +{ + FILE *f = 0; + unsigned char pattern[8] = { 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56 }; + unsigned char *buff, *p; + unsigned long patt_offset; // pattern offset in .text section + unsigned long size = 0, i, insert_pos, *handler;//, symbols; + unsigned short reloc_entry; + IMAGE_BASE_RELOCATION *reloc_page; + IMAGE_DOS_HEADER *dos_header; + IMAGE_FILE_HEADER *file_header; + IMAGE_SECTION_HEADER *sect_header, *relocsect_header = 0, *codesect_header = 0; + + if(argc != 2) { + printf("usage: %s \n\n", argv[0]); + printf("note: this was written to fix a problem related to Cyclone and as v.2.9-psion-98r2 and shouldn't be used for anything else. See Readme.\n", argv[0]); + return 1; + } + + f = fopen(argv[1], "rb+"); + if(!f) { + printf("%s: couldn't open %s\n", argv[0], argv[1]); + return 2; + } + + //symbols = atoi(argv[2]); + + // read the file + fseek(f,0,SEEK_END); size=ftell(f); fseek(f,0,SEEK_SET); + buff = (unsigned char *) malloc(size); + fread(buff,1,size,f); + + dos_header = (IMAGE_DOS_HEADER *) buff; + file_header= (IMAGE_FILE_HEADER *) (buff+dos_header->e_lfanew+4); + sect_header= (IMAGE_SECTION_HEADER *) (buff+dos_header->e_lfanew+4+sizeof(IMAGE_FILE_HEADER)+sizeof(IMAGE_OPTIONAL_HEADER32)); + + if(size < 0x500 || dos_header->e_magic != IMAGE_DOS_SIGNATURE || + *(DWORD *)(buff+dos_header->e_lfanew) != IMAGE_NT_SIGNATURE || file_header->Machine != 0x0A00) { + printf("%s: not a PE executable image for ARM target.\n", argv[0]); + fclose(f); + free(buff); + return 2; + } + + // scan all sections for data and reloc sections + for(i = 0; i < file_header->NumberOfSections; i++, sect_header++) { + if(strncmp(sect_header->Name, ".text", 5) == 0) codesect_header = sect_header; + else if(strncmp(sect_header->Name, ".reloc", 6) == 0) relocsect_header = sect_header; + } + + if(!codesect_header || !relocsect_header) { + printf("%s: failed to find reloc and/or data section.\n", argv[0]); + fclose(f); + free(buff); + return 3; + } + + if(relocsect_header != sect_header-1) { + printf("%s: bug: reloc section is not last, this is unexpected and not supported.\n", argv[0]); + fclose(f); + free(buff); + return 4; + } + + // find the pattern + for(i = codesect_header->PointerToRawData; i < size-8; i+=2) + if(memcmp(buff+i, pattern, 8) == 0) break; + if(i == size-8 || i < 4) { + printf("%s: failed to find the pattern.\n", argv[0]); + fclose(f); + free(buff); + return 5; + } + + // calculate pattern offset in RVA (relative virtual address) + patt_offset = i - codesect_header->PointerToRawData + codesect_header->VirtualAddress; + + // replace the placeholders themselves + handler = (unsigned long *) (buff + i - 4); + for(i = 1; i <= symbols; i++) + *(handler+i) = *handler; + + // find suitable reloc section + for(i = 0, p = buff+relocsect_header->PointerToRawData; i < relocsect_header->SizeOfRawData; ) { + reloc_page = (IMAGE_BASE_RELOCATION *) p; + if(patt_offset - reloc_page->VirtualAddress >= 0 && patt_offset - reloc_page->VirtualAddress < 0x1000 - symbols*2) break; + i += reloc_page->SizeOfBlock; + p += reloc_page->SizeOfBlock; + } + + if(i >= relocsect_header->SizeOfRawData) { + printf("%s: suitable reloc section not found.\n", argv[0]); + fclose(f); + free(buff); + return 6; + } + + // now find the insert pos and update everything + insert_pos = p + reloc_page->SizeOfBlock - buff; + reloc_page->SizeOfBlock += symbols*2; + relocsect_header->SizeOfRawData += symbols*2; + + // check for possible padding + if(!*(buff+insert_pos-1)) insert_pos -= 2; + + // write all this joy + fseek(f,0,SEEK_SET); + fwrite(buff, 1, insert_pos, f); + + // write new reloc entries + for(i = 0; i < symbols; i++) { + handler++; + reloc_entry = (unsigned short)(((unsigned char *) handler - buff) - reloc_page->VirtualAddress - codesect_header->PointerToRawData + codesect_header->VirtualAddress) | 0x3000; // quite nasty + fwrite(&reloc_entry, 1, 2, f); + } + + // write the remaining data + fwrite(buff+insert_pos, 1, size-insert_pos, f); + + // done at last! + fclose(f); + free(buff); + + return 0; +} diff --git a/cpu/Cyclone/epoc/readme.txt b/cpu/Cyclone/epoc/readme.txt new file mode 100644 index 00000000..97410f69 --- /dev/null +++ b/cpu/Cyclone/epoc/readme.txt @@ -0,0 +1,42 @@ +*update* +Use the "compress jumtable" Cyclone config.h option to fix this issue +(no patcher will be needed then). + + +There is a problem with Cyclone on symbian platform: +GNU as generates COFF object files, which allow max of 0xFFFF (65535) relocation +entries. Cyclone uses a jumptable of 0x10000 (65536, 1 for every opcode-word) +antries. When the executable is loaded, all jumptable entries must be relocated +to point to right code location. Because of this limitation, Cyclone's jumptable is +incomplete (misses 2 entries), and if M68k opcodes 0xFFFE or 0xFFFF are ever +encoundered when emulating, your emulator will crash. + +I have written a little patcher to fix that. It writes those two missing entries and +marks them as relocatable. Placeholders must not be deleted just after the jumttable +in the Cyclone source code. + +This version works with intermediate PE executable, which is used both for APPs and EXEs, +and is produced by gcc toolkit just before running petran. So it's best to insert +this in your makefile, in the rule which builds your APP/EXE, just after last 'ld' +statement, for example: + +$(EPOCTRGUREL)\PICODRIVEN.APP : $(EPOCBLDUREL)\PICODRIVEN.in $(EPOCSTATLINKUREL)\EDLL.LIB $(LIBSUREL) + ... + ld -s -e _E32Dll -u _E32Dll --dll \ + "$(EPOCBLDUREL)\PICODRIVEN.exp" \ + -Map "$(EPOCTRGUREL)\PICODRIVEN.APP.map" -o "$(EPOCBLDUREL)\PICODRIVEN.APP" \ + "$(EPOCSTATLINKUREL)\EDLL.LIB" --whole-archive "$(EPOCBLDUREL)\PICODRIVEN.in" \ + --no-whole-archive $(LIBSUREL) $(USERLDFLAGS) + -$(ERASE) "$(EPOCBLDUREL)\PICODRIVEN.exp" + + patchtable_symb2 "$(EPOCBLDUREL)\PICODRIVEN.APP" + + petran "$(EPOCBLDUREL)\PICODRIVEN.APP" "$@" \ + -nocall -uid1 0x10000079 -uid2 0x100039ce -uid3 0x1000c193 + -$(ERASE) "$(EPOCBLDUREL)\PICODRIVEN.APP" + perl -S ecopyfile.pl "$@" "PICODRIVEN.APP" + + +This is also compatible with ECompXL. + +To test if this thing worked, you can load crash_cyclone.bin in your emulator. diff --git a/cpu/Cyclone/proj/Makefile.linux b/cpu/Cyclone/proj/Makefile.linux new file mode 100644 index 00000000..912d3e94 --- /dev/null +++ b/cpu/Cyclone/proj/Makefile.linux @@ -0,0 +1,39 @@ +CFLAGS = -Wall + +ALL : cyclone.s + +cyclone.s : Cyclone.exe + ./Cyclone.exe + +Cyclone.exe : Main.o Ea.o OpAny.o OpArith.o OpBranch.o OpLogic.o Disa.o OpMove.o + $(CC) $^ -o $@ -lstdc++ + +Main.o : ../Main.cpp ../app.h + $(CC) $(CFLAGS) ../Main.cpp -c -o $@ + +Ea.o : ../Ea.cpp ../app.h + $(CC) $(CFLAGS) ../Ea.cpp -c -o $@ + +OpAny.o : ../OpAny.cpp ../app.h + $(CC) $(CFLAGS) ../OpAny.cpp -c -o $@ + +OpArith.o : ../OpArith.cpp ../app.h + $(CC) $(CFLAGS) ../OpArith.cpp -c -o $@ + +OpBranch.o : ../OpBranch.cpp ../app.h + $(CC) $(CFLAGS) ../OpBranch.cpp -c -o $@ + +OpLogic.o : ../OpLogic.cpp ../app.h + $(CC) $(CFLAGS) ../OpLogic.cpp -c -o $@ + +OpMove.o : ../OpMove.cpp ../app.h + $(CC) $(CFLAGS) ../OpMove.cpp -c -o $@ + +Disa.o : ../Disa/Disa.c ../Disa/Disa.h + $(CC) $(CFLAGS) ../Disa/Disa.c -c -o $@ + +../app.h : ../config.h + +clean : + $(RM) *.o Cyclone.exe Cyclone.s + diff --git a/cpu/Cyclone/proj/Makefile.win b/cpu/Cyclone/proj/Makefile.win new file mode 100644 index 00000000..20d489ba --- /dev/null +++ b/cpu/Cyclone/proj/Makefile.win @@ -0,0 +1,60 @@ +# Makefile for MS Visual C + +CPP=cl.exe +CPP_PROJ=/nologo /ML /W4 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" $(RC_FLAGS) /YX /FD /c + +LINK32=link.exe +LINK32_FLAGS=user32.lib /nologo /subsystem:console /machine:I386 /out:Cyclone.exe + + +ALL : cyclone.s + +cyclone.s : Cyclone.exe + Cyclone.exe + +Cyclone.exe : Main.obj Ea.obj OpAny.obj OpArith.obj OpBranch.obj OpLogic.obj Disa.obj OpMove.obj + $(LINK32) Main.obj Ea.obj OpAny.obj OpArith.obj OpBranch.obj OpLogic.obj Disa.obj OpMove.obj $(LINK32_FLAGS) + +Main.obj : ..\Main.cpp ..\app.h + $(CPP) $(CPP_PROJ) ..\Main.cpp + +Ea.obj : ..\Ea.cpp ..\app.h + $(CPP) $(CPP_PROJ) ..\Ea.cpp + +OpAny.obj : ..\OpAny.cpp ..\app.h + $(CPP) $(CPP_PROJ) ..\OpAny.cpp + +OpArith.obj : ..\OpArith.cpp ..\app.h + $(CPP) $(CPP_PROJ) ..\OpArith.cpp + +OpBranch.obj : ..\OpBranch.cpp ..\app.h + $(CPP) $(CPP_PROJ) ..\OpBranch.cpp + +OpLogic.obj : ..\OpLogic.cpp ..\app.h + $(CPP) $(CPP_PROJ) ..\OpLogic.cpp + +OpMove.obj : ..\OpMove.cpp ..\app.h + $(CPP) $(CPP_PROJ) ..\OpMove.cpp + +Disa.obj : ..\disa\Disa.c ..\disa\Disa.h + $(CPP) /nologo /ML /W4 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /c ..\disa\Disa.c + +..\app.h : ..\config.h + + +CLEAN : + -@erase "Disa.obj" + -@erase "Ea.obj" + -@erase "Main.obj" + -@erase "OpAny.obj" + -@erase "OpArith.obj" + -@erase "OpBranch.obj" + -@erase "OpLogic.obj" + -@erase "OpMove.obj" + -@erase "vc60.idb" + -@erase "vc60.pch" + -@erase "Cyclone.exe" + -@erase "Cyclone.asm" + -@erase "Cyclone.s" + -@erase "Cyclone.o" + diff --git a/cpu/Cyclone/proj/cyclone.dsp b/cpu/Cyclone/proj/cyclone.dsp new file mode 100644 index 00000000..803ad477 --- /dev/null +++ b/cpu/Cyclone/proj/cyclone.dsp @@ -0,0 +1,146 @@ +# Microsoft Developer Studio Project File - Name="cyclone" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=cyclone - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "cyclone.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "cyclone.mak" CFG="cyclone - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "cyclone - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "cyclone - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "cyclone - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x427 /d "NDEBUG" +# ADD RSC /l 0x427 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"cyclone.exe" + +!ELSEIF "$(CFG)" == "cyclone - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W4 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x427 /d "_DEBUG" +# ADD RSC /l 0x427 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"cyclone.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "cyclone - Win32 Release" +# Name "cyclone - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\disa\Disa.c +# End Source File +# Begin Source File + +SOURCE=..\Ea.cpp +# End Source File +# Begin Source File + +SOURCE=..\Main.cpp +# End Source File +# Begin Source File + +SOURCE=..\OpAny.cpp +# End Source File +# Begin Source File + +SOURCE=..\OpArith.cpp +# End Source File +# Begin Source File + +SOURCE=..\OpBranch.cpp +# End Source File +# Begin Source File + +SOURCE=..\OpLogic.cpp +# End Source File +# Begin Source File + +SOURCE=..\OpMove.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\app.h +# End Source File +# Begin Source File + +SOURCE=..\config.h +# End Source File +# Begin Source File + +SOURCE=..\Cyclone.h +# End Source File +# Begin Source File + +SOURCE=..\disa\Disa.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/cpu/DrZ80/DrZ80.txt b/cpu/DrZ80/DrZ80.txt new file mode 100644 index 00000000..b1996307 --- /dev/null +++ b/cpu/DrZ80/DrZ80.txt @@ -0,0 +1,144 @@ + +___________________________________________________________________________ + + DrZ80 (c) Copyright 2004 Reesy. Free for non-commercial use + + Reesy's e-mail: drsms_reesy(atsymbol)yahoo.co.uk + Replace (atsymbol) with @ + +___________________________________________________________________________ + + +What is it? +----------- + +DrZ80 is an emulator for the Z80 microprocessor, written in ARM 32-bit assembly. +It is aimed at chips such as ARM7 and ARM9 cores, StrongARM and XScale, to interpret Z80 +code as fast as possible. + +Flags are mapped onto ARM flags whenever possible, which speeds up the processing of an opcode. + +ARM Register Usage +------------------ + +See source code for up to date of register usage, however a summary is here: + + r0-3: Temporary registers + r3 : Pointer to Opcode Jump table + r4 : T-States remaining + r5 : Pointer to Cpu Context + r6 : Current PC + Memory Base (i.e. pointer to next opcode) + r7 : Z80 A Register in top 8 bits (i.e. 0xAA000000) + r8 : Z80 F Register (Flags) (NZCV) in lowest four bits + r9 : Z80 BC Register pair in top 16 bits (i.e. 0xBBCC0000) + r10 : Z80 DE Register pair in top 16 bits (i.e. 0xDDEE0000) + r11 : Z80 HL Register pair in top 16 bits (i.e. 0xHHLL0000) + r12 : Z80 Stack + Memory Base (i.e. pointer to current stack in host system memory) + +( note: r3,r12 are always preserved when calling external memory functions ) + +How to Compile +-------------- + +The core is targeted for the GNU compiler, so to compile just add the "DrZ80.o" object +to your makefile and that should be it. + +If you want to compile it seperately, use: as -o DrZ80.o DrZ80.s + +( note: If you want to use DrZ80 with a different compiler you will need to run + some sort of parser through the source to make the syntax of the source + compatible with your target compiler ) + + +Adding to your project +---------------------- + +To add DrZ80 to your project, add DrZ80.o, and include DrZ80.h +There is one structure: 'struct DrZ80', and three functions: DrZ80Run,DrZ80RaiseInt +and DrZ80_irq_callback. + +Don't worry if this seem very minimal - its all you need to run as many Z80s as you want. +It works with both C and C++. + +( Note: DrZ80_irq_callback is just a pointer to an irq call back function that needs + to be written by you ) + +Declaring a Memory handlers +--------------------------- + +Before you can reset or execute Z80 opcodes you must first set up a set of memory handlers. +There are 8 functions you have to set up per CPU, like this: + + unsigned int z80_rebaseSP(unsigned short new_sp); + unsigned int z80_rebasePC(unsigned short new_pc); + unsigned char z80_read8(unsigned short a); + unsigned short z80_read16(unsigned short a); + void z80_write8(unsigned char d,unsigned short a); + void z80_write16(unsigned short d,unsigned short a); + unsigned char z80_in(unsigned char p); + void z80_out(unsigned char p,unsigned char d); + +You can think of these functions representing the Z80's memory bus. +The Read and Write functions are called whenever the Z80 reads or writes memory. +The In and Out functions are called whenever the Z80 uses the I/O ports. +The z80_rebasePC and z80_rebaseSP functions are to do with creating direct memory +pointers in the host machines memory, I will explain more about this later. + +Declaring a CPU Context +----------------------- + +To declare a CPU simple declare a struct Cyclone in your code. For example to declare +two Z80s: + + struct DrZ80 MyCpu; + struct DrZ80 MyCpu2; + +It's probably a good idea to initialise the memory to zero: + + memset(&MyCpu, 0,sizeof(MyCpu)); + memset(&MyCpu2,0,sizeof(MyCpu2)); + +Next point to your memory handlers: + + MyCpu.z80_rebasePC=z80_rebasePC; + MyCpu.z80_rebaseSP=z80_rebaseSP; + MyCpu.z80_read8 =z80_read8; + MyCpu.z80_read16 =z80_read16; + MyCpu.z80_write8 =z80_write8; + MyCpu.z80_write16 =z80_write16; + MyCpu.z80_in =z80_in; + MyCpu.z80_out =z80_out; + +Now you are nearly ready to reset the Z80, except you need one more function: checkpc(). + +The z80_rebasePC() function +--------------------------- + +When DrZ80 reads opcodes, it doesn't use a memory handler every time, this would be +far too slow, instead it uses a direct pointer to ARM memory. +For example if your Rom image was at 0x3000000 and the program counter was $206, +Cyclone's program counter would be 0x3000206. + +The difference between an ARM address and a Z80 address is also stored in a variable called +'pc_membase'. In the above example it's 0x3000000. To retrieve the real PC, DrZ80 just +subtracts 'pc_membase'. + +Everytime the Z80 PC is modified, i.e. by a jump,branch intructions or by an interupt, DrZ80 +calls the z80_rebasePC function. If the PC is in a different bank, for example Ram instead +of Rom, change 'pc_membase', recalculate the new PC and return it. + +The z80_rebaseSP() function +--------------------------- + +When DrZ80 pushs/pops to the Z80 stack pointer, it doesn't use a memory handler every time. In +order to gain more speed a direct pointer to ARM memory is used. For example if your Ram was at +0x3000000 and the z80 stack pointer counter was 0xD000, DrZ80's stack pointer would be 0x300D000. + +The difference between an ARM address and a Z80 address is also stored in a variable called +'sp_membase'. In the above example it's 0x3000000. To retrieve the real SP, DrZ80 just +subtracts 'sp_membase'. + +Everytime the Z80 SP is modified ( i.e. set with a new value LD SP,NN etc ) DrZ80 +calls the z80_rebaseSP function. If the SP is in a different bank, for example Rom instead +of Ram, change 'sp_membase', recalculate the new SP and return it. + diff --git a/cpu/DrZ80/drz80.h b/cpu/DrZ80/drz80.h new file mode 100644 index 00000000..e4156104 --- /dev/null +++ b/cpu/DrZ80/drz80.h @@ -0,0 +1,77 @@ +/* + * DrZ80 Version 1.0 + * Z80 Emulator by Reesy + * Copyright 2005 Reesy + * + * This file is part of DrZ80. + * + * DrZ80 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * DrZ80 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with DrZ80; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef DRZ80_H +#define DRZ80_H + +extern int DrZ80Ver; /* Version number of library */ + +struct DrZ80 +{ + unsigned int Z80PC; /*0x00 - PC Program Counter (Memory Base + PC) */ + unsigned int Z80A; /*0x04 - A Register: 0xAA------ */ + unsigned int Z80F; /*0x08 - F Register: 0xFF------ */ + unsigned int Z80BC; /*0x0C - BC Registers: 0xBBCC---- */ + unsigned int Z80DE; /*0x10 - DE Registers: 0xDDEE---- */ + unsigned int Z80HL; /*0x14 - HL Registers: 0xHHLL---- */ + unsigned int Z80SP; /*0x18 - SP Stack Pointer (Memory Base + PC) */ + unsigned int Z80PC_BASE; /*0x1C - PC Program Counter (Memory Base) */ + unsigned int Z80SP_BASE; /*0x20 - SP Stack Pointer (Memory Base) */ + unsigned int Z80IX; /*0x24 - IX Index Register */ + unsigned int Z80IY; /*0x28 - IY Index Register */ + unsigned int Z80I; /*0x2C - I Interrupt Register */ + unsigned int Z80A2; /*0x30 - A' Register: 0xAA------ */ + unsigned int Z80F2; /*0x34 - F' Register: 0xFF------ */ + unsigned int Z80BC2; /*0x38 - B'C' Registers: 0xBBCC---- */ + unsigned int Z80DE2; /*0x3C - D'E' Registers: 0xDDEE---- */ + unsigned int Z80HL2; /*0x40 - H'L' Registers: 0xHHLL---- */ + int cycles; /*0x44 - Cycles pending to be executed yet */ + int previouspc; /*0x48 - Previous PC */ + unsigned char Z80_IRQ; /*0x4C - Set IRQ Number (must be halfword aligned) */ + unsigned char Z80IF; /*0x4D - Interrupt Flags: bit1=_IFF1, bit2=_IFF2, bit3=_HALT */ + unsigned char Z80IM; /*0x4E - Set IRQ Mode */ + unsigned char spare; /*0x4F - N/A */ + unsigned int z80irqvector; /*0x50 - Set IRQ Vector i.e. 0xFF=RST */ + void (*z80_irq_callback )(void); + void (*z80_write8 )(unsigned char d,unsigned short a); + void (*z80_write16 )(unsigned short d,unsigned short a); + unsigned char (*z80_in)(unsigned short p); + void (*z80_out )(unsigned short p,unsigned char d); + unsigned char (*z80_read8)(unsigned short a); + unsigned short (*z80_read16)(unsigned short a); + unsigned int (*z80_rebaseSP)(unsigned short new_sp); + unsigned int (*z80_rebasePC)(unsigned short new_pc); + unsigned int bla; +}; + +extern int DrZ80Run(struct DrZ80 *pcy,unsigned int cyc); + +#endif + +#ifdef __cplusplus +} /* End of extern "C" */ +#endif diff --git a/cpu/DrZ80/drz80.s b/cpu/DrZ80/drz80.s new file mode 100644 index 00000000..47606503 --- /dev/null +++ b/cpu/DrZ80/drz80.s @@ -0,0 +1,8076 @@ +;@ Reesy's Z80 Emulator Version 0.001 + +;@ (c) Copyright 2004 Reesy, All rights reserved +;@ DrZ80 is free for non-commercial use. + +;@ For commercial use, separate licencing terms must be obtained. + + .data + .align 4 + + .global DrZ80Run + .global DrZ80Ver + + .equiv INTERRUPT_MODE, 0 ;@0 = Use internal int handler, 1 = Use Mames int handler + .equiv FAST_Z80SP, 1 ;@0 = Use mem functions for stack pointer, 1 = Use direct mem pointer + .equiv UPDATE_CONTEXT, 0 + .equiv DRZ80_FOR_PICODRIVE, 1 + +.if INTERRUPT_MODE + .extern Interrupt +.endif + +.if DRZ80_FOR_PICODRIVE + .extern YM2612Read_ + .extern YM2612Read_940 + .extern PicoRead8 + .extern Pico + .extern z80_write +.endif + +DrZ80Ver: .long 0x0001 + +;@ --------------------------- Defines ---------------------------- +;@ Make sure that regs/pointers for z80pc to z80sp match up! + + opcodes .req r3 + z80_icount .req r4 + cpucontext .req r5 + z80pc .req r6 + z80a .req r7 + z80f .req r8 + z80bc .req r9 + z80de .req r10 + z80hl .req r11 + z80sp .req r12 + z80xx .req lr + + .equ z80pc_pointer, 0 ;@ 0 + .equ z80a_pointer, z80pc_pointer+4 ;@ 4 + .equ z80f_pointer, z80a_pointer+4 ;@ 8 + .equ z80bc_pointer, z80f_pointer+4 ;@ + .equ z80de_pointer, z80bc_pointer+4 + .equ z80hl_pointer, z80de_pointer+4 + .equ z80sp_pointer, z80hl_pointer+4 + .equ z80pc_base, z80sp_pointer+4 + .equ z80sp_base, z80pc_base+4 + .equ z80ix, z80sp_base+4 + .equ z80iy, z80ix+4 + .equ z80i, z80iy+4 + .equ z80a2, z80i+4 + .equ z80f2, z80a2+4 + .equ z80bc2, z80f2+4 + .equ z80de2, z80bc2+4 + .equ z80hl2, z80de2+4 + .equ cycles_pointer, z80hl2+4 + .equ previouspc, cycles_pointer+4 + .equ z80irq, previouspc+4 + .equ z80if, z80irq+1 + .equ z80im, z80if+1 + .equ z80r, z80im+1 + .equ z80irqvector, z80r+1 + .equ z80irqcallback, z80irqvector+4 + .equ z80_write8, z80irqcallback+4 + .equ z80_write16, z80_write8+4 + .equ z80_in, z80_write16+4 + .equ z80_out, z80_in+4 + .equ z80_read8, z80_out+4 + .equ z80_read16, z80_read8+4 + .equ z80_rebaseSP, z80_read16+4 + .equ z80_rebasePC, z80_rebaseSP+4 + + .equ VFlag, 0 + .equ CFlag, 1 + .equ ZFlag, 2 + .equ SFlag, 3 + .equ HFlag, 4 + .equ NFlag, 5 + .equ Flag3, 6 + .equ Flag5, 7 + + .equ Z80_CFlag, 0 + .equ Z80_NFlag, 1 + .equ Z80_VFlag, 2 + .equ Z80_Flag3, 3 + .equ Z80_HFlag, 4 + .equ Z80_Flag5, 5 + .equ Z80_ZFlag, 6 + .equ Z80_SFlag, 7 + + .equ Z80_IF1, 1<<0 + .equ Z80_IF2, 1<<1 + .equ Z80_HALT, 1<<2 + +;@--------------------------------------- + +.text + +.if DRZ80_FOR_PICODRIVE +.include "port_config.s" + +.macro YM2612Read_and_ret8 + stmfd sp!,{r3,r12,lr} +.if EXTERNAL_YM2612 + ldr r1,=PicoOpt + ldr r1,[r1] + tst r1,#0x200 + bne 10f + bl YM2612Read_ + ldmfd sp!,{r3,r12,pc} +10: + bl YM2612Read_940 +.else + bl YM2612Read_ +.endif + ldmfd sp!,{r3,r12,pc} +.endm + +.macro YM2612Read_and_ret16 + stmfd sp!,{r3,r12,lr} +.if EXTERNAL_YM2612 + ldr r0,=PicoOpt + ldr r0,[r0] + tst r0,#0x200 + bne 10f + bl YM2612Read_ + orr r0,r0,r0,lsl #8 + ldmfd sp!,{r3,r12,pc} +10: + bl YM2612Read_940 + orr r0,r0,r0,lsl #8 +.else + bl YM2612Read_ + orr r0,r0,r0,lsl #8 +.endif + ldmfd sp!,{r3,r12,pc} +.endm + +pico_z80_read8: @ addr + cmp r0,#0x2000 @ Z80 RAM + ldrlt r1,[cpucontext,#z80sp_base] + ldrltb r0,[r1,r0] + bxlt lr + + cmp r0,#0x8000 @ 68k bank + blt 1f + ldr r2,=(Pico+0x22212) + ldrh r1,[r2] + bic r0,r0,#0x3f8000 + orr r0,r0,r1,lsl #15 + ldr r1,[r2,#-0xe] @ ROM size + cmp r0,r1 + ldrlt r1,[r2,#-0x12] @ ROM + eorlt r0,r0,#1 @ our ROM is byteswapped + ldrltb r0,[r1,r0] + bxlt lr + stmfd sp!,{r3,r12,lr} + bl PicoRead8 + ldmfd sp!,{r3,r12,pc} +1: + mov r1,r0,lsr #13 + cmp r1,#2 @ YM2612 (0x4000-0x5fff) + bne 0f + and r0,r0,#3 + YM2612Read_and_ret8 +0: + cmp r0,#0x4000 + movge r0,#0xff + bxge lr + ldr r1,[cpucontext,#z80sp_base] + bic r0,r0,#0x0fe000 @ Z80 RAM (mirror) + ldrb r0,[r1,r0] + bx lr + +pico_z80_read16: @ addr + cmp r0,#0x2000 @ Z80 RAM + bge 2f + ldr r1,[cpucontext,#z80sp_base] + ldrb r0,[r1,r0]! + ldrb r1,[r1,#1] + orr r0,r0,r1,lsl #8 + bx lr + +2: + cmp r0,#0x8000 @ 68k bank + blt 1f + ldr r2,=(Pico+0x22212) + ldrh r1,[r2] + bic r0,r0,#0x1f8000 + orr r0,r0,r1,lsl #15 + ldr r1,[r2,#-0xe] @ ROM size + cmp r0,r1 + ldr r1,[r2,#-0x12] @ ROM + tst r0,#1 + eor r0,r0,#1 + ldrb r0,[r1,r0]! + ldreqb r1,[r1,#-1] + ldrneb r1,[r1,#3] @ this is due to byteswapped ROM + orr r0,r0,r1,lsl #8 + bx lr +3: + stmfd sp!,{r3-r5,r12,lr} + mov r4,r0 + bl PicoRead8 + mov r5,r0 + add r0,r4,#1 + bl PicoRead8 + orr r0,r5,r0,lsl #8 + ldmfd sp!,{r3-r5,r12,pc} +1: + mov r1,r0,lsr #13 + cmp r1,#2 @ YM2612 (0x4000-0x5fff) + bne 0f + and r0,r0,#3 + YM2612Read_and_ret16 +0: + cmp r0,#0x4000 + movge r0,#0xff + bxge lr + ldr r1,[cpucontext,#z80sp_base] + bic r0,r0,#0x0fe000 @ Z80 RAM (mirror) + ldrb r0,[r1,r0]! + ldrb r1,[r1,#1] + orr r0,r0,r1,lsl #8 + bx lr + +pico_z80_write8: @ data, addr + cmp r1,#0x4000 + bge 1f + ldr r2,[cpucontext,#z80sp_base] + bic r1,r1,#0x0fe000 @ Z80 RAM + strb r0,[r2,r1] + bx lr +1: + stmfd sp!,{r3,r12,lr} + bl z80_write + ldmfd sp!,{r3,r12,pc} + +pico_z80_write16: @ data, addr + cmp r1,#0x4000 + bge 1f + ldr r2,[cpucontext,#z80sp_base] + bic r1,r1,#0x0fe000 @ Z80 RAM + strb r0,[r2,r1]! + mov r0,r0,lsr #8 + strb r0,[r2,#1] + bx lr +1: + stmfd sp!,{r3-r5,r12,lr} + mov r4,r0 + mov r5,r1 + bl z80_write + mov r0,r4,lsr #8 + add r1,r5,#1 + bl z80_write + ldmfd sp!,{r3-r5,r12,pc} + + .pool +.endif + +.macro fetch cycs + subs z80_icount,z80_icount,#\cycs +.if UPDATE_CONTEXT + str z80pc,[cpucontext,#z80pc_pointer] + str z80_icount,[cpucontext,#cycles_pointer] + ldr r1,[cpucontext,#z80pc_base] + sub r2,z80pc,r1 + str r2,[cpucontext,#previouspc] +.endif + ldrplb r0,[z80pc],#1 + ldrpl pc,[opcodes,r0, lsl #2] + bmi z80_execute_end +.endm + +.macro eatcycles cycs + sub z80_icount,z80_icount,#\cycs +.if UPDATE_CONTEXT + str z80_icount,[cpucontext,#cycles_pointer] +.endif +.endm + +.macro readmem8 +.if UPDATE_CONTEXT + str z80pc,[cpucontext,#z80pc_pointer] +.endif +.if DRZ80_FOR_PICODRIVE + bl pico_z80_read8 +.else + stmfd sp!,{r3,r12} + mov lr,pc + ldr pc,[cpucontext,#z80_read8] ;@ r0 = addr - data returned in r0 + ldmfd sp!,{r3,r12} +.endif +.endm + +.macro readmem8HL + mov r0,z80hl, lsr #16 + readmem8 +.endm + +.macro readmem16 +.if UPDATE_CONTEXT + str z80pc,[cpucontext,#z80pc_pointer] +.endif +.if DRZ80_FOR_PICODRIVE + bl pico_z80_read16 +.else + stmfd sp!,{r3,r12} + mov lr,pc + ldr pc,[cpucontext,#z80_read16] + ldmfd sp!,{r3,r12} +.endif +.endm + +.macro writemem8 +.if UPDATE_CONTEXT + str z80pc,[cpucontext,#z80pc_pointer] +.endif +.if DRZ80_FOR_PICODRIVE + bl pico_z80_write8 +.else + stmfd sp!,{r3,r12} + mov lr,pc + ldr pc,[cpucontext,#z80_write8] ;@ r0=data r1=addr + ldmfd sp!,{r3,r12} +.endif +.endm + +.macro writemem8DE + mov r1,z80de, lsr #16 + writemem8 +.endm + +.macro writemem8HL + mov r1,z80hl, lsr #16 + writemem8 +.endm + +.macro writemem16 +.if UPDATE_CONTEXT + str z80pc,[cpucontext,#z80pc_pointer] +.endif +.if DRZ80_FOR_PICODRIVE + bl pico_z80_write16 +.else + stmfd sp!,{r3,r12} + mov lr,pc + ldr pc,[cpucontext,#z80_write16] ;@ r0=data r1=addr + ldmfd sp!,{r3,r12} +.endif +.endm + +.macro copymem8HL_DE +.if UPDATE_CONTEXT + str z80pc,[cpucontext,#z80pc_pointer] +.endif + mov r0,z80hl, lsr #16 +.if DRZ80_FOR_PICODRIVE + bl pico_z80_read8 +.else + stmfd sp!,{r3,r12} + mov lr,pc + ldr pc,[cpucontext,#z80_read8] ;@ r0 = addr - data returned in r0 +.endif +.if UPDATE_CONTEXT + str z80pc,[cpucontext,#z80pc_pointer] +.endif + mov r1,z80de, lsr #16 +.if DRZ80_FOR_PICODRIVE + bl pico_z80_write8 +.else + mov lr,pc + ldr pc,[cpucontext,#z80_write8] ;@ r0=data r1=addr + ldmfd sp!,{r3,r12} +.endif +.endm +;@--------------------------------------- + +.macro rebasepc +.if UPDATE_CONTEXT + str z80pc,[cpucontext,#z80pc_pointer] +.endif +.if DRZ80_FOR_PICODRIVE + bic r0,r0,#0xfe000 + ldr r1,[cpucontext,#z80pc_base] + add z80pc,r1,r0 +.else + stmfd sp!,{r3,r12} + mov lr,pc + ldr pc,[cpucontext,#z80_rebasePC] ;@ r0=new pc - external function sets z80pc_base and returns new z80pc in r0 + ldmfd sp!,{r3,r12} + mov z80pc,r0 +.endif +.endm + +.macro rebasesp +.if UPDATE_CONTEXT + str z80pc,[cpucontext,#z80pc_pointer] +.endif +.if DRZ80_FOR_PICODRIVE + bic r0,r0,#0xfe000 + ldr r1,[cpucontext,#z80sp_base] + add r0,r1,r0 +.else + stmfd sp!,{r3,r12} + mov lr,pc + ldr pc,[cpucontext,#z80_rebaseSP] ;@ external function must rebase sp + ldmfd sp!,{r3,r12} +.endif +.endm +;@---------------------------------------------------------------------------- + +.macro opADC + movs z80f,z80f,lsr#2 ;@ get C + subcs r0,r0,#0x100 + eor z80f,r0,z80a,lsr#24 ;@ prepare for check of half carry + adcs z80a,z80a,r0,ror#8 + mrs r0,cpsr ;@ S,Z,V&C + eor z80f,z80f,z80a,lsr#24 + and z80f,z80f,#1< r1 +.if FAST_Z80SP +.if DRZ80_FOR_PICODRIVE + @ notaz: try to protect against stack overflows, which tend to happen in Picodrive because of poor timing + ldr r0,[cpucontext,#z80sp_base] + cmp z80sp,r0 + addle z80sp,z80sp,#0x2000 + mov r1,\reg, lsr #8 + strb r1,[z80sp,#-1]! + cmp z80sp,r0 + addle z80sp,z80sp,#0x2000 + strb \reg,[z80sp,#-1]! +.else + mov r1,\reg, lsr #8 + strb r1,[z80sp,#-1]! + strb \reg,[z80sp,#-1]! +.endif +.else + mov r0,\reg + sub z80sp,z80sp,#2 + mov r1,z80sp + writemem16 +.endif +.endm + +.macro opPUSHreg reg +.if FAST_Z80SP +.if DRZ80_FOR_PICODRIVE + ldr r0,[cpucontext,#z80sp_base] + cmp z80sp,r0 + addle z80sp,z80sp,#0x2000 + mov r1,\reg, lsr #24 + strb r1,[z80sp,#-1]! + cmp z80sp,r0 + addle z80sp,z80sp,#0x2000 + mov r1,\reg, lsr #16 + strb r1,[z80sp,#-1]! +.else + mov r1,\reg, lsr #24 + strb r1,[z80sp,#-1]! + mov r1,\reg, lsr #16 + strb r1,[z80sp,#-1]! +.endif +.else + mov r0,\reg,lsr #16 + sub z80sp,z80sp,#2 + mov r1,z80sp + writemem16 +.endif +.endm +;@--------------------------------------- + +.macro opRESmemHL bit +.if DRZ80_FOR_PICODRIVE + mov r0,z80hl, lsr #16 + bl pico_z80_read8 + bic r0,r0,#1<<\bit + mov r1,z80hl, lsr #16 + bl pico_z80_write8 +.else + mov r0,z80hl, lsr #16 + stmfd sp!,{r3,r12} + mov lr,pc + ldr pc,[cpucontext,#z80_read8] ;@ r0 = addr - data returned in r0 + bic r0,r0,#1<<\bit + mov r1,z80hl, lsr #16 + mov lr,pc + ldr pc,[cpucontext,#z80_write8] ;@ r0=data r1=addr + ldmfd sp!,{r3,r12} +.endif + fetch 15 +.endm +;@--------------------------------------- + +.macro opRESmem bit +.if DRZ80_FOR_PICODRIVE + stmfd sp!,{r0} ;@ save addr as well + bl pico_z80_read8 + bic r0,r0,#1<<\bit + ldmfd sp!,{r1} ;@ restore addr into r1 + bl pico_z80_write8 +.else + stmfd sp!,{r3,r12} + stmfd sp!,{r0} ;@ save addr as well + mov lr,pc + ldr pc,[cpucontext,#z80_read8] ;@ r0=addr - data returned in r0 + bic r0,r0,#1<<\bit + ldmfd sp!,{r1} ;@ restore addr into r1 + mov lr,pc + ldr pc,[cpucontext,#z80_write8] ;@ r0=data r1=addr + ldmfd sp!,{r3,r12} +.endif + fetch 23 +.endm +;@--------------------------------------- + +.macro opRL reg1 reg2 shift + movs \reg1,\reg2,lsl \shift + tst z80f,#1< 0xFF + writemem8HL + add z80hl,z80hl,#1<<16 + sub z80bc,z80bc,#1<<24 + tst z80bc,#0xFF<<24 + orrmi z80f,z80f,#1< 0xFF + sub z80bc,z80bc,#1<<24 + tst z80bc,#0xFF<<24 + orrmi z80f,z80f,#1< 0xFF + writemem8HL + sub z80hl,z80hl,#1<<16 + sub z80bc,z80bc,#1<<24 + tst z80bc,#0xFF<<24 + orrmi z80f,z80f,#1< 0xFF + sub z80bc,z80bc,#1<<24 + tst z80bc,#0xFF<<24 + orrmi z80f,z80f,#1< 0xFF + writemem8HL + add z80hl,z80hl,#1<<16 + sub z80bc,z80bc,#1<<24 + tst z80bc,#0xFF<<24 + orrmi z80f,z80f,#1< 0xFF + sub z80bc,z80bc,#1<<24 + tst z80bc,#0xFF<<24 + orrmi z80f,z80f,#1< 0xFF + writemem8HL + sub z80hl,z80hl,#1<<16 + sub z80bc,z80bc,#1<<24 + tst z80bc,#0xFF<<24 + orrmi z80f,z80f,#1< 0xFF + sub z80bc,z80bc,#1<<24 + tst z80bc,#0xFF<<24 + orrmi z80f,z80f,#1< add reg,reg + * or ecx,ecx:jz -> jecxz + * 22.08.99 DEO - SBCD/ABCD sets N flag same as carry + * 19.10.99 MJC - Change DOS memory routines + * Change DOS Clobber flags (ESI no longer safe) + * Save EAX around memory write where needed + * bit commands optimised + * 25.10.99 MJC - Was keeping masked register on read/write + * if register was preserved over call + * ESI assumed 'safe' again + * 25.10.99 MJC - Bank ID moved to CPU context + * 03.11.99 KENJO - VC++6.0 seems not to preserve EDI. Fixed "ABCD -(A0), -(A0)" crash / "roxr (A0)"-type shift crash + * 13.11.99 KENJO - Fixed "NABC" + * Now Win32 uses FASTCALL type call for interrupt callback + * 09.02.00 MJC - Check CPU type before allowing 68010/68020 instructions + * remove routines for 5 non existant opcodes + * 05.03.00 MJC - not command decrement A7 by 1 for bytes + * 10.03.00 MJC - as did btst,cmpm and nbcd + * 22.03.00 MJC - Divide by zero should not decrement PC by 2 before push + * Move memory banking into exception routine + * 14.04.00 Dave - BTST missing Opcode + * ASL.L > 31 shift + * 20.04.00 MJC - TST.B Also missing A7 specific routine + * - Extra Define A7ROUTINE to switch between having seperate + * routines for +-(A7) address modes. + * 24.06.00 MJC - ADDX/SUBX +-(A7) routines added. + * TAS should not touch X flag + * LSL/LSR EA not clearing V flag + * CHK not all opcodes in jump table + * Add define to mask status register + * 04.07.00 MJC - Keep high byte of Program Counter on Bxx and Jxx + * Fix flag handling on NEGX + * Really fix ADDX/SUBX +-(A7) + * PC could be set wrong after CHK.W instruction + * DIVS/DIVU always clear C flag + * ABCD/SBCD missing +-(A7) Routine + * TAS missing +-(A7) Routine + * Bitwise Static missing +-(A7) Routine + * CMPM missing +-(A7) Routine + * 30.09.00 DEO - added mull, divl, bfextu + * added '020 addressing modes + * fixed $6xff branching + * 23.01.01 MJC - Spits out seperate code for 68000 & 68020 + * allows seperate optimising! + * 17.02.01 MJC - Support for encrypted PC relative fetch calls + * 11.03.01 GUTI - change some cmp reg,0 and or reg,reg with test + * 13.03.01 MJC - Single Icount for Asm & C cores + * 16.05.01 ASG - use push/pop around mem calls instead of store to safe_REG + * optimized a bit the 020 extension word decoder + * removed lots of unnecessary code in branches + *--------------------------------------------------------------- + * Known Problems / Bugs + * + * 68000 + * None - Let us know if you find any! + * + * 68010 + * Instructions that are supervisor only as per 68000 spec. + * move address space not implemented. + * + * 68020 + * only long Bcc instruction implemented. + *--------------------------------------------------------------- + * Notes + * + * STALLCHECK should be defined for Pentium Class + * undefined for P2/Celerons + * + * ALIGNMENT is normally 4, but seems faster on my P2 as 0 ! + * + *--------------------------------------------------------------- + * + * Future Changes + * + * 68020 instructions to be completed + * assembler memory routines + + * + * and anything else that takes our fancy! + *---------------------------------------------------------------*/ + +/* Specials - Switch what program allows/disallows */ + +#undef STALLCHECK /* Affects fetching of Opcode */ +#undef SAVEPPC /* Save Previous PC */ // dave +#define ENCRYPTED /* PC relative = decrypted */ +#define ASMBANK /* Memory banking algorithm to use */ // dave +#define A7ROUTINE /* Define to use separate routines for -(a7)/(a7)+ */ +#define ALIGNMENT 4 /* Alignment to use for branches */ +#undef MASKCCR /* Mask the status register to filter out unused bits */ +#define KEEPHIGHPC /* Keep or Ignore bits 24-31 */ +#define QUICKZERO /* selects XOR r,r or MOV r,0 */ + +#include +#include +#include +#include + +/* New Disassembler */ + +char * codebuf; +int DisOp; + +#define cpu_readmem24bew(addr) (0) +#define cpu_readmem24bew_word(addr) (DisOp) + +#define MEMORY_H /* so memory.h will not be included... */ +/* +#include "d68k.c" +*/ +#undef MEMORY_H + +#undef cpu_readmem24bew +#undef cpu_readmem24bew_word + +#include "cpuintrf.h" + +/* + * Defines used by Program + * + */ + +#define VERSION "0.30" + +#define TRUE -1 +#define FALSE 0 + +#define EAX 0 +#define EBX 1 +#define ECX 2 +#define EDX 3 +#define ESI 4 +#define PC ESI +#define EDI 5 +#define EBP 6 + + +#define NORMAL 0 +#define PCREL 1 + +/* Register Location Offsets */ + +#define ICOUNT "_m68k_ICount" + +#define REG_DAT "R_D0" +#define REG_DAT_EBX "[R_D0+ebx*4]" +#define REG_ADD "R_A0" +#define REG_A7 "R_A7" +#define REG_USP "R_USP" +#define REG_ISP "R_ISP" +#define REG_SRH "R_SR_H" +#define REG_CCR "R_CCR" +#define REG_X "R_XC" +#define REG_PC "R_PC" +#define REG_IRQ "R_IRQ" +#define REG_S "R_SR" +#define REG_IRQ_CALLBACK "R_IRQ_CALLBACK" +#define REG_RESET_CALLBACK "R_RESET_CALLBACK" + + +/* 68010 Regs */ + +#define REG_VBR "R_VBR" +#define REG_SFC "R_SFC" +#define REG_DFC "R_DFC" + +#define FASTCALL_FIRST_REG "ecx" +#define FASTCALL_SECOND_REG "edx" + + + +/* + * Global Variables + * + */ + +FILE *fp = NULL; + +char *comptab = NULL; +char *CPUtype = NULL; + +int CPU = 0; +int FlagProcess = 0; +int CheckInterrupt = 0; +int ExternalIO = 0; +int Opcount = 0; +int TimingCycles = 0; +int AddEACycles = 0; +int AccessType = NORMAL; +int ppro = 0; + + + +/* External register preservation */ + +#ifdef DOS + +/* Registers normally saved around C routines anyway */ +/* GCC 2.9.1 (dos) seems to preserve EBX,EDI and EBP */ +static char SavedRegs[] = "-B--SDB"; + +#elif defined(WIN32) + +/* visual C++, win32, says it preserves ebx, edi, esi, and ebp */ +/* ---------- VC++ deosn't preserve EDI? (Kenjo, 110399) ---------- */ +static char SavedRegs[] = "-B--S-B"; + +#else + +/* Assume nothing preserved */ +static char SavedRegs[] = "-------"; + +#endif + + + +/* Jump Table */ + +int OpcodeArray[65536]; + +/* Lookup Arrays */ + +static char* regnameslong[] = +{ "EAX","EBX","ECX","EDX","ESI","EDI","EBP"}; + +static char* regnamesword[] = +{ "AX","BX","CX","DX", "SI", "DI", "BP"}; + +static char* regnamesshort[] = +{ "AL","BL","CL","DL"}; + + + +/*********************************/ +/* Conversion / Utility Routines */ +/*********************************/ + +/* Convert EA to Address Mode Number + * + * 0 Dn + * 1 An + * 2 (An) + * 3 (An)+ + * 4 -(An) + * 5 x(An) + * 6 x(An,xr.s) + * 7 x.w + * 8 x.l + * 9 x(PC) + * 10 x(PC,xr.s) + * 11 #x,SR,CCR Read = Immediate, Write = SR or CCR + * in order to read SR to AX, use READCCR + * 12-15 INVALID + * + * 19 (A7)+ + * 20 -(A7) + * + */ + +int EAtoAMN(int EA, int Way) +{ + int Work; + + if (Way) + { + Work = (EA & 0x7); + + if (Work == 7) Work += ((EA & 0x38) >> 3); + + if (((Work == 3) || (Work == 4)) && (((EA & 0x38) >> 3) == 7)) + { + Work += 16; + } + } + else + { + Work = (EA & 0x38) >> 3; + + if (Work == 7) Work += (EA & 7); + + if (((Work == 3) || (Work == 4)) && ((EA & 7) == 7)) + { + Work += 16; + } + } + + return Work; +} + +/* + * Generate Main or Sub label + */ + +char *GenerateLabel(int ID,int Type) +{ + static int LabID,LabNum; +/* + static char disasm[80]; + char *dis = disasm; +*/ + if (Type == 0) + { + CheckInterrupt=0; /* No need to check for Interrupts */ + ExternalIO=0; /* Not left Assembler Yet */ + TimingCycles=0; /* No timing info for this command */ + AddEACycles=1; /* default to add in EA timing */ + Opcount++; /* for screen display */ + + DisOp = ID; +/* + m68k_disassemble(dis,0); + sprintf(codebuf, "OP%d_%4.4x:\t\t\t\t; %s", CPU,ID, dis); +*/ + sprintf(codebuf, "OP%d_%4.4x:\t\t\t\t;", CPU,ID); + + LabID = ID; + LabNum = 0; + } + else + { + LabNum++; + sprintf(codebuf, "OP%d_%4.4x_%1x", CPU,LabID, LabNum); + } + + return codebuf; +} + +/* + * Generate Alignment Line + */ + +void Align(void) +{ + fprintf(fp, "\t\t ALIGN %d\n\n",ALIGNMENT); +} + +/* + * Copy X into Carry + * + * There are several ways this could be done, this allows + * us to easily change the way we are doing it! + */ + +void CopyX(void) +{ + /* Copy bit 0 from X flag store into Carry */ + + fprintf(fp, "\t\t bt dword [%s],0\n",REG_X); +} + +/* + * Immediate 3 bit data + * + * 0=8, anything else is itself + * + * Again, several ways to achieve this + * + * ECX contains data as 3 lowest bits + * + */ + +void ClearRegister(int regno) +{ +#ifdef QUICKZERO + fprintf(fp, "\t\t mov %s,0\n",regnameslong[regno]); +#else + fprintf(fp, "\t\t xor %s,%s\n",regnameslong[regno],regnameslong[regno]); +#endif +} + +void Immediate8(void) +{ + /* This takes 3 cycles, 5 bytes, no memory reads */ + + fprintf(fp, "\t\t dec ecx ; Move range down\n"); + fprintf(fp, "\t\t and ecx,byte 7 ; Mask out lower bits\n"); + fprintf(fp, "\t\t inc ecx ; correct range\n"); + + + /* This takes 2 cycles, 10 bytes but has a memory read */ + /* I don't know timing for the mov command - assumed 1 */ + +#if 0 + fprintf(fp, "\t\t and ecx,byte 7\n"); + fprintf(fp, "\t\t mov ecx,[ImmTable+ECX*4]\n"); +#endif +} + +/* + * This will check for bank changes before + * resorting to calling the C bank select code + * + * Most of the time it does not change! + * + */ + +/* forward used by MemoryBanking */ +void Exception(int Number, int BaseCode) ; + +void MemoryBanking(int BaseCode) +{ + /* check for odd address */ + fprintf(fp, "\t\t test esi, dword 1\n"); + fprintf(fp, "\t\t jz near OP%d_%5.5x\n",CPU,BaseCode); + + /* trying to run at an odd address */ + Exception(3,BaseCode); + + /* Keep Whole PC */ + + fprintf(fp, "OP%d_%5.5x:\n",CPU,BaseCode); + +/* ASG - always call to the changepc subroutine now, since the number of */ +/* bits varies based on the memory model */ +#ifdef KEEPHIGHPC + fprintf(fp, "\t\t mov [FullPC],ESI\n"); +#endif + + /* Mask to n bits */ + fprintf(fp, "\t\t and esi,[_mem_amask]\n"); + +#if 0 +#ifdef KEEPHIGHPC + fprintf(fp, "\t\t mov [FullPC],ESI\n"); +#endif + + /* Mask to 24 bits */ +// fprintf(fp, "\t\t and esi,0ffffffh\n"); + +#ifdef ASMBANK + /* Assembler bank switch - 64k granularity */ + + fprintf(fp, "\t\t mov eax,esi\n"); + fprintf(fp, "\t\t shr eax,16\n"); + fprintf(fp, "\t\t cmp [asmbank],eax\n"); + fprintf(fp, "\t\t je OP%d_%5.5x_Bank\n",CPU,BaseCode); + + fprintf(fp, "\t\t mov [asmbank],eax\n"); +#else + /* This code is same as macro used by C core */ + + fprintf(fp, "\t\t mov ecx,esi\n"); + fprintf(fp, "\t\t mov ebx,[_cur_mrhard]\n"); + fprintf(fp, "\t\t shr ecx,9\n"); + fprintf(fp, "\t\t mov al,byte [_opcode_entry]\n"); + fprintf(fp, "\t\t cmp al,[ecx+ebx]\n"); + fprintf(fp, "\t\t je OP%d_%5.5x_Bank\n",CPU,BaseCode); +#endif +#endif + + /* Call Banking Routine */ + + if (SavedRegs[ESI] == '-') + { + fprintf(fp, "\t\t mov [%s],ESI\n",REG_PC); + } + + if (SavedRegs[EDX] == '-') + { + fprintf(fp, "\t\t mov [%s],edx\n",REG_CCR); + } + +#ifdef FASTCALL + fprintf(fp, "\t\t mov %s,esi\n",FASTCALL_FIRST_REG); +#else + fprintf(fp, "\t\t push esi\n"); +#endif + + fprintf(fp, "\t\t call [_a68k_memory_intf+28]\n"); + +#ifndef FASTCALL + fprintf(fp, "\t\t lea esp,[esp+4]\n"); +#endif + + if (SavedRegs[EDX] == '-') + { + fprintf(fp, "\t\t mov edx,[%s]\n",REG_CCR); + } + + if (SavedRegs[ESI] == '-') + { + fprintf(fp, "\t\t mov esi,[%s]\n",REG_PC); + } + + /* Update our copy */ + + fprintf(fp, "\t\t mov ebp,dword [_OP_ROM]\n"); + + fprintf(fp, "OP%d_%5.5x_Bank:\n",CPU,BaseCode); +} + +/* + * Update Previous PC value + * + */ + +void SavePreviousPC(void) +{ +#ifdef SAVEPPC + fprintf(fp, "\t\t mov [R_PPC],esi\t\t\t ; Keep Previous PC\n"); +#endif +} + +/* + * Complete Opcode handling + * + * Any tidying up, end code + * + */ + +void Completed(void) +{ + + /* Flag Processing to be finished off ? */ + + AccessType = NORMAL; + + /* Use assembler timing routines */ + + if (TimingCycles != 0) + { + if (TimingCycles > 127) + fprintf(fp, "\t\t sub dword [%s],%d\n",ICOUNT,TimingCycles); + else + { + if (TimingCycles != -1) + fprintf(fp, "\t\t sub dword [%s],byte %d\n",ICOUNT,TimingCycles); + } + + if (FlagProcess > 0) + fprintf(fp, "\t\t pop EDX\n"); + if (FlagProcess == 2) + fprintf(fp, "\t\t mov [%s],edx\n",REG_X); + + fprintf(fp, "\t\t js near MainExit\n\n"); + } + else + { + fprintf(fp, "\t\t test dword [%s],0xffffffff\n",ICOUNT); + + if (FlagProcess > 0) + fprintf(fp, "\t\t pop EDX\n"); + if (FlagProcess == 2) + fprintf(fp, "\t\t mov [%s],edx\n",REG_X); + + fprintf(fp, "\t\t jle near MainExit\n\n"); + } + FlagProcess = 0; + +#ifdef MAME_DEBUG + + /* Check for Debug Active */ + + fprintf(fp, "\n\t\t test byte [_mame_debug],byte 0xff\n"); + fprintf(fp, "\t\t jnz near MainExit\n\n"); + +#endif + + if (CheckInterrupt) + { + fprintf(fp,"; Check for Interrupt waiting\n\n"); + fprintf(fp,"\t\t test byte [%s],07H\n",REG_IRQ); + fprintf(fp,"\t\t jne near interrupt\n\n"); + } + + if(CPU==2) + { + /* 32 bit memory version */ + fprintf(fp, "\t\t mov eax,2\n"); /* ASG */ + fprintf(fp, "\t\t xor eax,esi\n"); /* ASG */ + +#ifdef STALLCHECK + ClearRegister(ECX); + fprintf(fp, "\t\t mov cx,[eax+ebp]\n"); +#else + fprintf(fp, "\t\t movzx ecx,word [eax+ebp]\n"); +#endif + } + else + { + /* 16 bit memory */ +#ifdef STALLCHECK + ClearRegister(ECX); + fprintf(fp, "\t\t mov cx,[esi+ebp]\n"); +#else + fprintf(fp, "\t\t movzx ecx,word [esi+ebp]\n"); +#endif + } + + fprintf(fp, "\t\t jmp [%s_OPCODETABLE+ecx*4]\n\n", CPUtype); +} + +/* + * Flag Routines + * + * Size = B,W or L + * Sreg = Register to Test + * TestReg = Need to test register (false if flags already set up) + * SetX = if C needs to be copied across to X register + * Delayed = Delays final processing to end of routine (Completed()) + * + */ + +void TestFlags(char Size,int Sreg) +{ + char* Regname=""; + + switch (Size) + { + case 66: + Regname = regnamesshort[Sreg]; + break; + + case 87: + Regname = regnamesword[Sreg]; + break; + + case 76: + Regname = regnameslong[Sreg]; + break; + } + + /* Test does not update register */ + /* so cannot generate partial stall */ + + fprintf(fp, "\t\t test %s,%s\n",Regname,Regname); +} + +void SetFlags(char Size,int Sreg,int Testreg,int SetX,int Delayed) +{ + if (Testreg) TestFlags(Size,Sreg); + + fprintf(fp, "\t\t pushfd\n"); + + if (Delayed) + { + /* Rest of code done by Completed routine */ + + if (SetX) FlagProcess = 2; + else FlagProcess = 1; + } + else + { + fprintf(fp, "\t\t pop EDX\n"); + + if (SetX) fprintf(fp, "\t\t mov [%s],edx\n",REG_X); + } +} + +/******************/ +/* Check CPU Type */ +/******************/ + +void CheckCPUtype(int Minimum) +{ + if(CPU==2) + { + /* Only check for > 020 */ + + if(Minimum>2) + { + fprintf(fp, "\t\t mov eax,[CPUversion]\n"); + + fprintf(fp, "\t\t cmp al,%d\n",Minimum); + fprintf(fp, "\t\t jb near ILLEGAL\n\n"); + } + } + else + { + fprintf(fp, "\t\t mov eax,[CPUversion]\n"); + + if (Minimum == 1) + { + fprintf(fp, "\t\t test eax,eax\n"); + fprintf(fp, "\t\t jz near ILLEGAL\n\n"); + } + else + { + fprintf(fp, "\t\t cmp al,%d\n",Minimum); + fprintf(fp, "\t\t jb near ILLEGAL\n\n"); + } + } +} + +/************************************/ +/* Pre-increment and Post-Decrement */ +/************************************/ + +void IncrementEDI(int Size,int Rreg) +{ + switch (Size) + { + case 66: + +#ifdef A7ROUTINE + + /* Always does Byte Increment - A7 uses special routine */ + + fprintf(fp, "\t\t inc dword [%s+%s*4]\n",REG_ADD,regnameslong[Rreg]); + +#else + + /* A7 uses same routines, so inc by 2 if A7 */ + + fprintf(fp, "\t\t cmp %s,7\n",regnamesshort[Rreg]); + fprintf(fp, "\t\t cmc\n"); + fprintf(fp, "\t\t adc dword [%s+%s*4],byte 1\n",REG_ADD,regnameslong[Rreg]); + +#endif + break; + + case 87: + + fprintf(fp, "\t\t add dword [%s+%s*4],byte 2\n",REG_ADD,regnameslong[Rreg]); + break; + + case 76: + + fprintf(fp, "\t\t add dword [%s+%s*4],byte 4\n",REG_ADD,regnameslong[Rreg]); + break; + } +} + +void DecrementEDI(int Size,int Rreg) +{ + switch (Size) + { + case 66: + +#ifdef A7ROUTINE + + /* Always does Byte Increment - A7 uses special routine */ + + fprintf(fp, "\t\t dec EDI\n"); + +#else + + /* A7 uses same routines, so dec by 2 if A7 */ + + fprintf(fp, "\t\t cmp %s,7\n",regnamesshort[Rreg]); + fprintf(fp, "\t\t cmc\n"); + fprintf(fp, "\t\t sbb dword edi,byte 1\n"); + +#endif + break; + + case 87: + + fprintf(fp, "\t\t sub EDI,byte 2\n"); + break; + + case 76: + fprintf(fp, "\t\t sub EDI,byte 4\n"); + break; + } +} + +/* + * Generate an exception + * + * if Number = -1 then assume value in AL already + * code must continue running afterwards + * + */ + +void Exception(int Number, int BaseCode) +{ + if (Number > -1) + { + fprintf(fp, "\t\t sub esi,byte 2\n"); + fprintf(fp, "\t\t mov al,%d\n",Number); + } + + fprintf(fp, "\t\t call Exception\n\n"); + + if (Number > -1) + Completed(); +} + + +/********************/ +/* Address Routines */ +/********************/ + +/* + * Decode Intel flags into AX as SR register + * + * Wreg = spare register to use (must not be EAX or EDX) + */ + +void ReadCCR(char Size, int Wreg) +{ + fprintf(fp, "\t\t mov eax,edx\n"); + fprintf(fp, "\t\t mov ah,byte [%s]\n",REG_X); + + /* Partial stall so .. switch to new bit of processing */ + + fprintf(fp, "\t\t mov %s,edx\n",regnameslong[Wreg]); + fprintf(fp, "\t\t and %s,byte 1\n",regnameslong[Wreg]); + + /* Finish what we started */ + + fprintf(fp, "\t\t shr eax,4\n"); + fprintf(fp, "\t\t and eax,byte 01Ch \t\t; X, N & Z\n\n"); + + /* and complete second task */ + + fprintf(fp, "\t\t or eax,%s \t\t\t\t; C\n\n",regnameslong[Wreg]); + + /* and Finally */ + + fprintf(fp, "\t\t mov %s,edx\n",regnameslong[Wreg]); + fprintf(fp, "\t\t shr %s,10\n",regnameslong[Wreg]); + fprintf(fp, "\t\t and %s,byte 2\n",regnameslong[Wreg]); + fprintf(fp, "\t\t or eax,%s\t\t\t\t; O\n\n",regnameslong[Wreg]); + + if (Size == 'W') + { + fprintf(fp, "\t\t mov ah,byte [%s] \t; T, S & I\n\n",REG_SRH); + +#ifdef MASKCCR + fprintf(fp, "\t\t and ax,0A71Fh\t; Mask unused bits\n"); +#endif + } +} + +/* + * Convert SR into Intel flags + * + * Also handles change of mode from Supervisor to User + * + * n.b. This is also called by EffectiveAddressWrite + */ + +void WriteCCR(char Size) +{ + if (Size == 'W') + { + /* Did we change from Supervisor to User mode ? */ + + char *Label = GenerateLabel(0,1); + + fprintf(fp, "\t\t test ah,20h \t\t\t; User Mode ?\n"); + fprintf(fp, "\t\t jne short %s\n\n",Label); + + /* Mode Switch - Update A7 */ + + fprintf(fp, "\t\t mov edx,[%s]\n",REG_A7); + fprintf(fp, "\t\t mov [%s],edx\n",REG_ISP); + fprintf(fp, "\t\t mov edx,[%s]\n",REG_USP); + fprintf(fp, "\t\t mov [%s],edx\n",REG_A7); + + fprintf(fp, "%s:\n",Label); + fprintf(fp, "\t\t mov byte [%s],ah \t;T, S & I\n",REG_SRH); + + /* Mask may now allow Interrupt */ + + CheckInterrupt += 1; + } + + /* Flags */ + + fprintf(fp, "\t\t and eax,byte 1Fh\n"); + fprintf(fp, "\t\t mov edx,[IntelFlag+eax*4]\n"); + fprintf(fp, "\t\t mov [%s],dh\n",REG_X); + fprintf(fp, "\t\t and edx,0EFFh\n"); +} + + +/* + * Interface to Mame memory commands + * + * Flags = "ABCDSDB" - set to '-' if not required to preserve + * (order EAX,EBX,ECX,EDX,ESI,EDI,EBP) + * + * AReg = Register containing Address + * + * Mask 0 : No Masking + * 1 : Mask top byte, but preserve register + * 2 : Mask top byte, preserve masked register + */ + +void Memory_Read(char Size,int AReg,char *Flags,int Mask) +{ + ExternalIO = 1; + + /* Save PC */ + + fprintf(fp, "\t\t mov [%s],ESI\n",REG_PC); + + /* Check for special mask condition */ + + /* ASG - no longer need to mask addresses here */ +/* if (Mask == 2) + fprintf(fp, "\t\t and %s,0FFFFFFh\n",regnameslong[AReg]);*/ + + /* Check to see if registers need saving */ + + if ((Flags[EDX] != '-') && (SavedRegs[EDX] == '-')) + { + fprintf(fp, "\t\t mov [%s],edx\n",REG_CCR); + } + + if ((Flags[EBX] != '-') && (SavedRegs[EBX] == '-')) + { + fprintf(fp, "\t\t push EBX\n"); + } + + if ((Flags[ECX] != '-') && (SavedRegs[ECX] == '-')) + { + fprintf(fp, "\t\t push ECX\n"); + } + + if ((Flags[EDI] != '-') && (SavedRegs[EDI] == '-')) + { + fprintf(fp, "\t\t push EDI\n"); + } + + /* Sort Address out */ + +#ifdef FASTCALL + + fprintf(fp, "\t\t mov %s,%s\n",FASTCALL_FIRST_REG,regnameslong[AReg]); + + /* ASG - no longer need to mask addresses here */ +/* if (Mask == 1) + fprintf(fp, "\t\t and %s,0FFFFFFh\n",FASTCALL_FIRST_REG);*/ + +#else + + if (Mask == 1) + { + if ((Flags[AReg] != '-') && (SavedRegs[AReg] != '-')) + { + /* Don't trash a wanted safe register */ + + fprintf(fp, "\t\t mov EAX,%s\n",regnameslong[AReg]); + /* ASG - no longer need to mask addresses here */ +/* fprintf(fp, "\t\t and EAX,0FFFFFFh\n");*/ + fprintf(fp, "\t\t push EAX\n"); + } + else + { + /* ASG - no longer need to mask addresses here */ +/* fprintf(fp, "\t\t and %s,0FFFFFFh\n",regnameslong[AReg]);*/ + fprintf(fp, "\t\t push %s\n",regnameslong[AReg]); + } + } + else + fprintf(fp, "\t\t push %s\n",regnameslong[AReg]); + +#endif + + + + /* Call Mame memory routine */ + + /* ASG - changed these to call through the function pointers */ + +#ifdef ENCRYPTED + switch (AccessType) + { + case NORMAL : + switch (Size) + { + case 66 : + fprintf(fp, "\t\t call [_a68k_memory_intf+4]\n"); + break; + + case 87 : + fprintf(fp, "\t\t call [_a68k_memory_intf+8]\n"); + break; + + case 76 : + fprintf(fp, "\t\t call [_a68k_memory_intf+12]\n"); + break; + } + break; + + case PCREL : + + switch (Size) + { + case 66 : + fprintf(fp, "\t\t call [_a68k_memory_intf+32]\n"); + break; + + case 87 : + fprintf(fp, "\t\t call [_a68k_memory_intf+36]\n"); + break; + + case 76 : + fprintf(fp, "\t\t call [_a68k_memory_intf+40]\n"); + break; + } + break; + } + +// AccessType = NORMAL; + +#else + + switch (Size) + { + case 66 : + fprintf(fp, "\t\t call [_a68k_memory_intf+4]\n"); + break; + + case 87 : + fprintf(fp, "\t\t call [_a68k_memory_intf+8]\n"); + break; + + case 76 : + fprintf(fp, "\t\t call [_a68k_memory_intf+12]\n"); + break; + } +#endif + + /* Correct Stack */ + +#ifndef FASTCALL + fprintf(fp, "\t\t lea esp,[esp+4]\n"); +#endif + + + + /* Restore registers */ + + /* Check to see if registers need restoring */ + + if ((Flags[EDI] != '-') && (SavedRegs[EDI] == '-')) + { + fprintf(fp, "\t\t pop EDI\n"); + } + + if ((Flags[ECX] != '-') && (SavedRegs[ECX] == '-')) + { + fprintf(fp, "\t\t pop ECX\n"); + } + + if ((Flags[EBX] != '-') && (SavedRegs[EBX] == '-')) + { + fprintf(fp, "\t\t pop EBX\n"); + } + + if ((Flags[ESI] != '-') && (SavedRegs[ESI] == '-')) + { + fprintf(fp, "\t\t mov ESI,[%s]\n",REG_PC); + } + + if ((Flags[EDX] != '-') && (SavedRegs[EDX] == '-')) + { + fprintf(fp, "\t\t mov EDX,[%s]\n",REG_CCR); + } + + if ((Flags[EBP] != '-') && (SavedRegs[EBP] == '-')) + { + fprintf(fp, "\t\t mov ebp,dword [_OP_ROM]\n"); + } +} + +void Memory_Write(char Size,int AReg,int DReg,char *Flags,int Mask) +{ + ExternalIO = 1; + + /* Save PC */ + + fprintf(fp, "\t\t mov [%s],ESI\n",REG_PC); + + /* Check for special mask condition */ + + /* ASG - no longer need to mask addresses here */ +/* if (Mask == 2) + fprintf(fp, "\t\t and %s,0FFFFFFh\n",regnameslong[AReg]);*/ + + /* Check to see if registers need saving */ + + if ((Flags[EDX] != '-') && (SavedRegs[EDX] == '-')) + { + fprintf(fp, "\t\t mov [%s],edx\n",REG_CCR); + } + + if ((Flags[EAX] != '-') && (SavedRegs[EAX] == '-')) + { + fprintf(fp, "\t\t push EAX\n"); + } + + if ((Flags[EBX] != '-') && (SavedRegs[EBX] == '-')) + { + fprintf(fp, "\t\t push EBX\n"); + } + + if ((Flags[ECX] != '-') && (SavedRegs[ECX] == '-')) + { + fprintf(fp, "\t\t push ECX\n"); + } + + if ((Flags[EDI] != '-') && (SavedRegs[EDI] == '-')) + { + fprintf(fp, "\t\t push EDI\n"); + } + +#ifdef FASTCALL + + fprintf(fp, "\t\t mov %s,%s\n",FASTCALL_SECOND_REG,regnameslong[DReg]); + fprintf(fp, "\t\t mov %s,%s\n",FASTCALL_FIRST_REG,regnameslong[AReg]); + + /* ASG - no longer need to mask addresses here */ +/* if (Mask == 1) + fprintf(fp, "\t\t and %s,0FFFFFFh\n",FASTCALL_FIRST_REG);*/ + +#else + + fprintf(fp, "\t\t push %s\n",regnameslong[DReg]); + + if (Mask == 1) + { + if ((Flags[AReg] != '-') && (SavedRegs[AReg] != '-')) + { + /* Don't trash a wanted safe register */ + + fprintf(fp, "\t\t mov EAX,%s\n",regnameslong[AReg]); + /* ASG - no longer need to mask addresses here */ +/* fprintf(fp, "\t\t and EAX,0FFFFFFh\n");*/ + fprintf(fp, "\t\t push EAX\n"); + } + else + { + /* ASG - no longer need to mask addresses here */ +/* fprintf(fp, "\t\t and %s,0FFFFFFh\n",regnameslong[AReg]);*/ + fprintf(fp, "\t\t push %s\n",regnameslong[AReg]); + } + } + else + fprintf(fp, "\t\t push %s\n",regnameslong[AReg]); + +#endif + + + + /* Call Mame Routine */ + + /* ASG - changed these to call through the function pointers */ + switch (Size) + { + case 66 : + fprintf(fp, "\t\t call [_a68k_memory_intf+16]\n"); + break; + + case 87 : + fprintf(fp, "\t\t call [_a68k_memory_intf+20]\n"); + break; + + case 76 : + fprintf(fp, "\t\t call [_a68k_memory_intf+24]\n"); + break; + } + + /* Correct Stack */ + +#ifndef FASTCALL + fprintf(fp, "\t\t lea esp,[esp+8]\n"); +#endif + + + + /* Restore registers */ + + /* Check to see if registers need restoring */ + + if ((Flags[EDI] != '-') && (SavedRegs[EDI] == '-')) + { + fprintf(fp, "\t\t pop EDI\n"); + } + + if ((Flags[ECX] != '-') && (SavedRegs[ECX] == '-')) + { + fprintf(fp, "\t\t pop ECX\n"); + } + + if ((Flags[EBX] != '-') && (SavedRegs[EBX] == '-')) + { + fprintf(fp, "\t\t pop EBX\n"); + } + + if ((Flags[EAX] != '-') && (SavedRegs[EAX] == '-')) + { + fprintf(fp, "\t\t pop EAX\n"); + } + + if ((Flags[EDX] != '-') && (SavedRegs[EDX] == '-')) + { + fprintf(fp, "\t\t mov EDX,[%s]\n",REG_CCR); + } + + if ((Flags[ESI] != '-') && (SavedRegs[ESI] == '-')) + { + fprintf(fp, "\t\t mov ESI,[%s]\n",REG_PC); + } + + if ((Flags[EBP] != '-') && (SavedRegs[EBP] == '-')) + { + fprintf(fp, "\t\t mov ebp,dword [_OP_ROM]\n"); + } +} + + +/* + * Fetch data from Code area + * + * Dreg = Destination Register + * Extend = Sign Extend Word to Long + * + */ + +void Memory_Fetch(char Size,int Dreg,int Extend) +{ + static int loopcount=0; + + /* Always goes via OP_ROM */ + + if(CPU!=2) + { + /* 16 Bit version */ + + if ((Extend == TRUE) & (Size == 'W')) + fprintf(fp, "\t\t movsx %s,word [esi+ebp]\n",regnameslong[Dreg]); + else if (Size == 'W') + fprintf(fp, "\t\t movzx %s,word [esi+ebp]\n",regnameslong[Dreg]); + else + fprintf(fp, "\t\t mov %s,dword [esi+ebp]\n",regnameslong[Dreg]); + + if (Size == 'L') + fprintf(fp, "\t\t rol %s,16\n",regnameslong[Dreg]); + } + else + { + /* 32 Bit version */ + + if (Size == 'W') + { + fprintf(fp, "\t\t mov %s,esi\n",regnameslong[Dreg]); + fprintf(fp, "\t\t xor %s,byte 2\n",regnameslong[Dreg]); + + if (Extend == TRUE) + fprintf(fp, "\t\t movsx %s,word [%s+ebp]\n",regnameslong[Dreg],regnameslong[Dreg]); + else + fprintf(fp, "\t\t movzx %s,word [%s+ebp]\n",regnameslong[Dreg],regnameslong[Dreg]); + } + else + { + // if address is exact multiple of 4, long read will work + // otherwise we need to get words address-2 and address+4 + + // Always read long + fprintf(fp, "\t\t test esi,2\n"); +#if (!ppro) + fprintf(fp, "\t\t mov %s,dword [esi+ebp]\n",regnameslong[Dreg]); + + // OK ? + fprintf(fp, "\t\t jz short FL%3.3d\n",loopcount+1); + + // no, so get high word + fprintf(fp, "\t\t mov %s,dword [esi+ebp-4]\n",regnameslong[Dreg]); + // and get low word + fprintf(fp, "\t\t mov %s,word [esi+ebp+4]\n",regnamesword[Dreg]); + + fprintf(fp, "FL%3.3d:\n",++loopcount); +#else + fprintf(fp, "\t\t cmovnz %s,dword [esi+ebp-4]\n",regnameslong[Dreg]); + fprintf(fp, "\t\t cmovz %s,dword [esi+ebp]\n",regnameslong[Dreg]); + fprintf(fp, "\t\t cmovnz %s,word [esi+ebp+4]\n",regnamesword[Dreg]); +#endif + } + } +} + +/**********************/ +/* Push PC onto Stack */ +/**********************/ + +void PushPC(int Wreg,int Wreg2,char *Flags, int Mask) +{ + + /* Wreg2 is only used when high byte is kept */ + /* If it is EBP then the register is restored */ + + fprintf(fp, "\t\t mov %s,[%s]\t ; Push onto Stack\n",regnameslong[Wreg],REG_A7); + fprintf(fp, "\t\t sub %s,byte 4\n",regnameslong[Wreg]); + fprintf(fp, "\t\t mov [%s],%s\n",REG_A7,regnameslong[Wreg]); + +#ifndef KEEPHIGHPC + + Memory_Write('L',Wreg,ESI,Flags,Mask); + +#else + + fprintf(fp, "\t\t mov %s,[FullPC]\n",regnameslong[Wreg2]); + fprintf(fp, "\t\t and %s,0xff000000\n",regnameslong[Wreg2]); + fprintf(fp, "\t\t or %s,ESI\n",regnameslong[Wreg2]); + + Memory_Write('L',Wreg,Wreg2,Flags,Mask); + + if (Wreg2 == EBP) + { + fprintf(fp, "\t\t mov ebp,dword [_OP_ROM]\n"); + } + +#endif +} + +void ExtensionDecode(int SaveEDX) +{ + char *Label = GenerateLabel(0,1); + + if (SaveEDX) + fprintf(fp, "\t\t push edx\n"); + + Memory_Fetch('W',EAX,FALSE); + fprintf(fp, "\t\t add esi,byte 2\n"); + + if(CPU!=2) + { + /* 68000 Extension */ + + fprintf(fp, "\t\t mov edx,eax\n"); + fprintf(fp, "\t\t shr eax,12\n"); + fprintf(fp, "\t\t test edx,0x0800\n"); + fprintf(fp, "\t\t mov eax,[%s+eax*4]\n",REG_DAT); + fprintf(fp, "\t\t jnz short %s\n",Label); + fprintf(fp, "\t\t cwde\n"); + fprintf(fp, "%s:\n",Label); + fprintf(fp, "\t\t lea edi,[edi+eax]\n"); + fprintf(fp, "\t\t movsx edx,dl\n"); + fprintf(fp, "\t\t lea edi,[edi+edx]\n"); + } + else + { + /* 68020 Extension */ + + // eax holds scaled index + + // might be faster just to push all regs + fprintf(fp, "\t\t push ebx\n"); + fprintf(fp, "\t\t push ecx\n"); + + // copies for later use + fprintf(fp, "\t\t mov ecx,eax\n"); + fprintf(fp, "\t\t mov edx,eax\n"); + + // check E bit to see if displacement or full format + fprintf(fp, "\t\t test edx,0x0100\n"); + fprintf(fp, "\t\t jz short %s_a\n",Label); + // full mode so check IS (index supress) + fprintf(fp, "\t\t test edx,0x0040\n"); + fprintf(fp, "\t\t jz short %s_b\n",Label); + // set index to 0, it's not added + ClearRegister(EAX); + fprintf(fp, "\t\t jmp short %s_d\n",Label); // near + + // add displacement + fprintf(fp, "%s_a:\n",Label); + fprintf(fp, "\t\t movsx eax,al\n"); + fprintf(fp, "\t\t lea edi,[edi+eax]\n"); + + fprintf(fp, "%s_b:\n",Label); + // calc index always scale (68k will scale by 1) + fprintf(fp, "\t\t mov eax,edx\n"); + fprintf(fp, "\t\t shr eax,12\n"); + fprintf(fp, "\t\t test edx,0x0800\n"); + fprintf(fp, "\t\t mov eax,[%s+eax*4]\n",REG_DAT); + fprintf(fp, "\t\t jnz short %s_c\n",Label); + fprintf(fp, "\t\t cwde\n"); + + fprintf(fp, "%s_c:\n",Label); + fprintf(fp, "\t\t shr ecx,byte 9\n"); + fprintf(fp, "\t\t and ecx,byte 3\n"); + fprintf(fp, "\t\t shl eax,cl\n"); + + // if brief mode we can add index and exit + fprintf(fp, "\t\t test edx,0x0100\n"); + fprintf(fp, "\t\t jz near %s_i2\n",Label); + + fprintf(fp, "%s_d:\n",Label); + // check BS (base supress) + // if BS is 1 then set edi to 0 + fprintf(fp, "\t\t test edx,0x0080\n"); + fprintf(fp, "\t\t jz short %s_4a\n",Label); + ClearRegister(EDI); + // if null displacement skip over + fprintf(fp, "%s_4a:\n",Label); + fprintf(fp, "\t\t test edx,0x0020\n"); + fprintf(fp, "\t\t jz short %s_f\n",Label); + + // **** calc base displacement **** + // is it long + fprintf(fp, "\t\t test edx,0x0010\n"); + fprintf(fp, "\t\t jz short %s_e\n",Label); + // fetch long base + Memory_Fetch('L',EBX,FALSE); + fprintf(fp, "\t\t lea edi,[edi+ebx]\n"); + fprintf(fp, "\t\t add esi,byte 4\n"); + fprintf(fp, "\t\t jmp short %s_f\n",Label); + + // fetch word base + fprintf(fp, "%s_e:\n",Label); + Memory_Fetch('W',EBX,TRUE); + fprintf(fp, "\t\t lea edi,[edi+ebx]\n"); + fprintf(fp, "\t\t add esi,byte 2\n"); + + // **** indirect? **** + fprintf(fp, "%s_f:\n",Label); + fprintf(fp, "\t\t test edx,0x0003\n"); + fprintf(fp, "\t\t jz near %s_7a\n",Label); + // pre or post indirect + fprintf(fp, "\t\t test edx,0x0004\n"); + fprintf(fp, "\t\t jnz short %s_g\n",Label); + // do pre + fprintf(fp, "\t\t lea edi,[edi+eax]\n"); + Memory_Read('L',EDI,"ABCDSDB",2); + fprintf(fp, "\t\t mov edi,eax\n"); + fprintf(fp, "\t\t jmp short %s_h\n",Label); + + // do post + fprintf(fp, "%s_g:\n",Label); + fprintf(fp, "\t\t push eax\n"); + Memory_Read('L',EDI,"-B-DS-B",2); + fprintf(fp, "\t\t pop edi\n"); + + fprintf(fp, "%s_7a:\n",Label); + fprintf(fp, "\t\t lea edi,[edi+eax]\n"); + + // **** outer displacement **** + // if null displacement skip over + fprintf(fp, "%s_h:\n",Label); + fprintf(fp, "\t\t test edx,0x0002\n"); + fprintf(fp, "\t\t jz short %s_j\n",Label); + // word or long? + fprintf(fp, "\t\t test edx,0x0001\n"); + fprintf(fp, "\t\t jz short %s_i\n",Label); + // fetch long + Memory_Fetch('L',EAX,FALSE); + fprintf(fp, "\t\t add esi,byte 4\n"); + fprintf(fp, "\t\t jmp short %s_i2\n",Label); + // fetch word + fprintf(fp, "%s_i:\n",Label); + Memory_Fetch('W',EAX,TRUE); + fprintf(fp, "\t\t add esi,byte 2\n"); + fprintf(fp, "%s_i2:\n",Label); + fprintf(fp, "\t\t lea edi,[edi+eax]\n"); + + // **** exit **** + fprintf(fp, "%s_j:\n",Label); + fprintf(fp, "\t\t pop ecx\n"); + fprintf(fp, "\t\t pop ebx\n"); + } + + if (SaveEDX) + fprintf(fp, "\t\t pop edx\n"); +} + +/* Calculate Effective Address - Return address in EDI + * + * mode = Effective Address from Instruction + * Size = Byte,Word or Long + * Rreg = Register with Register Number in + * + * Only for modes 2 - 10 (5-10 clobber EAX) + */ + +void EffectiveAddressCalculate(int mode,char Size,int Rreg,int SaveEDX) +{ + /* timing */ + + if ((TimingCycles > 0) && (AddEACycles!=0)) + { + switch (mode) + { + case 2: /* (An) */ + case 3: /* (An)+ */ + case 11: /* #x,SR,CCR */ + case 19: /* (A7)+ */ + TimingCycles += 4 ; + break ; + + case 4: /* -(An) */ + case 20: /* -(A7) */ + TimingCycles += (CPU==2) ? 5 : 6 ; + break ; + + case 5: /* x(An) */ + case 9: /* x(PC) */ + TimingCycles += (CPU==2) ? 5 : 8 ; + break ; + + case 7: /* x.w */ + TimingCycles += (CPU==2) ? 4 : 8 ; + break ; + + case 6: /* x(An,xr.s) */ + case 10: /* x(PC,xr.s) */ + TimingCycles += (CPU==2) ? 7 : 10 ; + break ; + + case 8: /* x.l */ + TimingCycles += (CPU==2) ? 4 : 12 ; + break ; + } + + /* long w/r adds 4 cycles */ + + if ((mode>1) && (Size == 'L') && (CPU != 2)) + TimingCycles += 4 ; + } + + AccessType = NORMAL; + + switch (mode) + { + + case 2: + fprintf(fp, "\t\t mov EDI,[%s+%s*4]\n",REG_ADD,regnameslong[Rreg]); + break; + + case 3: + fprintf(fp, "\t\t mov EDI,[%s+%s*4]\n",REG_ADD,regnameslong[Rreg]); + IncrementEDI(Size,Rreg); + break; + + case 4: + fprintf(fp, "\t\t mov EDI,[%s+%s*4]\n",REG_ADD,regnameslong[Rreg]); + DecrementEDI(Size,Rreg); + fprintf(fp, "\t\t mov [%s+%s*4],EDI\n",REG_ADD,regnameslong[Rreg]); + break; + + case 5: + Memory_Fetch('W',EAX,TRUE); + fprintf(fp, "\t\t mov EDI,[%s+%s*4]\n",REG_ADD,regnameslong[Rreg]); + fprintf(fp, "\t\t add esi,byte 2\n"); + fprintf(fp, "\t\t add edi,eax\n"); + break; + + case 6: + + /* Get Address register Value */ + + fprintf(fp, "\t\t mov EDI,[%s+%s*4]\n",REG_ADD,regnameslong[Rreg]); + + /* Add Extension Details */ + + ExtensionDecode(SaveEDX); + break; + + case 7: + + /* Get Word */ + + Memory_Fetch('W',EDI,TRUE); +// fprintf(fp, "\t\t movsx edi,di\n"); + fprintf(fp, "\t\t add esi,byte 2\n"); + break; + + case 8: + + /* Get Long */ + + Memory_Fetch('L',EDI,FALSE); + fprintf(fp, "\t\t add esi,byte 4\n"); + break; + + case 9: + + AccessType = PCREL; + + Memory_Fetch('W',EAX,TRUE); +// fprintf(fp, "\t\t movsx eax,ax\n"); + fprintf(fp, "\t\t mov EDI,ESI ; Get PC\n"); + fprintf(fp, "\t\t add esi,byte 2\n"); + fprintf(fp, "\t\t add edi,eax ; Add Offset to PC\n"); + break; + + case 10: + + AccessType = PCREL; + + /* Get PC */ + + fprintf(fp, "\t\t mov edi,esi ; Get PC\n"); + + /* Add Extension Details */ + + ExtensionDecode(SaveEDX); + + break; + + case 19: + + /* (A7)+ */ + + fprintf(fp, "\t\t mov edi,[%s] ; Get A7\n",REG_A7); + fprintf(fp, "\t\t add dword [%s],byte 2\n",REG_A7); + break; + + case 20: + + /* -(A7) */ + + fprintf(fp, "\t\t mov edi,[%s] ; Get A7\n",REG_A7); + fprintf(fp, "\t\t sub edi,byte 2\n"); + fprintf(fp, "\t\t mov [%s],edi\n",REG_A7); + break; + + } +} + +/* Read from Effective Address + * + * mode = Effective Address from Instruction + * Size = Byte,Word or Long + * Rreg = Register with Register Number in + * Flag = Registers to preserve (EDX is handled by SaveEDX) + * + * Return + * Dreg = Register to return result in (EAX is usually most efficient) + * (modes 5 to 10) EDI = Address of data read (masked with FFFFFF) + */ + +void EffectiveAddressRead(int mode,char Size,int Rreg,int Dreg,const char *flags,int SaveEDX) +{ + char* Regname=""; + int MaskMode; + char Flags[8]; + + AccessType = NORMAL; + + strcpy(Flags,flags); + + /* Which Masking to Use */ + + if (Flags[5] != '-') + MaskMode = 2; + else + MaskMode = 1; + + if (SaveEDX) + Flags[3] = 'D'; + else + Flags[3] = '-'; + + switch (Size) + { + case 66: + Regname = regnamesshort[Dreg]; + break; + + case 87: + Regname = regnamesword[Dreg]; + break; + + case 76: + Regname = regnameslong[Dreg]; + break; + } + + switch (mode & 15) + { + + case 0: + + /* Read 32 bits - No prefix */ + + fprintf(fp, "\t\t mov %s,[%s+%s*4]\n",regnameslong[Dreg],REG_DAT,regnameslong[Rreg]); + break; + + case 1: + + /* Read 32 bits - No prefix */ + + fprintf(fp, "\t\t mov %s,[%s+%s*4]\n",regnameslong[Dreg],REG_ADD,regnameslong[Rreg]); + break; + + case 2: + EffectiveAddressCalculate(mode,Size,Rreg,SaveEDX); + + Memory_Read(Size,EDI,Flags,MaskMode); + + if (Dreg != EAX) + { + fprintf(fp, "\t\t mov %s,EAX\n",regnameslong[Dreg]); + } + break; + + case 3: + EffectiveAddressCalculate(mode,Size,Rreg,SaveEDX); + + Memory_Read(Size,EDI,Flags,MaskMode); + + if (Dreg != EAX) + { + fprintf(fp, "\t\t mov %s,EAX\n",regnameslong[Dreg]); + } + break; + + case 4: + EffectiveAddressCalculate(mode,Size,Rreg,SaveEDX); + + Memory_Read(Size,EDI,Flags,MaskMode); + + if (Dreg != EAX) + { + fprintf(fp, "\t\t mov %s,EAX\n",regnameslong[Dreg]); + } + break; + + + case 5: + EffectiveAddressCalculate(mode,Size,Rreg,SaveEDX); + + Memory_Read(Size,EDI,Flags,MaskMode); + + if (Dreg != EAX) + { + fprintf(fp, "\t\t mov %s,EAX\n",regnameslong[Dreg]); + } + break; + + case 6: + EffectiveAddressCalculate(mode,Size,Rreg,SaveEDX); + + Memory_Read(Size,EDI,Flags,MaskMode); + + if (Dreg != EAX) + { + fprintf(fp, "\t\t mov %s,EAX\n",regnameslong[Dreg]); + } + break; + + case 7: + EffectiveAddressCalculate(mode,Size,Rreg,SaveEDX); + + Memory_Read(Size,EDI,Flags,MaskMode); + + if (Dreg != EAX) + { + fprintf(fp, "\t\t mov %s,EAX\n",regnameslong[Dreg]); + } + break; + + case 8: + EffectiveAddressCalculate(mode,Size,Rreg,SaveEDX); + + Memory_Read(Size,EDI,Flags,MaskMode); + + if (Dreg != EAX) + { + fprintf(fp, "\t\t mov %s,EAX\n",regnameslong[Dreg]); + } + break; + + case 9: + EffectiveAddressCalculate(mode,Size,Rreg,SaveEDX); + + Memory_Read(Size,EDI,Flags,MaskMode); + + if (Dreg != EAX) + { + fprintf(fp, "\t\t mov %s,EAX\n",regnameslong[Dreg]); + } + break; + + case 10: + EffectiveAddressCalculate(mode,Size,Rreg,SaveEDX); + + Memory_Read(Size,EDI,Flags,MaskMode); + + if (Dreg != EAX) + { + fprintf(fp, "\t\t mov %s,EAX\n",regnameslong[Dreg]); + } + break; + + case 11: + + /* Immediate - for SR or CCR see ReadCCR() */ + + if (Size == 'L') + { + Memory_Fetch('L',Dreg,FALSE); + fprintf(fp, "\t\t add esi,byte 4\n"); + } + else + { + Memory_Fetch('W',Dreg,FALSE); + fprintf(fp, "\t\t add esi,byte 2\n"); + }; + break; + } +} + +/* + * EA = Effective Address from Instruction + * Size = Byte,Word or Long + * Rreg = Register with Register Number in + * + * Writes from EAX + */ + +void EffectiveAddressWrite(int mode,char Size,int Rreg,int CalcAddress,const char *flags,int SaveEDX) +{ + int MaskMode; + char* Regname=""; + char Flags[8]; + + + strcpy(Flags,flags); + + /* Which Masking to Use ? */ + + if (CalcAddress) + { + if (Flags[5] != '-') + MaskMode = 2; + else + MaskMode = 1; + } + else + MaskMode = 0; + + if (SaveEDX) + Flags[3] = 'D'; + else + Flags[3] = '-'; + + switch (Size) + { + case 66: + Regname = regnamesshort[0]; + break; + + case 87: + Regname = regnamesword[0]; + break; + + case 76: + Regname = regnameslong[0]; + break; + } + + switch (mode & 15) + { + + case 0: + fprintf(fp, "\t\t mov [%s+%s*4],%s\n",REG_DAT,regnameslong[Rreg],Regname); + break; + + case 1: + if (Size == 66) + { + /* Not Allowed */ + + fprintf(fp, "DUFF CODE!\n"); + } + else + { + if (Size == 87) + { + fprintf(fp, "\t\t cwde\n"); + } + + fprintf(fp, "\t\t mov [%s+%s*4],%s\n",REG_ADD,regnameslong[Rreg],regnameslong[0]); + } + break; + + case 2: + if (CalcAddress) EffectiveAddressCalculate(mode,Size,Rreg,SaveEDX); + Memory_Write(Size,EDI,EAX,Flags,MaskMode); + break; + + case 3: + if (CalcAddress) EffectiveAddressCalculate(mode,Size,Rreg,SaveEDX); + Memory_Write(Size,EDI,EAX,Flags,MaskMode); + break; + + case 4: + if (CalcAddress) EffectiveAddressCalculate(mode,Size,Rreg,SaveEDX); + Memory_Write(Size,EDI,EAX,Flags,MaskMode); + break; + + case 5: + if (CalcAddress) + { + fprintf(fp, "\t\t push EAX\n"); + EffectiveAddressCalculate(mode,Size,Rreg,SaveEDX); + fprintf(fp, "\t\t pop EAX\n"); + } + Memory_Write(Size,EDI,EAX,Flags,MaskMode); + break; + + case 6: + if (CalcAddress) + { + fprintf(fp, "\t\t push EAX\n"); + EffectiveAddressCalculate(mode,Size,Rreg,SaveEDX); + fprintf(fp, "\t\t pop EAX\n"); + } + Memory_Write(Size,EDI,EAX,Flags,MaskMode); + break; + + case 7: + if (CalcAddress) + { + fprintf(fp, "\t\t push EAX\n"); + EffectiveAddressCalculate(mode,Size,Rreg,SaveEDX); + fprintf(fp, "\t\t pop EAX\n"); + } + Memory_Write(Size,EDI,EAX,Flags,MaskMode); + break; + + case 8: + if (CalcAddress) + { + fprintf(fp, "\t\t push EAX\n"); + EffectiveAddressCalculate(mode,Size,Rreg,SaveEDX); + fprintf(fp, "\t\t pop EAX\n"); + } + Memory_Write(Size,EDI,EAX,Flags,MaskMode); + break; + + case 9: + if (CalcAddress) + { + fprintf(fp, "\t\t push EAX\n"); + EffectiveAddressCalculate(mode,Size,Rreg,SaveEDX); + fprintf(fp, "\t\t pop EAX\n"); + } + Memory_Write(Size,EDI,EAX,Flags,MaskMode); + break; + + case 10: + if (CalcAddress) + { + fprintf(fp, "\t\t push EAX\n"); + EffectiveAddressCalculate(mode,Size,Rreg,SaveEDX); + fprintf(fp, "\t\t pop EAX\n"); + } + Memory_Write(Size,EDI,EAX,Flags,MaskMode); + break; + + case 11: + + /* SR, CCR - Chain to correct routine */ + + WriteCCR(Size); + } +} + +/* Condition Decode Routines */ + +/* + * mode = condition to check for + * + * Returns LABEL that is jumped to if condition is Condition + * + * Some conditions clobber AH + */ + +char *ConditionDecode(int mode, int Condition) +{ + char *Label = GenerateLabel(0,1); + + switch (mode) + { + + case 0: /* A - Always */ + if (Condition) + { + fprintf(fp, "\t\t jmp %s ;dave removed near\n",Label); + } + break; + + case 1: /* F - Never */ + if (!Condition) + { + fprintf(fp, "\t\t jmp near %s\n",Label); + } + break; + + case 2: /* Hi */ + fprintf(fp, "\t\t mov ah,dl\n"); + fprintf(fp, "\t\t sahf\n"); + + if (Condition) + { + fprintf(fp, "\t\t ja near %s\n",Label); + } + else + { + fprintf(fp, "\t\t jbe near %s\n",Label); + } + break; + + case 3: /* Ls */ + fprintf(fp, "\t\t mov ah,dl\n"); + fprintf(fp, "\t\t sahf\n"); + + if (Condition) + { + fprintf(fp, "\t\t jbe near %s\n",Label); + } + else + { + fprintf(fp, "\t\t ja near %s\n",Label); + } + break; + + case 4: /* CC */ + fprintf(fp, "\t\t test dl,1H\t\t;check carry\n"); + + if (Condition) + { + fprintf(fp, "\t\t jz near %s\n",Label); + } + else + { + fprintf(fp, "\t\t jnz near %s\n",Label); + } + break; + + case 5: /* CS */ + fprintf(fp, "\t\t test dl,1H\t\t;check carry\n"); + if (Condition) + { + fprintf(fp, "\t\t jnz near %s\n",Label); + } + else + { + fprintf(fp, "\t\t jz near %s\n",Label); + } + break; + + case 6: /* NE */ + fprintf(fp, "\t\t test dl,40H\t\t;Check zero\n"); + if (Condition) + { + fprintf(fp, "\t\t jz near %s\n",Label); + } + else + { + fprintf(fp, "\t\t jnz near %s\n",Label); + } + break; + + case 7: /* EQ */ + fprintf(fp, "\t\t test dl,40H\t\t;Check zero\n"); + if (Condition) + { + fprintf(fp, "\t\t jnz near %s\n",Label); + } + else + { + fprintf(fp, "\t\t jz near %s\n",Label); + } + break; + + case 8: /* VC */ + fprintf(fp, "\t\t test dh,8H\t\t;Check Overflow\n"); + if (Condition) + { + fprintf(fp, "\t\t jz near %s\n", Label); + } + else + { + fprintf(fp, "\t\t jnz near %s\n", Label); + } + break; + + case 9: /* VS */ + fprintf(fp, "\t\t test dh,8H\t\t;Check Overflow\n"); + if (Condition) + { + fprintf(fp, "\t\t jnz near %s\n", Label); + } + else + { + fprintf(fp, "\t\t jz near %s\n", Label); + } + break; + + case 10: /* PL */ + fprintf(fp,"\t\t test dl,80H\t\t;Check Sign\n"); + if (Condition) + { + fprintf(fp, "\t\t jz near %s\n", Label); + } + else + { + fprintf(fp, "\t\t jnz near %s\n", Label); + } + break; + + case 11: /* MI */ + fprintf(fp,"\t\t test dl,80H\t\t;Check Sign\n"); + if (Condition) + { + fprintf(fp, "\t\t jnz near %s\n", Label); + } + else + { + fprintf(fp, "\t\t jz near %s\n", Label); + } + break; + + case 12: /* GE */ + fprintf(fp, "\t\t or edx,200h\n"); + fprintf(fp, "\t\t push edx\n"); + fprintf(fp, "\t\t popf\n"); + if (Condition) + { + fprintf(fp, "\t\t jge near %s\n",Label); + } + else + { + fprintf(fp, "\t\t jl near %s\n",Label); + } + break; + + case 13: /* LT */ + fprintf(fp, "\t\t or edx,200h\n"); + fprintf(fp, "\t\t push edx\n"); + fprintf(fp, "\t\t popf\n"); + if (Condition) + { + fprintf(fp, "\t\t jl near %s\n",Label); + } + else + { + fprintf(fp, "\t\t jge near %s\n",Label); + } + break; + + case 14: /* GT */ + fprintf(fp, "\t\t or edx,200h\n"); + fprintf(fp, "\t\t push edx\n"); + fprintf(fp, "\t\t popf\n"); + if (Condition) + { + fprintf(fp, "\t\t jg near %s\n",Label); + } + else + { + fprintf(fp, "\t\t jle near %s\n",Label); + } + break; + + case 15: /* LE */ + fprintf(fp, "\t\t or edx,200h\n"); + fprintf(fp, "\t\t push edx\n"); + fprintf(fp, "\t\t popf\n"); + if (Condition) + { + fprintf(fp, "\t\t jle near %s\n",Label); + } + else + { + fprintf(fp, "\t\t jg near %s\n",Label); + } + break; + } + + return Label; +} + +/* + * mode = condition to check for + * SetWhat = text for assembler command (usually AL or address descriptor) + * + * Some conditions clobber AH + */ + +void ConditionCheck(int mode, char *SetWhat) +{ + switch (mode) + { + + case 0: /* A - Always */ + fprintf(fp, "\t\t mov %s,byte 0ffh\n",SetWhat); + break; + + case 1: /* F - Never */ + if (SetWhat[1] == 'L') + { + ClearRegister(EAX); + } + else + { + fprintf(fp, "\t\t mov %s,byte 0h\n",SetWhat); + } + break; + + case 2: /* Hi */ + fprintf(fp, "\t\t mov ah,dl\n"); + fprintf(fp, "\t\t sahf\n"); + fprintf(fp, "\t\t seta %s\n",SetWhat); + fprintf(fp, "\t\t neg byte %s\n",SetWhat); + break; + + case 3: /* Ls */ + fprintf(fp, "\t\t mov ah,dl\n"); + fprintf(fp, "\t\t sahf\n"); + fprintf(fp, "\t\t setbe %s\n",SetWhat); + fprintf(fp, "\t\t neg byte %s\n",SetWhat); + break; + + case 4: /* CC */ + fprintf(fp, "\t\t test dl,1\t\t;Check Carry\n"); + fprintf(fp, "\t\t setz %s\n",SetWhat); + fprintf(fp, "\t\t neg byte %s\n",SetWhat); + break; + + case 5: /* CS */ + fprintf(fp, "\t\t test dl,1\t\t;Check Carry\n"); + fprintf(fp, "\t\t setnz %s\n",SetWhat); + fprintf(fp, "\t\t neg byte %s\n",SetWhat); + break; + + case 6: /* NE */ + fprintf(fp, "\t\t test dl,40H\t\t;Check Zero\n"); + fprintf(fp, "\t\t setz %s\n",SetWhat); + fprintf(fp, "\t\t neg byte %s\n",SetWhat); + break; + + case 7: /* EQ */ + fprintf(fp, "\t\t test dl,40H\t\t;Check Zero\n"); + fprintf(fp, "\t\t setnz %s\n",SetWhat); + fprintf(fp, "\t\t neg byte %s\n",SetWhat); + break; + + case 8: /* VC */ + fprintf(fp, "\t\t test dh,8H\t\t;Check Overflow\n"); + fprintf(fp, "\t\t setz %s\n",SetWhat); + fprintf(fp, "\t\t neg byte %s\n",SetWhat); + break; + + case 9: /* VS */ + fprintf(fp, "\t\t test dh,8H\t\t;Check Overflow\n"); + fprintf(fp, "\t\t setnz %s\n",SetWhat); + fprintf(fp, "\t\t neg byte %s\n",SetWhat); + break; + + case 10: /* PL */ + fprintf(fp, "\t\t test dl,80H\t\t;Check Sign\n"); + fprintf(fp, "\t\t setz %s\n",SetWhat); + fprintf(fp, "\t\t neg byte %s\n",SetWhat); + break; + + case 11: /* MI */ + fprintf(fp, "\t\t test dl,80H\t\t;Check Sign\n"); + fprintf(fp, "\t\t setnz %s\n",SetWhat); + fprintf(fp, "\t\t neg byte %s\n",SetWhat); + break; + + case 12: /* GE */ + fprintf(fp, "\t\t or edx,200h\n"); + fprintf(fp, "\t\t push edx\n"); + fprintf(fp, "\t\t popf\n"); + fprintf(fp, "\t\t setge %s\n",SetWhat); + fprintf(fp, "\t\t neg byte %s\n",SetWhat); + break; + + case 13: /* LT */ + fprintf(fp, "\t\t or edx,200h\n"); + fprintf(fp, "\t\t push edx\n"); + fprintf(fp, "\t\t popf\n"); + fprintf(fp, "\t\t setl %s\n",SetWhat); + fprintf(fp, "\t\t neg byte %s\n",SetWhat); + break; + + case 14: /* GT */ + fprintf(fp, "\t\t or edx,200h\n"); + fprintf(fp, "\t\t push edx\n"); + fprintf(fp, "\t\t popf\n"); + fprintf(fp, "\t\t setg %s\n",SetWhat); + fprintf(fp, "\t\t neg byte %s\n",SetWhat); + break; + + case 15: /* LE */ + fprintf(fp, "\t\t or edx,200h\n"); + fprintf(fp, "\t\t push edx\n"); + fprintf(fp, "\t\t popf\n"); + fprintf(fp, "\t\t setle %s\n",SetWhat); + fprintf(fp, "\t\t neg byte %s\n",SetWhat); + break; + } +} + + +/**********************************************************************/ +/* Instructions - Each routine generates a range of instruction codes */ +/**********************************************************************/ + +/* + * Immediate Commands + * + * ORI 00xx + * ANDI 02xx + * SUBI 04xx + * ADDI 06xx + * EORI 0axx + * CMPI 0cxx + * + */ + +void dump_imm( int type, int leng, int mode, int sreg ) +{ + int Opcode,BaseCode ; + char Size=' ' ; + char * RegnameEBX="" ; + char * Regname="" ; + char * OpcodeName[16] = {"or ", "and", "sub", "add",0,"xor","cmp",0} ; + int allow[] = {1,0,1,1, 1,1,1,1, 1,0,0,0, 0,0,0,0, 0,0,0,1, 1} ; + + Opcode = (type << 9) | ( leng << 6 ) | ( mode << 3 ) | sreg; + + BaseCode = Opcode & 0xfff8; + + if (mode == 7) BaseCode |= sreg ; + +#ifdef A7ROUTINE + if ((leng == 0) && (sreg == 7) && (mode > 2) && (mode < 5)) + { + BaseCode |= sreg ; + } +#endif + + if (type != 4) /* Not Valid (for this routine) */ + { + int Dest = EAtoAMN(Opcode, FALSE); + int SetX; + + /* ADDI & SUBI also set X flag */ + + SetX = ((type == 2) || (type == 3)); + + switch (leng) + { + case 0: + Size = 'B'; + Regname = regnamesshort[0]; + RegnameEBX = regnamesshort[EBX]; + break; + case 1: + Size = 'W'; + Regname = regnamesword[0]; + RegnameEBX = regnamesword[EBX]; + break; + case 2: + Size = 'L'; + Regname = regnameslong[0]; + RegnameEBX = regnameslong[EBX]; + break; + } + + if (allow[Dest]) + { + if (OpcodeArray[BaseCode] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + + /* Save Previous PC if Memory Access */ + + if ((Dest >= 2) && (Dest <=10)) + SavePreviousPC(); + + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + if (mode < 2) + { + if (Size != 'L') + TimingCycles += (CPU==2) ? 4 : 8; + else + { + TimingCycles += (CPU==2) ? 8 : 14; + if ((type != 1) && (type!=6)) + TimingCycles += 2 ; + } + } + else + { + if (type != 6) + { + if (Size != 'L') + TimingCycles += (CPU==2) ? 4 : 12 ; + else + TimingCycles += (CPU==2) ? 4 : 20 ; + } + else + { + if (Size != 'L') + TimingCycles += (CPU==2) ? 4 : 8 ; + else + TimingCycles += (CPU==2) ? 4 : 12 ; + } + } + + fprintf(fp, "\t\t and ecx,byte 7\n"); + + /* Immediate Mode Data */ + EffectiveAddressRead(11,Size,EBX,EBX,"--C-S-B",FALSE); + + /* Source Data */ + EffectiveAddressRead(Dest,Size,ECX,EAX,"-BC-SDB",FALSE); + + /* The actual work */ + fprintf(fp, "\t\t %s %s,%s\n", OpcodeName[type], Regname, RegnameEBX ); + + SetFlags(Size,EAX,FALSE,SetX,TRUE); + + if (type != 6) /* CMP no update */ + EffectiveAddressWrite(Dest,Size,ECX,EAX,"---DS-B",FALSE); + + Completed(); + } + } + else + { + /* Logicals are allowed to alter SR/CCR */ + + if ((!SetX) && (Dest == 11) && (Size != 'L') && (type != 6)) + { + Align(); + + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + TimingCycles += 20 ; + + if (Size=='W') + { + /* If SR then must be in Supervisor Mode */ + + char *Label = GenerateLabel(0,1); + + fprintf(fp, "\t\t test byte [%s],20h \t\t\t; Supervisor Mode ?\n",REG_SRH); + fprintf(fp, "\t\t jne near %s\n\n",Label); + + /* User Mode - Exception */ + + Exception(8,BaseCode); + + fprintf(fp, "%s:\n",Label); + } + + /* Immediate Mode Data */ + EffectiveAddressRead(11,Size,EBX,EBX,"---DS-B",TRUE); + + ReadCCR(Size,ECX); + + fprintf(fp, "\t\t %s %s,%s\n", OpcodeName[type], Regname, RegnameEBX ); + + WriteCCR(Size); + + Completed(); + } + else + { + + /* Illegal Opcode */ + + OpcodeArray[BaseCode] = -1; + BaseCode = -1; + } + } + } + else + { + BaseCode = -2; + } + + OpcodeArray[Opcode] = BaseCode; +} + +void immediate(void) +{ + int type, size, mode, sreg ; + + for (type = 0 ; type < 0x7; type++) + for (size = 0 ; size < 3 ; size++) + for (mode = 0 ; mode < 8 ; mode++) + for (sreg = 0 ; sreg < 8 ; sreg++) + dump_imm( type, size, mode, sreg ) ; +} + + +/* + * Bitwise Codes + * + */ + +void dump_bit_dynamic( int sreg, int type, int mode, int dreg ) +{ + int Opcode, BaseCode ; + char Size ; + char *EAXReg,*ECXReg, *Label ; + char allow[] = "0-2345678-------" ; + int Dest ; + + /* BTST allows x(PC) and x(PC,xr.s) - others do not */ + + if (type == 0) + { + allow[9] = '9'; + allow[10] = 'a'; + allow[11] = 'b'; // dave fix to nhl + } + + Opcode = 0x0100 | (sreg << 9) | (type<<6) | (mode<<3) | dreg ; + + BaseCode = Opcode & 0x01f8 ; + if (mode == 7) BaseCode |= dreg ; + + + // A7+, A7- + +#ifdef A7ROUTINE + if ((mode > 2) && (mode < 5)) + { + if (dreg == 7) BaseCode |= dreg; + } +#endif + + Dest = EAtoAMN(Opcode, FALSE); + + if (allow[Dest&0xf] != '-') + { + if (mode == 0) /* long*/ + { + /* Modify register memory directly */ + + Size = 'L' ; + EAXReg = REG_DAT_EBX; + ECXReg = regnameslong[ECX]; + } + else + { + Size = 'B' ; + EAXReg = regnamesshort[EAX]; + ECXReg = regnamesshort[ECX]; + } + + if (OpcodeArray[BaseCode] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + + /* Save Previous PC if Memory Access */ + + if ((Dest >= 2) && (Dest <=10)) + SavePreviousPC(); + + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + if (mode<2) + { + switch (type) + { + case 0: + TimingCycles += 6 ; + break; + case 1: + case 3: + TimingCycles += 8 ; + break; + case 2: + TimingCycles += 10; + break; + } + } + else + { + if (type==0) + TimingCycles += 4; + else + TimingCycles += 8; + } + + /* Only need this sorted out if a register is involved */ + + if (Dest < 7) + { + fprintf(fp, "\t\t mov ebx,ecx\n"); + fprintf(fp, "\t\t and ebx,byte 7\n"); + } + + /* Get bit number and create mask in ECX */ + + fprintf(fp, "\t\t shr ecx, byte 9\n"); + fprintf(fp, "\t\t and ecx, byte 7\n"); + fprintf(fp, "\t\t mov ecx, [%s+ECX*4]\n",REG_DAT); + + if (Size == 'L') + fprintf(fp, "\t\t and ecx, byte 31\n"); + else + fprintf(fp, "\t\t and ecx, byte 7\n"); + + #ifdef QUICKZERO + fprintf(fp,"\t\t mov eax,1\n"); + #else + fprintf(fp,"\t\t xor eax,eax\n"); + fprintf(fp,"\t\t inc eax\n"); + #endif + + fprintf(fp,"\t\t shl eax,cl\n"); + fprintf(fp,"\t\t mov ecx,eax\n"); + + if (mode != 0) + EffectiveAddressRead(Dest,Size,EBX,EAX,"-BCDSDB",TRUE); + + + /* All commands copy existing bit to Zero Flag */ + + Label = GenerateLabel(0,1); + + fprintf(fp,"\t\t or edx,byte 40h\t; Set Zero Flag\n"); + fprintf(fp,"\t\t test %s,%s\n",EAXReg,ECXReg); + fprintf(fp,"\t\t jz short %s\n",Label); + fprintf(fp,"\t\t xor edx,byte 40h\t; Clear Zero Flag\n"); + fprintf(fp,"%s:\n",Label); + + /* Some then modify the data */ + + switch (type) + { + case 0: /* btst*/ + break; + + case 1: /* bchg*/ + fprintf(fp,"\t\t xor %s,%s\n",EAXReg,ECXReg); + break; + + case 2: /* bclr*/ + fprintf(fp,"\t\t not ecx\n"); + fprintf(fp,"\t\t and %s,%s\n",EAXReg,ECXReg); + break; + + case 3: /* bset*/ + fprintf(fp,"\t\t or %s,%s\n",EAXReg,ECXReg); + break; + } + + if ((mode !=0) && (type != 0)) + EffectiveAddressWrite(Dest,Size,EBX,FALSE,"---DS-B",TRUE); + + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } +} + +void bitdynamic(void) /* dynamic non-immediate bit operations*/ +{ + int type, sreg, mode, dreg ; + + for (sreg = 0 ; sreg < 8 ; sreg++) + for (type = 0 ; type < 4 ; type++) + for (mode = 0 ; mode < 8 ;mode++) + for (dreg = 0 ; dreg < 8 ;dreg++) + dump_bit_dynamic( sreg, type, mode, dreg ) ; +} + +void dump_bit_static(int type, int mode, int dreg ) +{ + int Opcode, BaseCode ; + char Size ; + char *EAXReg,*ECXReg, *Label ; + char allow[] = "0-2345678-------" ; + int Dest ; + + /* BTST allows x(PC) and x(PC,xr.s) - others do not */ + + if (type == 0) + { + allow[9] = '9'; + allow[10] = 'a'; + } + + Opcode = 0x0800 | (type<<6) | (mode<<3) | dreg ; + BaseCode = Opcode & 0x08f8 ; + if (mode == 7) BaseCode |= dreg ; + + // A7+, A7- + +#ifdef A7ROUTINE + if ((mode > 2) && (mode < 5)) + { + if (dreg == 7) BaseCode |= dreg; + } +#endif + + Dest = EAtoAMN(Opcode, FALSE); + + if (allow[Dest&0xf] != '-') + { + if (mode == 0) /* long*/ + { + /* Modify register memory directly */ + + Size = 'L' ; + EAXReg = REG_DAT_EBX; + ECXReg = regnameslong[ECX]; + } + else + { + Size = 'B' ; + EAXReg = regnamesshort[EAX]; + ECXReg = regnamesshort[ECX]; + } + + if (OpcodeArray[BaseCode] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + + /* Save Previous PC if Memory Access */ + + if ((Dest >= 2) && (Dest <=10)) + SavePreviousPC(); + + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + if (mode<2) + { + switch (type) + { + case 0: + TimingCycles += 10 ; + break ; + case 1: + case 3: + TimingCycles += 12 ; + break ; + case 2: + TimingCycles += 14 ; + break ; + } + } + else + { + if (type != 0) + TimingCycles += 12 ; + else + TimingCycles += 8 ; + } + + /* Only need this sorted out if a register is involved */ + + if (Dest < 7) + { + fprintf(fp, "\t\t mov ebx,ecx\n"); + fprintf(fp, "\t\t and ebx, byte 7\n"); + } + + /* Get bit number and create mask in ECX */ + + Memory_Fetch('W',ECX,FALSE); + fprintf(fp, "\t\t add esi,byte 2\n"); + + if (Size == 'L') + fprintf(fp, "\t\t and ecx, byte 31\n"); + else + fprintf(fp, "\t\t and ecx, byte 7\n"); + + #ifdef QUICKZERO + fprintf(fp,"\t\t mov eax,1\n"); + #else + fprintf(fp,"\t\t xor eax,eax\n"); + fprintf(fp,"\t\t inc eax\n"); + #endif + + fprintf(fp,"\t\t shl eax,cl\n"); + fprintf(fp,"\t\t mov ecx,eax\n"); + + if (mode != 0) + EffectiveAddressRead(Dest,Size,EBX,EAX,"-BCDSDB",TRUE); + + /* All commands copy existing bit to Zero Flag */ + + Label = GenerateLabel(0,1); + + fprintf(fp,"\t\t or edx,byte 40h\t; Set Zero Flag\n"); + fprintf(fp,"\t\t test %s,%s\n",EAXReg,ECXReg); + fprintf(fp,"\t\t jz short %s\n",Label); + fprintf(fp,"\t\t xor edx,byte 40h\t; Clear Zero Flag\n"); + fprintf(fp,"%s:\n",Label); + + /* Some then modify the data */ + + switch (type) + { + case 0: /* btst*/ + break; + + case 1: /* bchg*/ + fprintf(fp,"\t\t xor %s,%s\n",EAXReg,ECXReg); + break; + + case 2: /* bclr*/ + fprintf(fp,"\t\t not ecx\n"); + fprintf(fp,"\t\t and %s,%s\n",EAXReg,ECXReg); + break; + + case 3: /* bset*/ + fprintf(fp,"\t\t or %s,%s\n",EAXReg,ECXReg); + break; + } + + if ((mode !=0) && (type != 0)) + EffectiveAddressWrite(Dest,Size,EBX,FALSE,"---DS-B",TRUE); + + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } +} + + +void bitstatic(void) /* static non-immediate bit operations*/ +{ + int type, mode, dreg ; + + for (type = 0 ; type < 4 ; type++) + for (mode = 0 ; mode < 8 ;mode++) + for (dreg = 0 ; dreg < 8 ;dreg++) + dump_bit_static( type, mode, dreg ) ; +} + +/* + * Move Peripheral + * + */ + +void movep(void) +{ + int sreg,dir,leng,dreg ; + int Opcode, BaseCode ; + + for (sreg = 0 ; sreg < 8 ; sreg++) + { + for (dir = 0 ; dir < 2 ; dir++) + { + for (leng = 0 ; leng < 2 ; leng++) + { + for (dreg = 0 ; dreg < 8 ; dreg++) + { + Opcode = 0x0108 | (sreg<<9) | (dir<<7) | (leng<<6) | dreg; + BaseCode = Opcode & 0x01c8 ; + if (OpcodeArray[BaseCode] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + SavePreviousPC(); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + if (leng == 0) /* word */ + TimingCycles += 16 ; + else + TimingCycles += 24 ; + + /* Save Flags Register (so we only do it once) */ + + fprintf(fp, "\t\t push edx\n"); + + fprintf(fp, "\t\t mov ebx,ecx\n"); + fprintf(fp, "\t\t and ebx,byte 7\n"); + + /* Get Address to Read/Write in EDI */ + + EffectiveAddressCalculate(5,'L',EBX,FALSE); + + fprintf(fp, "\t\t shr ecx,byte 9\n"); + fprintf(fp, "\t\t and ecx,byte 7\n"); + + + if (dir == 0) /* from memory to register*/ + { + Memory_Read('B',EDI,"-BC-SDB",2); /* mask first call */ + fprintf(fp,"\t\t mov bh,al\n"); + fprintf(fp,"\t\t add edi,byte 2\n"); + Memory_Read('B',EDI,"-BC-SDB",0); /* not needed then */ + fprintf(fp,"\t\t mov bl,al\n"); + + if (leng == 0) /* word d(Ax) into Dx.W*/ + { + fprintf(fp,"\t\t mov [%s+ecx*4],bx\n",REG_DAT); + } + else /* long d(Ax) into Dx.L*/ + { + fprintf(fp,"\t\t add edi,byte 2\n"); + fprintf(fp,"\t\t shl ebx,16\n"); + Memory_Read('B',EDI,"-BC-SDB",0); + fprintf(fp,"\t\t mov bh,al\n"); + fprintf(fp,"\t\t add edi,byte 2\n"); + Memory_Read('B',EDI,"-BC-S-B",0); + fprintf(fp,"\t\t mov bl,al\n"); + fprintf(fp,"\t\t mov [%s+ecx*4],ebx\n",REG_DAT); + } + } + else /* Register to Memory*/ + { + fprintf(fp,"\t\t mov eax,[%s+ecx*4]\n",REG_DAT); + + /* Move bytes into Line */ + + if (leng == 1) + fprintf(fp,"\t\t rol eax,byte 8\n"); + else + fprintf(fp,"\t\t rol eax,byte 24\n"); + + Memory_Write('B',EDI,EAX,"A---SDB",2); /* Mask First */ + fprintf(fp,"\t\t add edi,byte 2\n"); + fprintf(fp,"\t\t rol eax,byte 8\n"); + + if (leng == 1) /* long*/ + { + Memory_Write('B',EDI,EAX,"A---SDB",0); + fprintf(fp,"\t\t add edi,byte 2\n"); + fprintf(fp,"\t\t rol eax,byte 8\n"); + Memory_Write('B',EDI,EAX,"A---SDB",0); + fprintf(fp,"\t\t add edi,byte 2\n"); + fprintf(fp,"\t\t rol eax,byte 8\n"); + } + Memory_Write('B',EDI,EAX,"A---S-B",0); + } + + fprintf(fp, "\t\t pop edx\n"); + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } + } + } + } +} + +void movecodes(int allowfrom[],int allowto[],int Start,char Size) /* MJC */ +{ + int Opcode; + int Src,Dest; + int SaveEDX; + int BaseCode; + + for (Opcode=Start;Opcode> 6, TRUE); + + if ((allowfrom[(Src & 15)]) && (allowto[(Dest & 15)])) + { + /* If we are not going to calculate the flags */ + /* we need to preserve the existing ones */ + + SaveEDX = (Dest == 1); + + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + + if (((Src >= 2) && (Src <= 10)) || ((Dest >= 2) && (Dest <=10))) + SavePreviousPC(); + + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + + TimingCycles += 4 ; + + if (Src < 7) + { + if (Dest < 7) + { + fprintf(fp, "\t\t mov ebx,ecx\n"); + + if ((Src == 0) && allowfrom[1]) + fprintf(fp, "\t\t and ebx,byte 15\n"); + else + fprintf(fp, "\t\t and ebx,byte 7\n"); + + EffectiveAddressRead(Src,Size,EBX,EAX,"--CDS-B",SaveEDX); + } + else + { + if ((Src == 0) && allowfrom[1]) + fprintf(fp, "\t\t and ecx,byte 15\n"); + else + fprintf(fp, "\t\t and ecx,byte 7\n"); + + EffectiveAddressRead(Src,Size,ECX,EAX,"---DS-B",SaveEDX); + } + } + else + { + if (Dest < 7) + EffectiveAddressRead(Src,Size,EBX,EAX,"--CDS-B",SaveEDX); + else + EffectiveAddressRead(Src,Size,EBX,EAX,"---DS-B",SaveEDX); + } + + /* No flags if Destination Ax */ + + if (!SaveEDX) + { + SetFlags(Size,EAX,TRUE,FALSE,TRUE); + } + + if (Dest < 7) + { + fprintf(fp, "\t\t shr ecx,9\n"); + fprintf(fp, "\t\t and ecx,byte 7\n"); + } + + EffectiveAddressWrite(Dest,Size,ECX,TRUE,"---DS-B",SaveEDX); + + Completed(); + } + else + { + BaseCode = -1; /* Invalid Code */ + } + } + else + { + BaseCode = OpcodeArray[BaseCode]; + } + + if (OpcodeArray[Opcode] < 0) + OpcodeArray[Opcode] = BaseCode; + } +} + +void moveinstructions(void) +{ + int allowfrom[] = {1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0}; + int allowto[] = {1,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0}; + + /* For Byte */ + + movecodes(allowfrom,allowto,0x1000,'B'); + + /* For Word & Long */ + + allowto[1] = 1; + movecodes(allowfrom,allowto,0x2000,'L'); + movecodes(allowfrom,allowto,0x3000,'W'); +} + +/* + * + * Opcodes 5### + * + * ADDQ,SUBQ,Scc and DBcc + * + */ + +void opcode5(void) +{ + /* ADDQ,SUBQ,Scc and DBcc */ + + int allowtoScc[] = {1,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0}; + int allowtoADDQ[] = {1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0}; + int Opcode,BaseCode; + char Label[32]; + char Label2[32]; + char Size=' '; + char* Regname=""; + char* RegnameECX=""; + + for (Opcode = 0x5000;Opcode < 0x6000;Opcode++) + { + if ((Opcode & 0xc0) == 0xc0) + { + /* Scc or DBcc */ + + BaseCode = Opcode & 0x5FF8; + if ((BaseCode & 0x38) == 0x38) BaseCode |= (Opcode & 7); + + /* If mode = 3 or 4 and register = A7 */ + /* then make it a separate code */ + +#ifdef A7ROUTINE + if (((Opcode & 0x3F) == 0x1F) || ((Opcode & 0x3F) == 0x27)) + { + BaseCode |= 0x07; + } +#endif + + if (OpcodeArray[BaseCode] == -2) + { + OpcodeArray[BaseCode] = BaseCode; + + if ((BaseCode & 0x38) == 0x8) + { + /* DBcc */ + + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + + TimingCycles += 10 ; + + + strcpy(Label,GenerateLabel(BaseCode,1)) ; + strcpy(Label2,ConditionDecode((Opcode >> 8) & 0x0F,TRUE)); + + /* False - Decrement Counter - Loop if not -1 */ + + fprintf(fp, "\t\t and ecx,byte 7\n"); + fprintf(fp, "\t\t mov ax,[%s+ecx*4]\n",REG_DAT); + fprintf(fp, "\t\t dec ax\n"); + fprintf(fp, "\t\t mov [%s+ecx*4],ax\n",REG_DAT); + fprintf(fp, "\t\t inc ax\t\t; Is it -1\n"); + fprintf(fp, "\t\t jz short %s\n",Label); + + fprintf(fp, "\t\t add esi,byte 2\n\n"); + Memory_Fetch('W',EAX,TRUE); + fprintf(fp, "\t\t add esi,eax\n"); + Completed(); + + /* True - Exit Loop */ + fprintf(fp, "%s:\n",Label); + + fprintf(fp, "%s:\n",Label2); + fprintf(fp, "\t\t add esi,byte 4\n"); + TimingCycles += 2 ; + + Completed(); + } + else + { + /* Scc */ + + int Dest = EAtoAMN(Opcode, FALSE); + + if (allowtoScc[(Dest & 15)]) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + + if ((Dest >= 2) && (Dest <=10)) + SavePreviousPC(); + + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + if (Dest > 1) + TimingCycles += 8 ; + else + TimingCycles += 4 ; + + if (Dest < 7) + { + fprintf(fp, "\t\t and ecx,byte 7\n"); + } + + if (Dest > 1) + { + EffectiveAddressCalculate(Dest,'B',ECX,TRUE); + /* ASG - no longer need to mask addresses here */ +/* fprintf(fp,"\t\t and edi,0FFFFFFh\n");*/ + } + + ConditionCheck((Opcode >> 8) & 0x0F,"AL"); + + EffectiveAddressWrite(Dest,'B',ECX,FALSE,"---DS-B",TRUE); + + /* take advantage of AL being 0 for false, 0xff for true */ + /* need to add 2 cycles if register and condition is true */ + + if (Dest == 0) + { + fprintf(fp, "\t\t and eax,byte 2\n"); + fprintf(fp, "\t\t add eax,byte %d\n",TimingCycles); + fprintf(fp, "\t\t sub dword [%s],eax\n",ICOUNT); + + TimingCycles = -1; + } + Completed(); + } + else + { + OpcodeArray[BaseCode] = -1; + BaseCode = -1; + } + } + } + else + { + BaseCode = OpcodeArray[BaseCode]; + } + + OpcodeArray[Opcode] = BaseCode; + } + else + { + /* ADDQ or SUBQ */ + + BaseCode = Opcode & 0x51F8; + if ((BaseCode & 0x38) == 0x38) BaseCode |= (Opcode & 7); + + /* Special for Address Register Direct - Force LONG */ + + if ((Opcode & 0x38) == 0x8) BaseCode = ((BaseCode & 0xFF3F) | 0x80); + + + /* If mode = 3 or 4 and Size = byte and register = A7 */ + /* then make it a separate code */ + +#ifdef A7ROUTINE + if ((Opcode & 0xC0) == 0) + { + if (((Opcode & 0x3F) == 0x1F) || ((Opcode & 0x3F) == 0x27)) + { + BaseCode |= 0x07; + } + } +#endif + + if (OpcodeArray[BaseCode] == -2) + { + char *Operation; + int Dest = EAtoAMN(Opcode, FALSE); + int SaveEDX = (Dest == 1); + + if (allowtoADDQ[(Dest & 15)]) + { + switch (BaseCode & 0xC0) + { + case 0: + Size = 'B'; + Regname = regnamesshort[0]; + RegnameECX = regnamesshort[ECX]; + break; + + case 0x40: + Size = 'W'; + Regname = regnamesword[0]; + RegnameECX = regnamesword[ECX]; + break; + + case 0x80: + Size = 'L'; + Regname = regnameslong[0]; + RegnameECX = regnameslong[ECX]; + break; + } + + OpcodeArray[BaseCode] = BaseCode; + + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + + if ((Dest >= 2) && (Dest <=10)) + SavePreviousPC(); + + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + if (Dest == 0) /* write to Dx */ + { + if (Size != 'L') + TimingCycles += 4 ; + else + TimingCycles += 8 ; + } + + if (Dest == 1) + { + if ((Size == 'L') || (Opcode & 0x100)) /* if long or SUBQ */ + TimingCycles += 8 ; + else + TimingCycles += 4 ; + } + + if (Dest > 1) /* write to mem */ + { + if (Size != 'L') + TimingCycles += 8 ; + else + TimingCycles += 12 ; + } + + if (Dest < 7) + { + fprintf(fp, "\t\t mov ebx,ecx\n"); + fprintf(fp, "\t\t and ebx,byte 7\n"); + } + + if (Dest > 1) + { + EffectiveAddressRead(Dest,Size,EBX,EAX,"-BCDSDB",SaveEDX); + } + + /* Sub Immediate from Opcode */ + + fprintf(fp, "\t\t shr ecx,9\n"); + + Immediate8(); + + if (Opcode & 0x100) + { + /* SUBQ */ + Operation = "sub"; + } + else + { + /* ADDQ */ + Operation = "add"; + } + + /* For Data or Address register, operate directly */ + /* on the memory location. Don't load into EAX */ + + if (Dest < 2) + { + if (Dest == 0) + { + fprintf(fp, "\t\t %s [%s+ebx*4],%s\n",Operation,REG_DAT,RegnameECX); + } + else + { + fprintf(fp, "\t\t %s [%s+ebx*4],%s\n",Operation,REG_ADD,RegnameECX); + } + } + else + { + fprintf(fp, "\t\t %s %s,%s\n",Operation,Regname,RegnameECX); + } + + /* No Flags for Address Direct */ + + if (!SaveEDX) + { + /* Directly after ADD or SUB, so test not needed */ + + SetFlags(Size,EAX,FALSE,TRUE,TRUE); + } + + if (Dest > 1) + { + EffectiveAddressWrite(Dest,Size,EBX,FALSE,"---DS-B",FALSE); + } + + Completed(); + } + else + { + OpcodeArray[BaseCode] = -1; + BaseCode = -1; + } + } + else + { + BaseCode = OpcodeArray[BaseCode]; + } + + OpcodeArray[Opcode] = BaseCode; + } + } +} + +/* + * Branch Instructions + * + * BSR, Bcc + * + */ + +void branchinstructions(void) +{ + int Opcode,BaseCode; + int Counter; + char *Label; + char jmpLabel[40] ; + + for (Opcode = 0x60;Opcode < 0x70;Opcode++) + { + /* Displacement = 0 -> 16 Bit displacement */ + + BaseCode = Opcode * 0x100; + OpcodeArray[BaseCode] = BaseCode; + + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + TimingCycles += 10 ; + + if (Opcode == 0x60) + { + Memory_Fetch('W',EAX,TRUE); + fprintf(fp, "\t\t add esi,eax\n"); + MemoryBanking(BaseCode); + Completed(); + } + else + { + if (Opcode != 0x61) + { + Label = ConditionDecode(Opcode & 0x0F,TRUE); + + /* Code for Failed branch */ + + fprintf(fp, "\t\t add esi,byte 2\n"); + + /* 2 less cycles for Failure */ + + TimingCycles -= 2; + Completed(); + TimingCycles += 2; + + /* Successful Branch */ + + Align(); + fprintf(fp, "%s:\n",Label); + + Memory_Fetch('W',EAX,TRUE); + fprintf(fp, "\t\t add esi,eax\n"); + MemoryBanking(BaseCode+2); + Completed(); + + } + else + { + /* BSR - Special Case */ + + TimingCycles += 8 ; + + Memory_Fetch('W',EBX,TRUE); + fprintf(fp, "\t\t add ebx,esi\n"); + + fprintf(fp, "\t\t add esi,byte 2\n"); + PushPC(ECX,EAX,"-B-DS-B",1); + + fprintf(fp, "\t\t mov esi,ebx\n"); + MemoryBanking(BaseCode+3); + Completed(); + } + } + + /* 8 Bit Displacement */ + + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode+1,0)); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + TimingCycles += 10 ; + + if (Opcode > 0x60) + { + if (Opcode != 0x61) + { + Label = ConditionDecode(Opcode & 0x0F,TRUE); + + /* Code for Failed branch */ + + TimingCycles -= 2; + Completed(); + TimingCycles += 2; + + /* Successful Branch */ + + Align(); + fprintf(fp, "%s:\n",Label); + } + else + { + /* BSR - Special Case */ + + TimingCycles += 8 ; + + PushPC(EDI,EBX,"--CDS-B",1); + } + } + + /* Common Ending */ + + fprintf(fp, "\t\t movsx eax,cl ; Sign Extend displacement\n"); + fprintf(fp, "\t\t add esi,eax\n"); + MemoryBanking(BaseCode+5); + Completed(); + + /* Fill up Opcode Array */ + + for (Counter=1;Counter<0x100;Counter++) + OpcodeArray[BaseCode+Counter] = BaseCode+1; + + if(CPU==2) + { + + /* 8 bit 0xff & 68020 instruction - 32 bit displacement */ + + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode+0xff,0)); + sprintf( jmpLabel, GenerateLabel(BaseCode+0xff,1) ) ; + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + TimingCycles += 10 ; + + if (Opcode == 0x60) + { + /* bra - always branch */ + Memory_Fetch('L',EAX,FALSE); + fprintf(fp, "\t\t add esi,eax\n"); + MemoryBanking(BaseCode+6); + Completed(); + } + else + { + if (Opcode != 0x61) + { + Label = ConditionDecode(Opcode & 0x0F,TRUE); + + /* Code for Failed branch */ + fprintf(fp, "\t\t add esi,byte 4\n"); + + TimingCycles -= 2; + Completed(); + TimingCycles += 2; + + /* Successful Branch */ + Align(); + fprintf(fp, "%s:\n",Label); + + Memory_Fetch('L',EAX,FALSE); + fprintf(fp, "\t\t add esi,eax\n"); + MemoryBanking(BaseCode+8); + Completed(); + } + else + { + /* BSR - Special Case */ + + TimingCycles += 8 ; + + Memory_Fetch('L',EBX,TRUE); + fprintf(fp, "\t\t add ebx,esi\n"); + + fprintf(fp, "\t\t add esi,byte 4\n"); + PushPC(ECX,EAX,"-B-DS-B",1); + + fprintf(fp, "\t\t mov esi,ebx\n"); + MemoryBanking(BaseCode+9); + Completed(); + } + } + + OpcodeArray[BaseCode+0xff] = BaseCode+0xff; + } + } +} + +/* + * Move Quick Commands + * + * Fairly simple, as only allowed to Data Registers + * + */ + +void moveq(void) +{ + int Count; + + /* The Code */ + + Align(); + fprintf(fp, "%s:\n",GenerateLabel(0x7000,0)); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + TimingCycles += 4 ; + + fprintf(fp, "\t\t movsx eax,cl\n"); + fprintf(fp, "\t\t shr ecx,9\n"); + fprintf(fp, "\t\t and ecx,byte 7\n"); + SetFlags('L',EAX,TRUE,FALSE,FALSE); + EffectiveAddressWrite(0,'L',ECX,TRUE,"---DS-B",FALSE); + Completed(); + + /* Set OpcodeArray (Not strictly correct, since some are illegal!) */ + + for (Count=0x7000;Count<0x8000;Count++) + { + OpcodeArray[Count] = 0x7000; + } +} + +/* + * Extended version of Add & Sub commands + * + */ + +void addx_subx(void) +{ + int Opcode, BaseCode ; + int regx,type,leng,rm,regy,mode ; + int ModeModX; + int ModeModY; + char Size=' ' ; + char * Regname="" ; + char * RegnameEBX="" ; + char * Operand=""; + char * Label; + + for (type = 0 ; type < 2 ; type ++) /* 0=subx, 1=addx */ + for (regx = 0 ; regx < 8 ; regx++) + for (leng = 0 ; leng < 3 ; leng++) + for (rm = 0 ; rm < 2 ; rm++) + for (regy = 0 ; regy < 8 ; regy++) + { + Opcode = 0x9100 | (type<<14) | (regx<<9) | (leng<<6) | (rm<<3) | regy ; + + BaseCode = Opcode & 0xd1c8 ; + + ModeModX = 0; + ModeModY = 0; + +#ifdef A7ROUTINE + if ((rm == 1) && (leng == 0)) + { + if (regx == 7) + { + BaseCode |= (regx << 9); + ModeModY = 16; + } + if (regy == 7) + { + BaseCode |= regy; + ModeModX = 16; + } + } +#endif + + if (rm == 0) + mode = 0 ; + else + mode = 4 ; + + switch (leng) + { + case 0: + Size = 'B'; + Regname = regnamesshort[0]; + RegnameEBX = regnamesshort[EBX]; + break; + case 1: + Size = 'W'; + Regname = regnamesword[0]; + RegnameEBX = regnamesword[EBX]; + break; + case 2: + Size = 'L'; + Regname = regnameslong[0]; + RegnameEBX = regnameslong[EBX]; + break; + } + + if (OpcodeArray[BaseCode] == -2) + { + if (type == 0) + Operand = "sbb"; + else + Operand = "adc"; + + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + + if (mode == 4) + SavePreviousPC(); + + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + /* don't add in EA timing for ADDX,SUBX */ + + AddEACycles = 0 ; + + if (rm == 0) /* reg to reg */ + { + if (Size != 'L') + TimingCycles += 4 ; + else + TimingCycles += 8 ; + } + else + { + if (Size != 'L') + TimingCycles += 18 ; + else + TimingCycles += 30 ; + } + + fprintf(fp, "\t\t mov ebx,ecx\n"); + fprintf(fp, "\t\t and ebx, byte 7\n"); + fprintf(fp, "\t\t shr ecx, byte 9\n"); + fprintf(fp, "\t\t and ecx, byte 7\n"); + + /* Get Source */ + + EffectiveAddressRead(mode+ModeModX,Size,EBX,EBX,"--CDS-B",FALSE); + + /* Get Destination (if needed) */ + + if (mode == 4) + EffectiveAddressRead(mode+ModeModY,Size,ECX,EAX,"-BCDSDB",FALSE); + + /* Copy the X flag into the Carry Flag */ + + CopyX(); + + /* Do the sums */ + + if (mode == 0) + fprintf(fp, "\t\t %s [%s+ecx*4],%s\n",Operand,REG_DAT,RegnameEBX); + else + fprintf(fp, "\t\t %s %s,%s\n",Operand,Regname,RegnameEBX); + + /* Preserve old Z flag */ + + fprintf(fp, "\t\t mov ebx,edx\n"); + + /* Set the Flags */ + + SetFlags(Size,EAX,FALSE,TRUE,FALSE); + + /* Handle the Z flag */ + + Label = GenerateLabel(0,1); + + fprintf(fp, "\t\t jnz short %s\n\n",Label); + + fprintf(fp, "\t\t and dl,0BFh ; Remove Z\n"); + fprintf(fp, "\t\t and bl,40h ; Mask out Old Z\n"); + fprintf(fp, "\t\t or dl,bl ; Copy across\n\n"); + fprintf(fp, "%s:\n",Label); + + /* Update the Data (if needed) */ + + if (mode == 4) + EffectiveAddressWrite(mode,Size,ECX,FALSE,"---DS-B",TRUE); + + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } +} + +/* + * Logicals / Simple Maths (+ and -) + * + * OR,AND,CMP,EOR,ADD and SUB + * + */ + +void dumpx( int start, int reg, int type, char * Op, int dir, int leng, int mode, int sreg ) +{ + int Opcode,BaseCode ; + char Size=' ' ; + char * RegnameECX="" ; + char * Regname="" ; + int Dest ; + int SaveEDX ; + int SaveDir; + char * allow="" ; + char * allowtypes[] = { "0-23456789ab----", "--2345678-------", + "0123456789ab----", "0-2345678-------"}; + + SaveDir = dir; + + switch (type) + { + case 0: /* or and*/ + if (dir == 0) + allow = allowtypes[0]; + else + allow = allowtypes[1]; + break ; + + case 1: /* cmp*/ + allow = allowtypes[2] ; + break ; + + case 2: /* eor*/ + allow = allowtypes[3] ; + break ; + + case 3: /* adda suba cmpa*/ + allow = allowtypes[2] ; + break ; + + case 4: /* sub add*/ + if (dir == 0) + allow = allowtypes[0] ; + else + allow = allowtypes[1] ; + break ; + } + + if ((type == 4) && (dir == 0) && (leng > 0)) + { + allow = allowtypes[2] ; /* word and long ok*/ + } + + Opcode = start | (reg << 9 ) | (dir<<8) | (leng<<6) | (mode<<3) | sreg; + + BaseCode = Opcode & 0xf1f8; + + if (mode == 7) BaseCode |= sreg ; + +#ifdef A7ROUTINE + if ((mode == 3 || mode == 4) && ( leng == 0 ) && (sreg == 7 )) + BaseCode |= sreg ; +#endif + + + + /* If Source = Data or Address register - combine into same routine */ + + if (((Opcode & 0x38) == 0x08) && (allow[1] != '-')) + { + BaseCode &= 0xfff7; + } + + Dest = EAtoAMN(Opcode, FALSE); + SaveEDX = (Dest == 1) || (type == 3); + + if (allow[Dest&0xf] != '-') + { + if (OpcodeArray[BaseCode] == -2) + { + switch (leng) + { + case 0: + Size = 'B'; + Regname = regnamesshort[0]; + RegnameECX = regnamesshort[ECX]; + break; + case 1: + Size = 'W'; + Regname = regnamesword[0]; + RegnameECX = regnamesword[ECX]; + break; + case 2: + Size = 'L'; + Regname = regnameslong[0]; + RegnameECX = regnameslong[ECX]; + break; + + case 3: /* cmpa adda suba */ + if (dir == 0) + { + Size = 'W'; + Regname = regnamesword[0]; + RegnameECX = regnamesword[ECX]; + } + else + { + Size = 'L'; + Regname = regnameslong[0]; + RegnameECX = regnameslong[ECX]; + } + dir = 0 ; + break ; + } + + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + + if ((Dest >= 2) && (Dest <=10)) + SavePreviousPC(); + + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + if (dir==0) + { + if (Size != 'L') + TimingCycles += 4; + else + TimingCycles += 6; + } + else + { + if (Size != 'L') + TimingCycles += 8; + else + TimingCycles += 12; + } + + if ((mode == 0) && (dir==0) && (Size == 'L')) + TimingCycles += 2 ; + + if ((mode == 1) && (dir==0) && (Size != 'L')) + TimingCycles += 4 ; + + if (Dest < 7) /* Others do not need reg.no. */ + { + fprintf(fp, "\t\t mov ebx,ecx\n"); + + if ((Dest == 0) & (allow[1] != '-')) + fprintf(fp, "\t\t and ebx,byte 15\n"); + else + fprintf(fp, "\t\t and ebx,byte 7\n"); + } + + fprintf(fp, "\t\t shr ecx,byte 9\n"); + fprintf(fp, "\t\t and ecx,byte 7\n"); + + EffectiveAddressRead(Dest,Size,EBX,EAX,"-BCDSDB",SaveEDX); + + if (dir == 0) + { + if (type != 3) + { + fprintf(fp, "\t\t %s [%s+ECX*4],%s\n",Op ,REG_DAT ,Regname ) ; + + if (type == 4) + SetFlags(Size,EAX,FALSE,TRUE,FALSE); + else + SetFlags(Size,EAX,FALSE,FALSE,FALSE); + } + else + { + if (Size == 'W') + fprintf(fp, "\t\t cwde\n"); + + fprintf(fp, "\t\t %s [%s+ECX*4],EAX\n",Op ,REG_ADD); + + if (Op[0] == 'c') + { + SetFlags('L',EAX,FALSE,FALSE,FALSE); + } + } + } + else + { + fprintf(fp, "\t\t %s %s,[%s+ECX*4]\n", Op, Regname ,REG_DAT ) ; + + if (type == 4) + SetFlags(Size,EAX,FALSE,TRUE,TRUE); + else + SetFlags(Size,EAX,FALSE,FALSE,TRUE); + + EffectiveAddressWrite(Dest,Size,EBX,FALSE,"---DS-B",FALSE); + } + Completed(); + } + + OpcodeArray[Opcode] = BaseCode; + } + + dir = SaveDir; +} + +void typelogicalmath(void) +{ + int dir, leng, mode, sreg ,reg ; + + for (reg = 0 ; reg < 8 ; reg++) + { + /* or */ + for (dir = 0 ; dir < 2 ; dir++) + for (leng = 0 ; leng < 3; leng++) + for (mode = 0 ; mode < 8 ; mode++) + for (sreg = 0 ; sreg < 8 ; sreg++) + dumpx( 0x8000, reg, 0, "or ", dir, leng, mode, sreg ) ; + + /* sub */ + for (dir = 0 ; dir < 2 ; dir++) + for (leng = 0 ; leng < 3; leng++) + for (mode = 0 ; mode < 8 ; mode++) + for (sreg = 0 ; sreg < 8 ; sreg++) + dumpx( 0x9000, reg, 4, "sub", dir, leng, mode, sreg ) ; + + /* suba */ + + for (dir = 0 ; dir < 2 ; dir++) + for (mode = 0 ; mode < 8 ; mode++) + for (sreg = 0 ; sreg < 8 ; sreg++) + dumpx( 0x9000, reg, 3, "sub", dir, 3, mode, sreg ) ; + + + /* cmp */ + for (leng = 0 ; leng < 3; leng++) + for (mode = 0 ; mode < 8 ; mode++) + for (sreg = 0 ; sreg < 8 ; sreg++) + dumpx( 0xb000, reg, 1, "cmp", 0, leng, mode, sreg ) ; + + /* cmpa */ + + for (dir = 0 ; dir < 2 ; dir++) + for (mode = 0 ; mode < 8 ; mode++) + for (sreg = 0 ; sreg < 8 ; sreg++) + dumpx( 0xb000, reg, 3, "cmp", dir, 3, mode, sreg ) ; + + /* adda */ + + for (dir = 0 ; dir < 2 ; dir++) + for (mode = 0 ; mode < 8 ; mode++) + for (sreg = 0 ; sreg < 8 ; sreg++) + dumpx( 0xd000, reg, 3, "add", dir, 3, mode, sreg ) ; + + + /* eor */ + for (leng = 0 ; leng < 3; leng++) + for (mode = 0 ; mode < 8 ; mode++) + for (sreg = 0 ; sreg < 8 ; sreg++) + dumpx( 0xb100, reg, 2, "xor", 1, leng, mode, sreg ) ; + + /* and */ + for (dir = 0 ; dir < 2 ; dir++) + for (leng = 0 ; leng < 3; leng++) + for (mode = 0 ; mode < 8 ; mode++) + for (sreg = 0 ; sreg < 8 ; sreg++) + dumpx( 0xc000, reg, 0, "and", dir, leng, mode, sreg ) ; + + /* add */ + for (dir = 0 ; dir < 2 ; dir++) + for (leng = 0 ; leng < 3; leng++) + for (mode = 0 ; mode < 8 ; mode++) + for (sreg = 0 ; sreg < 8 ; sreg++) + dumpx( 0xd000, reg, 4, "add", dir, leng, mode, sreg ) ; + } +} + +/* + * Single commands missed out by routines above + * + */ + +void mul(void) +{ + int dreg, type, mode, sreg ; + int Opcode, BaseCode ; + int Dest ; + char allow[] = "0-23456789ab-----" ; + + for (dreg = 0 ; dreg < 8 ; dreg++) + for (type = 0 ; type < 2 ; type++) + for (mode = 0 ; mode < 8 ; mode++) + for (sreg = 0 ; sreg < 8 ; sreg++) + { + Opcode = 0xc0c0 | (dreg<<9) | (type<<8) | (mode<<3) | sreg ; + BaseCode = Opcode & 0xc1f8 ; + if (mode == 7) + { + BaseCode |= sreg ; + } + + Dest = EAtoAMN(Opcode, FALSE); + if (allow[Dest&0x0f] != '-') + { + if (OpcodeArray[ BaseCode ] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + + if ((Dest >= 2) && (Dest <=10)) + SavePreviousPC(); + + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + TimingCycles += 70 ; + + if (mode < 7) + { + fprintf(fp, "\t\t mov ebx,ecx\n"); + fprintf(fp, "\t\t and ebx,byte 7\n"); + } + + fprintf(fp, "\t\t shr ecx, byte 9\n"); + fprintf(fp, "\t\t and ecx, byte 7\n"); + + EffectiveAddressRead(Dest,'W',EBX,EAX,"ABCDSDB",FALSE); + + if (type == 0) + fprintf(fp, "\t\t mul word [%s+ECX*4]\n",REG_DAT); + else + fprintf(fp, "\t\t imul word [%s+ECX*4]\n",REG_DAT); + + fprintf(fp, "\t\t shl edx, byte 16\n"); + fprintf(fp, "\t\t mov dx,ax\n"); + fprintf(fp, "\t\t mov [%s+ECX*4],edx\n",REG_DAT); + SetFlags('L',EDX,TRUE,FALSE,FALSE); + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } + } +} + +void mull(void) +{ + int mode, sreg ; + int Opcode, BaseCode ; + int Dest ; + char allow[] = "0-23456789ab-----" ; + char *Label = NULL ; + + for (mode = 0 ; mode < 8 ; mode++) + for (sreg = 0 ; sreg < 8 ; sreg++) + { + Opcode = 0x4c00 | (mode<<3) | sreg ; + BaseCode = Opcode & 0x4c38 ; + if (mode == 7) + { + BaseCode |= sreg ; + } + + Dest = EAtoAMN(Opcode, FALSE); + if (allow[Dest&0x0f] != '-') + { + if (OpcodeArray[ BaseCode ] == -2) + { + TimingCycles += 70 ; + Align(); + Label = GenerateLabel(BaseCode,0); + fprintf(fp, "%s:\n",Label); + if ((Dest >= 2) && (Dest <=10)) + SavePreviousPC(); + + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + if (mode < 7) + { + fprintf(fp, "\t\t and ecx,byte 7\n"); + } + + Memory_Fetch('W', EBX, FALSE ); // fetch the next word + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + EffectiveAddressRead(Dest,'L',ECX,EAX,"ABCDSDB",FALSE); // read from the EA + + fprintf(fp, "\t\t mov ecx,ebx\n"); // save 2nd word in ecx + fprintf(fp, "\t\t shr ebx,12\n"); // ebx = Dl register + fprintf(fp, "\t\t and ebx,7\n"); // 0-7 + + Label = GenerateLabel(BaseCode,1); + + fprintf(fp, "\t\t test ecx,0x0800\n"); // signed/unsigned? + fprintf(fp, "\t\t jz short %s\n",Label); // skip if unsigned + + fprintf(fp, "\t\t imul dword [%s+EBX*4]\n",REG_DAT); // signed 32x32->64 + fprintf(fp, "\t\t jmp short %s_1\n",Label); // skip + + fprintf(fp, "%s:\n",Label); + fprintf(fp, "\t\t mul dword [%s+EBX*4]\n",REG_DAT); // unsigned 32x32->64 + + fprintf(fp, "%s_1:\n",Label); + fprintf(fp, "\t\t mov [%s+EBX*4],eax\n",REG_DAT); // store Dl back + + fprintf(fp, "\t\t test ecx,0x0400\n"); // do we care? + fprintf(fp, "\t\t jz short %s_2\n",Label); // if not, skip + fprintf(fp, "\t\t and ecx,7\n"); // get Dh register + fprintf(fp, "\t\t mov [%s+ECX*4],edx\n",REG_DAT); // store upper 32 bits + SetFlags('L',EDX,TRUE,FALSE,FALSE); // set the flags + fprintf(fp, "\t\t and edx,~0x0800\n"); // clear the overflow + fprintf(fp, "\t\t jmp short %s_3\n",Label); // skip + + fprintf(fp, "%s_2:\n",Label); + fprintf(fp, "\t\t mov ebx,edx\n"); // save upper 32 in ebx + SetFlags('L',EAX,TRUE,FALSE,FALSE); // set the flags + fprintf(fp, "\t\t sar eax,31\n"); // eax = sign-extended + fprintf(fp, "\t\t test ecx,0x0800\n"); // signed/unsigned? + fprintf(fp, "\t\t jnz short %s_4\n",Label); // skip if signed + fprintf(fp, "\t\t xor eax,eax\n"); // always use 0 for unsigned + fprintf(fp, "%s_4:\n",Label); + fprintf(fp, "\t\t cmp eax,ebx\n"); // compare upper 32 against eax + fprintf(fp, "\t\t je short %s_3\n",Label); // if equal to sign extension, skip + fprintf(fp, "\t\t or edx,0x0800\n"); // set the overflow + + fprintf(fp, "%s_3:\n",Label); + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } + } +} + +void divl(void) +{ + int mode, sreg ; + int Opcode, BaseCode ; + int Dest ; + char allow[] = "0-23456789ab-----" ; + char *Label = NULL ; + + for (mode = 0 ; mode < 8 ; mode++) + for (sreg = 0 ; sreg < 8 ; sreg++) + { + Opcode = 0x4c40 | (mode<<3) | sreg ; + BaseCode = Opcode & 0x4c78 ; + if (mode == 7) + { + BaseCode |= sreg ; + } + + Dest = EAtoAMN(Opcode, FALSE); + if (allow[Dest&0x0f] != '-') + { + if (OpcodeArray[ BaseCode ] == -2) + { + TimingCycles += 70 ; + Align(); + Label = GenerateLabel(BaseCode,0); + fprintf(fp, "%s:\n",Label); + if ((Dest >= 2) && (Dest <=10)) + SavePreviousPC(); + + fprintf(fp, "\t\t push edx\n"); // save edx + fprintf(fp, "\t\t add esi,byte 2\n\n"); + fprintf(fp, "\t\t and ecx,byte 7\n"); // read from ea + + Memory_Fetch('W', EDX, FALSE ); // fetch 2nd word in ecx + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + EffectiveAddressRead(Dest,'L',ECX,EBX,"---DSDB",FALSE); + + fprintf(fp, "\t\t push esi\n"); // save and 0 esi + ClearRegister(ESI); + + Label = GenerateLabel(BaseCode,1); + + fprintf(fp, "\t\t test ebx,ebx\n"); // check divisor against 0 + fprintf(fp, "\t\t jz near %s_ZERO\n",Label); // handle divide-by-zero +// low part always used + fprintf(fp, "\t\t mov ecx,edx\n"); // ecx = extension word + fprintf(fp, "\t\t shr edx,12\n"); // edx = Dq register + fprintf(fp, "\t\t and edx,7\n"); // 0-7 + fprintf(fp, "\t\t mov eax,[%s+edx*4]\n",REG_DAT); // eax = Dq register value + + ClearRegister(EDX); // edx = 0 + fprintf(fp, "\t\t test ecx,0x0400\n"); // check size + fprintf(fp, "\t\t jz short %s_1\n",Label); // skip if 32-bit dividend +// high longword (64bit) + fprintf(fp, "\t\t mov edx,ecx\n"); // edx = extension word + fprintf(fp, "\t\t and edx,7\n"); // 0-7 + fprintf(fp, "\t\t mov edx,[%s+edx*4]\n",REG_DAT); // fetch upper 32-bits + + fprintf(fp, "\t\t test ecx,0x0800\n"); // signed? + fprintf(fp, "\t\t jz near %s_3\n",Label); // if not, skip to unsigned 64-bit + fprintf(fp, "\t\t jmp near %s_2\n",Label); // skip to signed 64-bit case + + fprintf(fp, "%s_1:\n",Label); // short case + ClearRegister(EDX); // clear edx + fprintf(fp, "\t\t test ecx,0x0800\n"); // signed? + fprintf(fp, "\t\t jz short %s_3\n",Label); // if not, don't convert + fprintf(fp, "\t\t cdq\n"); // sign extend into edx +// signed + fprintf(fp, "%s_2:\n",Label); // signed 32/64-bit case + fprintf(fp, "\t\t or esi,1\n"); // esi |= 1 to indicate signed + fprintf(fp, "\t\t test ebx,ebx\n"); // check divisor sign + fprintf(fp, "\t\t jge short %s_2b\n",Label); // if >= 0, don't set + fprintf(fp, "\t\t or esi,2\n"); // esi |= 2 to indicate negative divisor + fprintf(fp, "\t\t neg ebx\n"); // make positive + fprintf(fp, "%s_2b:\n",Label); + fprintf(fp, "\t\t test edx,edx\n"); // check dividend sign + fprintf(fp, "\t\t jge short %s_3\n",Label); // if >= 0, don't set + fprintf(fp, "\t\t push ebx\n"); // save ebx + fprintf(fp, "\t\t push ecx\n"); // save ecx + ClearRegister(EBX); // clear ebx + ClearRegister(ECX); // clear ecx + fprintf(fp, "\t\t sub ebx,eax\n"); // ebx = 0 - eax + fprintf(fp, "\t\t sbb ecx,edx\n"); // ecx = 0 - edx + fprintf(fp, "\t\t mov eax,ebx\n"); // eax = ebx + fprintf(fp, "\t\t mov edx,ecx\n"); // edx = ecx + fprintf(fp, "\t\t pop ecx\n"); // restore ecx + fprintf(fp, "\t\t pop ebx\n"); // restore ebx + fprintf(fp, "\t\t or esi,4\n"); // esi |= 4 to indicate negative dividend +// unsigned + fprintf(fp, "%s_3:\n",Label); // unsigned 32/64-bit case + fprintf(fp, "\t\t cmp ebx,edx\n"); // check ebx against upper 32 bits + fprintf(fp, "\t\t jbe near %s_OVERFLOW\n",Label); // generate overflow + fprintf(fp, "\t\t div ebx\n"); // do the divide + fprintf(fp, "\t\t test esi,esi\n"); // see if we need to post process + fprintf(fp, "\t\t jz short %s_4\n",Label); // if not, skip + fprintf(fp, "\t\t jpo short %s_4\n",Label); // if PO (pos*pos or neg*neg), leave the result + fprintf(fp, "\t\t neg eax\n"); // negate the result + +// store results + fprintf(fp, "%s_4:\n",Label); + fprintf(fp, "\t\t mov ebx,ecx\n"); // ebx = extension word + fprintf(fp, "\t\t and ebx,7\n"); // get Dr in ebx + fprintf(fp, "\t\t shr ecx,12\n"); // ecx = Dq + fprintf(fp, "\t\t and ecx,7\n"); // 0-7 + fprintf(fp, "\t\t mov [%s+ebx*4],edx\n",REG_DAT); // store remainder first + fprintf(fp, "\t\t mov [%s+ecx*4],eax\n",REG_DAT); // store quotient second + fprintf(fp, "\t\t pop esi\n"); // restore esi + fprintf(fp, "\t\t pop edx\n"); // restore edx + SetFlags('L',EAX,TRUE,FALSE,FALSE); // set the flags + fprintf(fp, "%s_5:\n",Label); + fprintf(fp, "\t\t and edx,~1\n"); // clear the carry + Completed(); + + fprintf(fp, "%s_ZERO:\t\t ;Do divide by zero trap\n", Label); + /* Correct cycle counter for error */ + fprintf(fp, "\t\t pop esi\n"); // restore esi + fprintf(fp, "\t\t pop edx\n"); // restore edx + fprintf(fp, "\t\t add dword [%s],byte %d\n",ICOUNT,95); + fprintf(fp,"\t\t jmp short %s_5\n",Label); + Exception(5,BaseCode); + + fprintf(fp, "%s_OVERFLOW:\n",Label); +//set overflow + fprintf(fp, "\t\t pop esi\n"); // restore esi + fprintf(fp, "\t\t pop edx\n"); // restore edx + fprintf(fp, "\t\t or edx,0x0800\n"); // set the overflow bit + fprintf(fp, "\t\t jmp near %s_5\n",Label); // done + + } + + OpcodeArray[Opcode] = BaseCode ; + } + } +} + +void bfext(void) +{ +// just bfextu/bfexts for now + char allow[] = "0-2--56789a-----" ; + char *Label = NULL ; + int mode,dreg,sign,Opcode,BaseCode,Dest ; + for (mode=0; mode<8; mode++) + for (dreg=0; dreg<8; dreg++) + for (sign=0; sign<2; sign++) + { + Opcode = 0xe9c0 | (sign<<9) | (mode<<3) | dreg ; + BaseCode = Opcode & 0xebf8 ; + if (mode == 7) + BaseCode |= dreg ; + Dest = EAtoAMN(Opcode, FALSE); + if (allow[Dest&0xf] != '-') + { + if (OpcodeArray[BaseCode] == -2) + { + Align(); + Label = GenerateLabel(BaseCode,0); + fprintf(fp, "%s:\n",Label); + Label = GenerateLabel(BaseCode,1); + if ((Dest >= 2) && (Dest <=10)) + SavePreviousPC(); + + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + if (mode < 7) + { + fprintf(fp, "\t\t and ecx,byte 7\n"); + } + + Memory_Fetch('W', EAX, FALSE ) ; + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + EffectiveAddressRead(Dest,'L',ECX,EDX,"ABCDSDB",FALSE); // edx = dword + + fprintf(fp, "\t\t mov ecx,eax\n"); + fprintf(fp, "\t\t shr ecx,byte 6\n"); + fprintf(fp, "\t\t test eax,0x0800\n"); + fprintf(fp, "\t\t je short %s_1\n",Label); + //get offset from Dx + fprintf(fp, "\t\t and ecx,byte 7\n"); + fprintf(fp, "\t\t mov ecx,[%s+ECX*4]\n",REG_DAT); + //get offset from extension + fprintf(fp, "%s_1:\n",Label); + fprintf(fp, "\t\t and ecx,31\n"); // ecx = offset + fprintf(fp, "\t\t mov ebx,eax\n"); + fprintf(fp, "\t\t test eax,0x0020\n"); + fprintf(fp, "\t\t je short %s_2\n",Label); + //get width from Dy + fprintf(fp, "\t\t and ebx,byte 7\n"); + fprintf(fp, "\t\t mov ebx,[%s+EBX*4]\n",REG_DAT); + //get width from extension + fprintf(fp, "%s_2:\n",Label); + //fix 0=32 + fprintf(fp, "\t\t sub ebx,byte 1\n"); + fprintf(fp, "\t\t and ebx,byte 31\n"); + fprintf(fp, "\t\t add ebx,byte 1\n"); // ebx = width + fprintf(fp, "\t\t rol edx,cl\n"); + // check for N + fprintf(fp, "\t\t mov ecx,32\n"); + fprintf(fp, "\t\t sub ecx,ebx\n"); + fprintf(fp, "\t\t mov ebx,edx\n"); + SetFlags('L',EBX,TRUE,FALSE,FALSE); + if (sign) + fprintf(fp, "\t\t sar ebx,cl\n"); + else + fprintf(fp, "\t\t shr ebx,cl\n"); + fprintf(fp, "\t\t shr eax,12\n"); + fprintf(fp, "\t\t and eax,7\n"); + fprintf(fp, "\t\t mov [%s+EAX*4],ebx\n",REG_DAT); + fprintf(fp, "\t\t test ebx,ebx\n"); + fprintf(fp, "\t\t jnz short %s_3\n",Label); + //zero flag + fprintf(fp, "\t\t or edx,40h\n"); + fprintf(fp, "%s_3:\n",Label); + Completed(); + } + OpcodeArray[Opcode] = BaseCode ; + } + } +} + +/* + * not + * clr + * neg + * negx + * + */ + +void not(void) +{ + int type,leng, mode, sreg ; + int Opcode, BaseCode ; + int Dest ; + int SaveEDX=0; + char Size=' ' ; + char * Regname="" ; + char * RegnameECX ; + char * Label; + + char allow[] = "0-2345678-------" ; + + for (type = 0 ; type < 4 ; type++) + for (leng = 0 ; leng < 3 ; leng++) + for (mode = 0 ; mode < 8 ; mode++) + for (sreg = 0 ; sreg < 8 ; sreg++) + { + Opcode = 0x4000 | (type<<9) | (leng<<6) | (mode<<3) | sreg ; + BaseCode = Opcode & 0x46f8 ; + if (mode == 7) + { + BaseCode |= sreg ; + } + + // A7+, A7- + +#ifdef A7ROUTINE + if ((leng == 0) && (sreg == 7) && (mode > 2) && (mode < 5)) + { + BaseCode |= sreg ; + } +#endif + + Dest = EAtoAMN(Opcode, FALSE); + + if (allow[Dest&0x0f] != '-') + { + switch (leng) + { + case 0: + Size = 'B'; + Regname = regnamesshort[0]; + RegnameECX = regnamesshort[ECX]; + break; + case 1: + Size = 'W'; + Regname = regnamesword[0]; + RegnameECX = regnamesword[ECX]; + break; + case 2: + Size = 'L'; + Regname = regnameslong[0]; + RegnameECX = regnameslong[ECX]; + break; + } + + if (OpcodeArray[ BaseCode ] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + + if ((Dest >= 2) && (Dest <=10)) + SavePreviousPC(); + + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + if (Size != 'L') + TimingCycles += 4; + else + TimingCycles += 6; + + if (Dest < 7) + fprintf(fp, "\t\t and ecx,byte 7\n"); + + if (type == 0) SaveEDX = TRUE; + else SaveEDX = FALSE; + + /* CLR does not need to read source (although it does on a real 68000) */ + + if (type != 1) + { + EffectiveAddressRead(Dest,Size,ECX,EAX,"A-CDS-B",SaveEDX); + } + + switch (type) + { + case 0: /* negx */ + + /* Preserve old Z flag */ + + fprintf(fp, "\t\t mov ebx,edx\n"); + + CopyX(); + fprintf(fp, "\t\t adc %s,byte 0\n", Regname ) ; + fprintf(fp, "\t\t neg %s\n", Regname ) ; + + /* Set the Flags */ + + SetFlags(Size,EAX,FALSE,TRUE,FALSE); + + /* Handle the Z flag */ + + Label = GenerateLabel(0,1); + + fprintf(fp, "\t\t jnz short %s\n\n",Label); + + fprintf(fp, "\t\t and edx,byte -65 ; Remove Z\n"); + fprintf(fp, "\t\t and ebx,byte 40h ; Mask out Old Z\n"); + fprintf(fp, "\t\t or edx,ebx ; Copy across\n\n"); + fprintf(fp, "%s:\n",Label); + + break; + + case 1: /* clr */ + ClearRegister(EAX); + EffectiveAddressWrite(Dest,Size,ECX,TRUE,"----S-B",FALSE); + fprintf(fp, "\t\t mov edx,40H\n"); + break; + + case 2: /* neg */ + fprintf(fp, "\t\t neg %s\n",Regname ) ; + SetFlags(Size,EAX,FALSE,TRUE,TRUE); + break; + + case 3: /* not */ + fprintf(fp, "\t\t xor %s,-1\n",Regname ) ; + SetFlags(Size,EAX,FALSE,FALSE,TRUE); + break; + } + + /* Update (unless CLR command) */ + + if (type != 1) + EffectiveAddressWrite(Dest,Size,ECX,FALSE,"---DS-B",TRUE); + + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } + } +} + +/* + * Move to/from USP + * + */ + +void moveusp(void) +{ + int Opcode, BaseCode ; + int dir, sreg ; + char * Label; + + for (dir = 0 ; dir < 2 ; dir++) + for (sreg = 0 ; sreg < 8 ; sreg++) + { + Opcode = 0x4e60 | ( dir << 3 ) | sreg ; + BaseCode = Opcode & 0x4e68 ; + + if (OpcodeArray[BaseCode] == -2) + { + Align(); + Label = GenerateLabel(BaseCode,0); + fprintf(fp, "%s\n", Label ); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + TimingCycles += 4; + + fprintf(fp, "\t\t test byte [%s],20h \t\t\t; Supervisor Mode ?\n",REG_SRH); + fprintf(fp, "\t\t jz short OP%d_%4.4x_Trap\n",CPU,BaseCode); + + fprintf(fp, "\t\t and ecx,7\n"); + + if (dir == 0) /* reg 2 USP */ + { + fprintf(fp, "\t\t mov eax,[%s+ECX*4]\n",REG_ADD); + fprintf(fp, "\t\t mov [%s],eax\n",REG_USP); + } + else + { + fprintf(fp, "\t\t mov eax,[%s]\n",REG_USP); + fprintf(fp, "\t\t mov [%s+ECX*4],eax\n",REG_ADD); + } + Completed(); + + fprintf(fp, "OP%d_%4.4x_Trap:\n",CPU,BaseCode); + Exception(8,BaseCode); + } + OpcodeArray[Opcode] = BaseCode ; + } +} + + +/* + * Check + * + */ + +void chk(void) +{ + int dreg,mode,sreg,size ; + int Opcode, BaseCode ; + int Dest ; + char * Label ; + + char *allow = "0-23456789ab----" ; + + for (size = 0 ; size < (CPU==2 ? 2 : 1); size++) + for (dreg = 0 ; dreg < 8; dreg++) + for (mode = 0 ; mode < 8; mode++) + for (sreg = 0 ; sreg < 8; sreg++) + { + if (size == 0) /* word */ + Opcode = 0x4180 | (dreg<<9) | (mode<<3) | sreg ; + else /* long */ + Opcode = 0x4100 | (dreg<<9) | (mode<<3) | sreg ; + BaseCode = Opcode & 0x41f8 ; + + if (mode == 7) + { + BaseCode |= sreg ; + } + + Dest = EAtoAMN(Opcode, FALSE); + + if (allow[Dest&0xf] != '-') + { + if (OpcodeArray[BaseCode] == -2) + { + Align(); + Label = GenerateLabel(BaseCode,0); + fprintf(fp, "%s:\n", Label ); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + TimingCycles += 10; + + fprintf(fp, "\t\t mov ebx,ecx\n"); + fprintf(fp, "\t\t shr ebx,byte 9\n"); + fprintf(fp, "\t\t and ebx,byte 7\n"); + + if (Dest < 7) + fprintf(fp, "\t\t and ecx,byte 7\n"); + + EffectiveAddressRead(Dest,(size == 0) ? 'W' : 'L',ECX,EAX,"----S-B",FALSE); + + if (size == 0) /* word */ + { + fprintf(fp, "\t\t movsx ebx,word [%s+EBX*4]\n",REG_DAT); + fprintf(fp, "\t\t movsx eax,ax\n"); + } + else /* long */ + fprintf(fp, "\t\t mov ebx,[%s+EBX*4]\n",REG_DAT); + + fprintf(fp, "\t\t test ebx,ebx\n"); /* is word bx < 0 */ + fprintf(fp, "\t\t jl near OP%d_%4.4x_Trap_minus\n",CPU,BaseCode); + + fprintf(fp, "\t\t cmp ebx,eax\n"); + fprintf(fp, "\t\t jg near OP%d_%4.4x_Trap_over\n",CPU,BaseCode); + Completed(); + + /* N is set if data less than zero */ + + Align(); + fprintf(fp, "OP%d_%4.4x_Trap_minus:\n",CPU,BaseCode); + fprintf(fp, "\t\t or edx,0x0080\n"); /* N flag = 80H */ + fprintf(fp, "\t\t jmp short OP%d_%4.4x_Trap_Exception\n",CPU,BaseCode); + + /* N is cleared if greated than compared number */ + + Align(); + fprintf(fp, "OP%d_%4.4x_Trap_over:\n",CPU,BaseCode); + fprintf(fp, "\t\t and edx,0x007f\n"); /* N flag = 80H */ + + fprintf(fp, "OP%d_%4.4x_Trap_Exception:\n",CPU,BaseCode); + fprintf(fp, "\t\t mov al,6\n"); + Exception(-1,0x10000+BaseCode); + Completed(); + + } + + OpcodeArray[Opcode] = BaseCode ; + } + } +} + +void chk2(void) +{ +#if 0 + int mode,sreg,size ; + int Opcode, BaseCode ; + int Dest ; + char * Label ; + + char *allow = "--2--56789a-----" ; + + for (size = 0 ; size < 2; size++) + for (mode = 0 ; mode < 8; mode++) + for (sreg = 0 ; sreg < 8; sreg++) + { + Opcode = 0x00c0 | (size<<9) | (mode<<3) | sreg; + BaseCode = Opcode & 0xfff8 ; + + if (mode == 7) + { + BaseCode |= sreg ; + } + + Dest = EAtoAMN(Opcode, FALSE); + + if (allow[Dest&0xf] != '-') + { + if (OpcodeArray[BaseCode] == -2) + { + Align(); + Label = GenerateLabel(BaseCode,0); + fprintf(fp, "%s:\n", Label ); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + TimingCycles += 10; + + fprintf(fp, "\t\t mov ebx,ecx\n"); + fprintf(fp, "\t\t shr ebx,byte 9\n"); + fprintf(fp, "\t\t and ebx,byte 7\n"); + + if (Dest < 7) + fprintf(fp, "\t\t and ecx,byte 7\n"); + + EffectiveAddressRead(Dest,'W',ECX,EAX,"----S-B",FALSE); + + if (size == 0) /* word */ + { + fprintf(fp, "\t\t movsx ebx,word [%s+EBX*4]\n",REG_DAT); + fprintf(fp, "\t\t movsx eax,ax\n"); + } + else /* long */ + fprintf(fp, "\t\t mov ebx,[%s+EBX*4]\n",REG_DAT); + + fprintf(fp, "\t\t test ebx,ebx\n"); /* is word bx < 0 */ + fprintf(fp, "\t\t jl near OP%d_%4.4x_Trap_minus\n",CPU,BaseCode); + + fprintf(fp, "\t\t cmp ebx,eax\n"); + fprintf(fp, "\t\t jg near OP%d_%4.4x_Trap_over\n",CPU,BaseCode); + Completed(); + + /* N is set if data less than zero */ + + Align(); + fprintf(fp, "OP%d_%4.4x_Trap_minus:\n",CPU,BaseCode); + fprintf(fp, "\t\t or edx,0x0080\n"); /* N flag = 80H */ + fprintf(fp, "\t\t jmp short OP%d_%4.4x_Trap_Exception\n",CPU,BaseCode); + + /* N is cleared if greated than compared number */ + + Align(); + fprintf(fp, "OP%d_%4.4x_Trap_over:\n",CPU,BaseCode); + fprintf(fp, "\t\t and edx,0x007f\n"); /* N flag = 80H */ + + fprintf(fp, "OP%d_%4.4x_Trap_Exception:\n",CPU,BaseCode); + fprintf(fp, "\t\t mov al,6\n"); + Exception(-1,0x10000+BaseCode); + Completed(); + + } + + OpcodeArray[Opcode] = BaseCode ; + } + } +#endif +} + +/* + * Load Effective Address + */ + +void LoadEffectiveAddress(void) +{ + int Opcode, BaseCode ; + int sreg,mode,dreg ; + int Dest ; + char allow[] = "--2--56789a-----" ; + + for (sreg = 0 ; sreg < 8 ; sreg++) + for (mode = 0 ; mode < 8 ; mode++) + for (dreg = 0 ; dreg < 8 ; dreg++) + { + Opcode = 0x41c0 | (sreg<<9) | (mode<<3) | dreg ; + + BaseCode = Opcode & 0x41f8 ; + + if (mode == 7) + BaseCode = BaseCode | dreg ; + + Dest = EAtoAMN(BaseCode, FALSE); + + if (allow[Dest&0x0f] != '-') + { + if (OpcodeArray[BaseCode] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + switch (mode) + { + case 2: + TimingCycles += 4; + break; + case 5: + case 7: + case 9: + TimingCycles += 8; + break; + case 6: + case 8: + case 10: + TimingCycles += 12; + break; + } + + if (mode < 7) + { + fprintf(fp, "\t\t mov ebx,ecx\n"); + fprintf(fp, "\t\t and ebx,byte 7\n"); + } + + fprintf(fp, "\t\t shr ecx,byte 9\n"); + fprintf(fp, "\t\t and ecx,byte 7\n"); + + EffectiveAddressCalculate(Dest,'L',EBX,TRUE); + fprintf(fp, "\t\t mov [%s+ECX*4],edi\n",REG_ADD); + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } + } +} + +/* + * Negate BCD + * + */ + +void nbcd(void) +{ + int Opcode, BaseCode ; + int sreg,mode,Dest ; + char allow[] = "0-2345678-------" ; + + for (mode = 0 ; mode < 8 ; mode++) + for (sreg = 0 ; sreg < 8 ; sreg++) + { + Opcode = 0x4800 | (mode<<3) | sreg ; + BaseCode = Opcode & 0x4838 ; + + if (mode == 7) + BaseCode |= sreg ; + + // A7+, A7- + +#ifdef A7ROUTINE + if ((sreg == 7) && (mode > 2) && (mode < 5)) + { + BaseCode |= sreg; + } +#endif + + Dest = EAtoAMN(BaseCode, FALSE); + + if (allow[Dest&0xf] != '-') + { + if (OpcodeArray[BaseCode] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + + if ((Dest >= 2) && (Dest <=10)) + SavePreviousPC(); + + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + if (mode < 2) + TimingCycles += 6; + else + TimingCycles += 8; + + fprintf(fp, "\t\t and ecx, byte 7\n"); + + EffectiveAddressRead(Dest,'B',ECX,EBX,"--C-SDB",FALSE); + + ClearRegister(EAX); + CopyX(); + + fprintf(fp, "\t\t sbb al,bl\n"); + fprintf(fp, "\t\t das\n"); + + SetFlags('B',EAX,FALSE,TRUE,TRUE); + + EffectiveAddressWrite(Dest,'B',ECX,EAX,"----S-B",FALSE); + Completed(); + } + OpcodeArray[Opcode] = BaseCode ; + } + } +} + +void tas(void) +{ + int Opcode, BaseCode ; + int sreg,mode,Dest ; + char allow[] = "0-2345678-------" ; + + for (mode = 0 ; mode < 8 ; mode++) + for (sreg = 0 ; sreg < 8 ; sreg++) + { + Opcode = 0x4ac0 | (mode<<3) | sreg ; + BaseCode = Opcode & 0x4af8 ; + + if (mode == 7) + BaseCode |= sreg ; + +#ifdef A7ROUTINE + if ((sreg == 7) && (mode > 2) && (mode < 5)) + { + BaseCode |= sreg ; + } +#endif + + Dest = EAtoAMN(BaseCode, FALSE); + + if (allow[Dest&0xf] != '-') + { + if (OpcodeArray[BaseCode] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + + if ((Dest >= 2) && (Dest <=10)) + SavePreviousPC(); + + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + if (mode < 2) + TimingCycles += 4; + else + TimingCycles += 14; + + fprintf(fp, "\t\t and ecx, byte 7\n"); + + EffectiveAddressRead(Dest,'B',ECX,EAX,"--C-SDB",FALSE); + + SetFlags('B',EAX,TRUE,FALSE,TRUE); + fprintf(fp, "\t\t or al,128\n"); + + EffectiveAddressWrite(Dest,'B',ECX,EAX,"----S-B",FALSE); + Completed(); + } + OpcodeArray[Opcode] = BaseCode ; + } + } +} + +/* + * push Effective Address + */ + +void PushEffectiveAddress(void) +{ + int Opcode, BaseCode ; + int mode,dreg ; + int Dest ; + char allow[] = "--2--56789a-----" ; + + for (mode = 0 ; mode < 8 ; mode++) + for (dreg = 0 ; dreg < 8 ; dreg++) + { + Opcode = 0x4840 | (mode<<3) | dreg ; + + BaseCode = Opcode & 0x4878 ; + + if (mode == 7) + BaseCode = BaseCode | dreg ; + + Dest = EAtoAMN(BaseCode, FALSE); + + if (allow[Dest&0x0f] != '-') + { + if (OpcodeArray[BaseCode] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + SavePreviousPC(); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + switch (mode) + { + case 2: + TimingCycles += 12; + break; + case 5: + case 7: + case 9: + TimingCycles += 16; + break; + case 6: + case 8: + case 10: + TimingCycles += 20; + break; + } + + if (mode < 7) + { + fprintf(fp, "\t\t and ecx,byte 7\n"); + } + + EffectiveAddressCalculate(Dest,'L',ECX,TRUE); + + fprintf(fp, "\t\t mov ecx,[%s]\t ; Push onto Stack\n",REG_A7); + fprintf(fp, "\t\t sub ecx,byte 4\n"); + fprintf(fp, "\t\t mov [%s],ecx\n",REG_A7); + Memory_Write('L',ECX,EDI,"---DS-B",2); + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } + } +} + +/* + * Test + * + */ + +void tst(void) +{ + int leng, mode, sreg ; + int Opcode, BaseCode ; + int Dest ; + char Size=' ' ; + char * Regname ; + char * RegnameECX ; + + char allow[] = "0-2345678-------" ; + if (CPU==2) + allow[1] = '1'; + + for (leng = 0 ; leng < 3 ; leng++) + for (mode = 0 ; mode < 8 ; mode++) + for (sreg = 0 ; sreg < 8 ; sreg++) + { + Opcode = 0x4a00 | (leng<<6) | (mode<<3) | sreg ; + BaseCode = Opcode & 0x4af8 ; + if (mode == 7) + { + BaseCode |= sreg ; + } + + // A7+, A7- + +#ifdef A7ROUTINE + if ((leng == 0) && (sreg == 7) && (mode > 2) && (mode < 5)) + { + BaseCode |= sreg ; + } +#endif + + Dest = EAtoAMN(Opcode, FALSE); + + if ((allow[Dest&0x0f] != '-') || (( mode == 1 ) && (leng != 0))) + { + switch (leng) + { + case 0: + Size = 'B'; + Regname = regnamesshort[0]; + RegnameECX = regnamesshort[ECX]; + break; + case 1: + Size = 'W'; + Regname = regnamesword[0]; + RegnameECX = regnamesword[ECX]; + break; + case 2: + Size = 'L'; + Regname = regnameslong[0]; + RegnameECX = regnameslong[ECX]; + break; + } + + if (OpcodeArray[ BaseCode ] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + + if ((Dest >= 2) && (Dest <=10)) + SavePreviousPC(); + + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + TimingCycles += 4; + + if (Dest < 7) + fprintf(fp, "\t\t and ecx,byte 7\n"); + + EffectiveAddressRead(Dest,Size,ECX,EAX,"----S-B",FALSE); + + SetFlags(Size,EAX,TRUE,FALSE,FALSE); + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } + } +} + +/* + * Move registers too / from memory + * + */ + +void movem_reg_ea(void) +{ + int leng,mode,sreg ; + int Opcode, BaseCode ; + int Dest ; + char Size ; + char * Label ; + + char *allow = "--2-45678-------" ; + + for (leng = 0 ; leng < 2; leng++) + for (mode = 0 ; mode < 8; mode++) + for (sreg = 0 ; sreg < 8; sreg++) + { + Opcode = 0x4880 | ( leng<<6) | (mode<<3) | sreg ; + BaseCode = Opcode & 0x4cf8 ; + + if (mode == 7) + { + BaseCode |= sreg ; + } + + Dest = EAtoAMN(Opcode, FALSE); + + Size = "WL"[leng] ; + + if (allow[Dest&0xf] != '-') + { + if (OpcodeArray[BaseCode] == - 2) + { + Align(); + Label = GenerateLabel(BaseCode,0); + fprintf(fp, "%s:\n",Label ) ; + SavePreviousPC(); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + switch (mode) + { + case 2: + case 4: + TimingCycles += 8 ; + break; + case 5: + case 7: + TimingCycles += 12 ; + break; + case 6: + case 8: + TimingCycles += 14 ; + break; + } + + fprintf(fp, "\t\t push edx\n"); + + Memory_Fetch('W',EDX,FALSE); + fprintf(fp, "\t\t add esi,byte 2\n"); + + if (mode < 7) + { + fprintf(fp, "\t\t and ecx,byte 7\n"); + } + + if (mode == 4) + { + fprintf(fp, "\t\t push ecx\n"); + fprintf(fp, "\t\t mov edi,[%s+ECX*4]\n",REG_ADD); + } + else + EffectiveAddressCalculate(Dest,'L',ECX,TRUE); + + fprintf(fp, "\t\t mov ebx,1\n"); + + /* predecrement uses d0-d7..a0-a7 a7 first*/ + /* other modes use a7-a0..d7-d0 d0 first*/ + + if (Dest != 4) + ClearRegister(ECX); + else + fprintf(fp, "\t\t mov ecx,3Ch\n"); + + fprintf(fp, "OP%d_%4.4x_Again:\n",CPU,BaseCode); + fprintf(fp, "\t\t test edx,ebx\n"); + fprintf(fp, "\t\t je OP%d_%4.4x_Skip\n",CPU,BaseCode); + + fprintf(fp, "\t\t mov eax,[%s+ecx]\n",REG_DAT); /* load eax with current reg data */ + + if (Dest == 4) + { + if (Size == 'W') /* adjust pointer before write */ + fprintf(fp, "\t\t sub edi,byte 2\n"); + else + fprintf(fp, "\t\t sub edi,byte 4\n"); + } + + Memory_Write(Size,EDI,EAX,"-BCDSDB",1); + + if (Dest != 4) + { + if (Size == 'W') /* adjust pointer after write */ + fprintf(fp, "\t\t add edi,byte 2\n"); + else + fprintf(fp, "\t\t add edi,byte 4\n"); + } + + /* Update Cycle Count */ + + if (Size == 'W') + fprintf(fp, "\t\t sub dword [%s],byte 4\n",ICOUNT); + else + fprintf(fp, "\t\t sub dword [%s],byte 8\n",ICOUNT); + + fprintf(fp, "OP%d_%4.4x_Skip:\n",CPU,BaseCode); + + if (Dest != 4) + fprintf(fp, "\t\t add ecx,byte 4h\n"); + else + fprintf(fp, "\t\t sub ecx,byte 4h\n"); + + fprintf(fp, "\t\t add ebx,ebx\n"); /* faster than shl ebx,1 */ + fprintf(fp, "\t\t test bx,bx\n"); /* check low 16 bits */ + fprintf(fp, "\t\t jnz OP%d_%4.4x_Again\n",CPU,BaseCode); + + if (Dest == 4) + { + fprintf(fp, "\t\t pop ecx\n"); + fprintf(fp, "\t\t mov [%s+ECX*4],edi\n",REG_ADD); + } + + fprintf(fp, "\t\t pop edx\n"); + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } + } +} + +void movem_ea_reg(void) +{ + int leng,mode,sreg ; + int Opcode, BaseCode ; + int Dest ; + char Size ; + char * Label ; + + char *allow = "--23-56789a-----" ; + + for (leng = 0 ; leng < 2; leng++) + for (mode = 0 ; mode < 8; mode++) + for (sreg = 0 ; sreg < 8; sreg++) + { + Opcode = 0x4c80 | ( leng<<6) | (mode<<3) | sreg ; + BaseCode = Opcode & 0x4cf8 ; + + if (mode == 7) + { + BaseCode |= sreg ; + } + + Dest = EAtoAMN(Opcode, FALSE); + + Size = "WL"[leng] ; + + if (allow[Dest&0xf] != '-') + { + if (OpcodeArray[BaseCode] == - 2) + { + Align(); + Label = GenerateLabel(BaseCode,0); + + fprintf(fp, "%s:\n",Label ) ; + SavePreviousPC(); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + switch (mode) + { + case 2: + case 4: + TimingCycles += 8 ; + break; + case 5: + case 7: + TimingCycles += 12 ; + break; + case 6: + case 8: + TimingCycles += 14 ; + break; + } + + fprintf(fp, "\t\t push edx\n"); /* save edx because sr is unaffected */ + + Memory_Fetch('W',EDX,FALSE); + fprintf(fp, "\t\t add esi,byte 2\n"); + + if (mode < 7) + { + fprintf(fp, "\t\t and ecx,byte 7\n"); + } + + if (mode == 3) + fprintf(fp, "\t\t push ecx\n"); /* if (An)+ then it needed later */ + + EffectiveAddressCalculate(Dest,'L',ECX,TRUE); + + fprintf(fp, "\t\t mov ebx,1\n"); /* setup register list mask */ + + /* predecrement uses d0-d7..a0-a7 a7 first*/ + /* other modes use a7-a0..d7-d0 d0 first*/ + + ClearRegister(ECX); /* always start with D0 */ + + fprintf(fp, "OP%d_%4.4x_Again:\n",CPU,BaseCode); + fprintf(fp, "\t\t test edx,ebx\n"); /* is bit set for this register? */ + fprintf(fp, "\t\t je OP%d_%4.4x_Skip\n",CPU,BaseCode); + + Memory_Read(Size,EDI,"-BCDSDB",1); + + if (Size == 'W') + fprintf(fp, "\t\t cwde\n"); /* word size must be sign extended */ + + fprintf(fp, "\t\t mov [%s+ecx],eax\n",REG_DAT); /* load current reg with eax */ + + if (Size == 'W') /* adjust pointer after write */ + fprintf(fp, "\t\t add edi,byte 2\n"); + else + fprintf(fp, "\t\t add edi,byte 4\n"); + + /* Update Cycle Count */ + + if (Size == 'W') + fprintf(fp, "\t\t sub dword [%s],byte 4\n",ICOUNT); + else + fprintf(fp, "\t\t sub dword [%s],byte 8\n",ICOUNT); + + fprintf(fp, "OP%d_%4.4x_Skip:\n",CPU,BaseCode); + fprintf(fp, "\t\t add ecx,byte 4\n"); /* adjust pointer to next reg */ + fprintf(fp, "\t\t add ebx,ebx\n"); /* Faster than shl ebx,1 */ + fprintf(fp, "\t\t test bx,bx\n"); /* check low 16 bits */ + fprintf(fp, "\t\t jnz OP%d_%4.4x_Again\n",CPU,BaseCode); + + if (mode == 3) + { + fprintf(fp, "\t\t pop ecx\n"); + fprintf(fp, "\t\t mov [%s+ECX*4],edi\n",REG_ADD); /* reset Ax if mode = (Ax)+ */ + } + + fprintf(fp, "\t\t pop edx\n"); /* restore flags */ + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } + } +} + +/* + * Link / Unlink + * + * Local stack space + * + */ + +void link(void) +{ + int sreg ; + int Opcode, BaseCode ; + + for (sreg = 0 ; sreg < 8; sreg++) + { + Opcode = 0x4e50 | sreg ; + BaseCode = 0x4e50 ; + + if (OpcodeArray[BaseCode] == - 2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + SavePreviousPC(); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + TimingCycles += 16; + + fprintf(fp, "\t\t sub dword [%s],byte 4\n",REG_A7); + + fprintf(fp, "\t\t and ecx, byte 7\n"); + fprintf(fp, "\t\t mov eax,[%s+ECX*4]\n",REG_ADD); + fprintf(fp, "\t\t mov edi,[%s]\n",REG_A7); + fprintf(fp, "\t\t mov [%s+ECX*4],edi\n",REG_ADD); + + Memory_Write('L',EDI,EAX,"---DS-B",1); + + Memory_Fetch('W',EAX,TRUE); + fprintf(fp, "\t\t add esi,byte 2\n"); + fprintf(fp, "\t\t add [%s],eax\n",REG_A7); + + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } +} + +void unlinkasm(void) +{ + int sreg ; + int Opcode, BaseCode ; + + for (sreg = 0 ; sreg < 8; sreg++) + { + Opcode = 0x4e58 | sreg ; + BaseCode = 0x4e58 ; + + if (OpcodeArray[BaseCode] == - 2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + SavePreviousPC(); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + TimingCycles += 12; + + fprintf(fp, "\t\t mov ebx,ecx\n"); + fprintf(fp, "\t\t and ebx, byte 7\n"); + fprintf(fp, "\t\t mov edi,[%s+EBX*4]\n",REG_ADD); + + Memory_Read('L',EDI,"-B-DSDB",1); + + fprintf(fp, "\t\t mov [%s+EBX*4],eax\n",REG_ADD); + fprintf(fp, "\t\t add edi,byte 4\n"); + fprintf(fp, "\t\t mov dword [%s],EDI\n",REG_A7); + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } +} + +void trap(void) +{ + int Count; + int BaseCode = 0x4E40; + + if (OpcodeArray[BaseCode] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + fprintf(fp, "\t\t mov eax,ecx\n"); + fprintf(fp, "\t\t and eax,byte 15\n"); + fprintf(fp, "\t\t or eax,byte 32\n"); + Exception(-1,BaseCode); + Completed(); + } + + for (Count=0;Count<=15;Count++) + OpcodeArray[BaseCode+Count] = BaseCode; +} + +void reset(void) +{ + int BaseCode = 0x4E70; + char * Label; + + if (OpcodeArray[BaseCode] == -2) + { + Align(); + Label = GenerateLabel(BaseCode,0); + + TimingCycles += 132; + + fprintf(fp, "%s:\n", Label ); + SavePreviousPC(); + + fprintf(fp, "\t\t add esi,byte 2\n\n"); + fprintf(fp, "\t\t test byte [%s],20h \t\t\t; Supervisor Mode ?\n",REG_SRH); + fprintf(fp, "\t\t jnz near OP%d_%4.4x_RESET\n",CPU,BaseCode); + Exception(8,BaseCode); + + fprintf(fp, "\nOP%d_%4.4x_RESET:\n",CPU,BaseCode); + + /* Prefetch next instruction */ + + if(CPU==2) + { + /* 32 bit memory version */ + + fprintf(fp, "\t\t xor esi,2\n"); /* ASG */ +#ifdef STALLCHECK + ClearRegister(ECX); + fprintf(fp, "\t\t mov cx,[esi+ebp]\n"); +#else + fprintf(fp, "\t\t movzx ecx,word [esi+ebp]\n"); +#endif + fprintf(fp, "\t\t xor esi,2\n"); /* ASG */ + } + else + { + /* 16 bit memory */ +#ifdef STALLCHECK + ClearRegister(ECX); + fprintf(fp, "\t\t mov cx,[esi+ebp]\n"); +#else + fprintf(fp, "\t\t movzx ecx,word [esi+ebp]\n"); +#endif + } + + fprintf(fp, "\t\t mov eax,dword [%s]\n", REG_RESET_CALLBACK); + fprintf(fp, "\t\t test eax,eax\n"); + fprintf(fp, "\t\t jz near OP%d_%4.4x_END\n",CPU,BaseCode); + + /* Callback for Reset */ + + fprintf(fp, "\t\t mov [%s],ESI,\n",REG_PC); + fprintf(fp, "\t\t mov [%s],edx\n",REG_CCR); + fprintf(fp, "\t\t push ECX\n"); + + fprintf(fp, "\t\t call [eax]\n"); + + fprintf(fp, "\t\t mov ESI,[%s]\n",REG_PC); + fprintf(fp, "\t\t mov edx,[%s]\n",REG_CCR); + fprintf(fp, "\t\t pop ECX\n"); + fprintf(fp, "\t\t mov ebp,dword [_OP_ROM]\n"); + + fprintf(fp, "OP%d_%4.4x_END:\n",CPU,BaseCode); + fprintf(fp, "\t\t sub dword [%s],%d\n",ICOUNT,TimingCycles); + fprintf(fp, "\t\t jmp [%s_OPCODETABLE+ecx*4]\n\n", CPUtype); + } + OpcodeArray[BaseCode] = BaseCode ; +} + +void nop(void) +{ + int BaseCode = 0x4e71 ; + + if (OpcodeArray[BaseCode] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + TimingCycles += 4; + + Completed(); + OpcodeArray[BaseCode] = BaseCode ; + } +} + +void stop(void) +{ + char TrueLabel[16]; + int BaseCode = 0x4e72 ; + + if (OpcodeArray[BaseCode] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + TimingCycles += 4; + + /* Must be in Supervisor Mode */ + + sprintf(TrueLabel,GenerateLabel(0,1)); + + fprintf(fp, "\t\t test byte [%s],20h \t\t\t; Supervisor Mode ?\n",REG_SRH); + fprintf(fp, "\t\t je near %s\n\n",TrueLabel); + + /* Next WORD is new SR */ + + Memory_Fetch('W',EAX,FALSE); + fprintf(fp, "\t\t add esi,byte 2\n"); + + WriteCCR('W'); + + /* See if Valid interrupt waiting */ + + CheckInterrupt = 0; + + fprintf(fp, "\t\t mov eax,[%s]\n",REG_IRQ); + fprintf(fp, "\t\t and eax,byte 07H\n"); + + fprintf(fp, "\t\t cmp al,7\t\t ; Always take 7\n"); + fprintf(fp, "\t\t je near procint\n\n"); + + fprintf(fp, "\t\t mov ebx,[%s]\t\t; int mask\n",REG_SRH); + fprintf(fp, "\t\t and ebx,byte 07H\n"); + fprintf(fp, "\t\t cmp eax,ebx\n"); + fprintf(fp, "\t\t jg near procint\n\n"); + + /* No int waiting - clear count, set stop */ + + ClearRegister(ECX); + fprintf(fp, "\t\t mov [%s],ecx\n",ICOUNT); + fprintf(fp, "\t\t or byte [%s],80h\n",REG_IRQ); + Completed(); + + /* User Mode - Exception */ + + Align(); + fprintf(fp, "%s:\n",TrueLabel); + Exception(8,BaseCode); + + OpcodeArray[BaseCode] = BaseCode ; + } +} + +void ReturnFromException(void) +{ + char TrueLabel[16]; + + int BaseCode = 0x4e73; + + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + SavePreviousPC(); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + TimingCycles += 20; + + /* Check in Supervisor Mode */ + + sprintf(TrueLabel,GenerateLabel(0,1)); + fprintf(fp, "\t\t test byte [%s],20h \t\t\t; Supervisor Mode ?\n",REG_SRH); + fprintf(fp, "\t\t je near %s\n\n",TrueLabel); + + /* Get SR - Save in EBX */ + + fprintf(fp, "\t\t mov edi,[%s]\n",REG_A7); + fprintf(fp, "\t\t add dword [%s],byte 6\n",REG_A7); + Memory_Read('W',EDI,"-----DB",2); + fprintf(fp, "\t\t add edi,byte 2\n"); + fprintf(fp, "\t\t mov esi,eax\n"); + + /* Get PC */ + + Memory_Read('L',EDI,"----S-B",0); + fprintf(fp, "\t\t xchg esi,eax\n"); + + /* Update CCR (and A7) */ + + WriteCCR('W'); + + MemoryBanking(BaseCode); + Completed(); + + fprintf(fp, "%s:\n",TrueLabel); + Exception(8,0x10000+BaseCode); + + OpcodeArray[BaseCode] = BaseCode; +} + +void trapv(void) +{ + int BaseCode = 0x4E76; + char * Label; + + if (OpcodeArray[BaseCode] == -2) + { + Align(); + Label = GenerateLabel(BaseCode,0); + fprintf(fp, "%s\n", Label ); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + TimingCycles += 4; + + fprintf(fp, "\t\t test dh,08h\n"); + fprintf(fp, "\t\t jz near OP%d_%4.4x_Clear\n",CPU,BaseCode); + Exception(7,BaseCode); + + fprintf(fp, "OP%d_%4.4x_Clear:\n",CPU,BaseCode); + Completed(); + } + OpcodeArray[BaseCode] = BaseCode ; +} + +void illegal_opcode(void) +{ + Align(); + fprintf(fp, "ILLEGAL:\n"); + fprintf(fp, "\t\t mov [_illegal_op],ecx\n"); + fprintf(fp, "\t\t mov [_illegal_pc],esi\n"); + +#ifdef MAME_DEBUG + fprintf(fp, "\t\t jmp ecx\n"); + fprintf(fp, "\t\t pushad\n"); + fprintf(fp, "\t\t call _m68k_illegal_opcode\n"); + fprintf(fp, "\t\t popad\n"); +#endif + + Exception(4,0xFFFE); +} + +/* + * Return from subroutine + * restoring flags as well + * + */ + +void ReturnandRestore(void) +{ + int BaseCode = 0x4e77; + + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + SavePreviousPC(); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + TimingCycles += 20; + + /* Get SR into ESI */ + + fprintf(fp, "\t\t mov edi,[%s]\n",REG_A7); + fprintf(fp, "\t\t add dword [%s],byte 6\n",REG_A7); + + Memory_Read('W',EDI,"-----DB",2); + fprintf(fp, "\t\t add edi,byte 2\n"); + fprintf(fp, "\t\t mov esi,eax\n"); + + /* Get PC */ + + Memory_Read('L',EDI,"----SDB",0); + fprintf(fp, "\t\t xchg esi,eax\n"); + + /* Update flags */ + + WriteCCR('B'); + + MemoryBanking(BaseCode); + Completed(); + + OpcodeArray[BaseCode] = BaseCode; +} + +/* + * Return from Subroutine + * + */ + +void rts(void) +{ + int BaseCode = 0x4e75 ; + + if (OpcodeArray[BaseCode] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + SavePreviousPC(); + + TimingCycles += 16; + + OpcodeArray[BaseCode] = BaseCode ; + + fprintf(fp, "\t\t mov eax,[%s]\n",REG_A7); + fprintf(fp, "\t\t add dword [%s],byte 4\n",REG_A7); + Memory_Read('L',EAX,"---D--B",1); + fprintf(fp, "\t\t mov esi,eax\n"); + MemoryBanking(BaseCode); + Completed(); + } +} + +void jmp_jsr(void) +{ + int Opcode, BaseCode ; + int dreg,mode,type ; + int Dest ; + char allow[] = "--2--56789a-----" ; + + for (type = 0 ; type < 2 ; type++) + for (mode = 0 ; mode < 8 ; mode++) + for (dreg = 0 ; dreg < 8 ; dreg++) + { + Opcode = 0x4e80 | (type<<6) | (mode<<3) | dreg ; + BaseCode = Opcode & 0x4ef8 ; + if (mode == 7) + BaseCode = BaseCode | dreg ; + + Dest = EAtoAMN(BaseCode, FALSE); + if (allow[Dest&0x0f] != '-') + { + if (OpcodeArray[BaseCode] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + SavePreviousPC(); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + switch (mode) + { + case 2: + TimingCycles += 8; + break; + case 5: + case 7: + case 9: + TimingCycles += 10; + break; + case 8: + TimingCycles += 12; + break; + case 6: + case 10: + TimingCycles += 14; + break; + } + + if (type == 0) /* jsr takes 8 more than jmp */ + TimingCycles += 8; + + if (mode < 7) + { + fprintf(fp, "\t\t and ecx,byte 7\n"); + } + EffectiveAddressCalculate(Dest,'L',ECX,TRUE); + + /* jsr needs to push PC onto stack */ + + if (type == 0) + { + PushPC(EBX,EAX,"---D-DB",1); + } + + fprintf(fp, "\t\t mov esi,edi\n"); + MemoryBanking(BaseCode); + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } + } +} + +void cmpm(void) +{ + int Opcode, BaseCode ; + int regx,leng,regy ; + int ModeModX, ModeModY; + char Size=' ' ; + char * Regname="" ; + char * RegnameEBX="" ; + + for (regx = 0 ; regx < 8 ; regx++) + for (leng = 0 ; leng < 3 ; leng++) + for (regy = 0 ; regy < 8 ; regy++) + { + Opcode = 0xb108 | (regx<<9) | (leng<<6) | regy ; + BaseCode = Opcode & 0xb1c8 ; + + ModeModX = 0; + ModeModY = 0; + +#ifdef A7ROUTINE + if (leng==0) + { + if (regx==7) + { + BaseCode |= (regx<<9); + ModeModX = 16; + } + + if (regy==7) + { + BaseCode |= regy; + ModeModY = 16; + } + } +#endif + + switch (leng) + { + case 0: + Size = 'B'; + Regname = regnamesshort[EAX]; + RegnameEBX = regnamesshort[EBX]; + break; + case 1: + Size = 'W'; + Regname = regnamesword[EAX]; + RegnameEBX = regnamesword[EBX]; + break; + case 2: + Size = 'L'; + Regname = regnameslong[EAX]; + RegnameEBX = regnameslong[EBX]; + break; + } + + if (OpcodeArray[BaseCode] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + SavePreviousPC(); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + AddEACycles = 0 ; + + if (Size != 'L') + TimingCycles += 12 ; + else + TimingCycles += 20 ; + + fprintf(fp, "\t\t mov ebx,ecx\n"); + fprintf(fp, "\t\t and ebx, byte 7\n"); + fprintf(fp, "\t\t shr ecx, byte 9\n"); + fprintf(fp, "\t\t and ecx, byte 7\n"); + + EffectiveAddressRead(3+ModeModY,Size,EBX,EBX,"--C-S-B",FALSE); + EffectiveAddressRead(3+ModeModX,Size,ECX,EAX,"-B--S-B",FALSE); + + fprintf(fp, "\t\t cmp %s,%s\n",Regname,RegnameEBX); + SetFlags(Size,EAX,FALSE,FALSE,FALSE); + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } +} + +void exg(void) +{ + int Opcode, BaseCode ; + int regx,type,regy ; + int opmask[3] = { 0x08, 0x09, 0x11} ; + + for (regx = 0 ; regx < 8 ; regx++) + for (type = 0 ; type < 3 ; type++) + for (regy = 0 ; regy < 8 ; regy++) + { + Opcode = 0xc100 | (regx<<9) | (opmask[type]<<3) | regy ; + BaseCode = Opcode & 0xc1c8 ; + + if (OpcodeArray[BaseCode] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + TimingCycles += 6 ; + + fprintf(fp, "\t\t mov ebx,ecx\n"); + fprintf(fp, "\t\t and ebx,byte 7\n"); + fprintf(fp, "\t\t shr ecx,byte 9\n"); + fprintf(fp, "\t\t and ecx,byte 7\n"); + + if (type == 0) + { + fprintf(fp, "\t\t mov eax,[%s+ECX*4]\n",REG_DAT); + fprintf(fp, "\t\t mov edi,[%s+EBX*4]\n",REG_DAT); + fprintf(fp, "\t\t mov [%s+ECX*4],edi\n",REG_DAT); + fprintf(fp, "\t\t mov [%s+EBX*4],eax\n",REG_DAT); + } + if (type == 1) + { + fprintf(fp, "\t\t mov eax,[%s+ECX*4]\n",REG_ADD); + fprintf(fp, "\t\t mov edi,[%s+EBX*4]\n",REG_ADD); + fprintf(fp, "\t\t mov [%s+ECX*4],edi\n",REG_ADD); + fprintf(fp, "\t\t mov [%s+EBX*4],eax\n",REG_ADD); + } + if (type == 2) + { + fprintf(fp, "\t\t mov eax,[%s+ECX*4]\n",REG_DAT); + fprintf(fp, "\t\t mov edi,[%s+EBX*4]\n",REG_ADD); + fprintf(fp, "\t\t mov [%s+ECX*4],edi\n",REG_DAT); + fprintf(fp, "\t\t mov [%s+EBX*4],eax\n",REG_ADD); + } + + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } +} + +void ext(void) +{ + int Opcode, BaseCode ; + int type,regy ; + + for (type = 2 ; type < 8 ; type++) + for (regy = 0 ; regy < 8 ; regy++) + { + if (type > 3 && type < 7) + continue ; + Opcode = 0x4800 | (type<<6) | regy ; + BaseCode = Opcode & 0x48c0 ; + + if (OpcodeArray[BaseCode] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + TimingCycles += 4 ; + + fprintf(fp, "\t\t and ecx, byte 7\n"); + + if (type == 2) /* byte to word */ + { + fprintf(fp, "\t\t movsx eax,byte [%s+ECX*4]\n",REG_DAT); + fprintf(fp, "\t\t mov [%s+ECX*4],ax\n",REG_DAT); + SetFlags('W',EAX,TRUE,FALSE,FALSE); + } + if (type == 3) /* word to long */ + { + fprintf(fp, "\t\t movsx eax,word [%s+ECX*4]\n",REG_DAT); + fprintf(fp, "\t\t mov [%s+ECX*4],eax\n",REG_DAT); + SetFlags('L',EAX,TRUE,FALSE,FALSE); + } + if (type == 7) /* byte to long */ + { + fprintf(fp, "\t\t movsx eax,byte [%s+ECX*4]\n",REG_DAT); + fprintf(fp, "\t\t mov [%s+ECX*4],eax\n",REG_DAT); + SetFlags('L',EAX,TRUE,FALSE,FALSE); + } + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } +} + +void swap(void) +{ + int Opcode, BaseCode ; + int sreg ; + + for (sreg = 0 ; sreg < 8 ; sreg++) + { + Opcode = 0x4840 | sreg ; + BaseCode = Opcode & 0x4840; + + if (OpcodeArray[BaseCode] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + TimingCycles += 4 ; + + fprintf(fp, "\t\t and ecx, byte 7\n"); + fprintf(fp, "\t\t mov eax, dword [%s+ECX*4]\n",REG_DAT); + fprintf(fp, "\t\t ror eax, 16\n"); + fprintf(fp, "\t\t test eax,eax\n"); + fprintf(fp, "\t\t mov dword [%s+ECX*4],eax\n",REG_DAT); + SetFlags('L',EAX,FALSE,FALSE,FALSE); + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } +} + +/* + * Line A and Line F commands + * + */ + +void LineA(void) +{ + int Count; + + /* Line A */ + + Align(); + fprintf(fp, "%s:\n",GenerateLabel(0xA000,0)); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + Exception(0x0A,0xA000); + + for (Count=0xA000;Count<0xB000;Count++) + { + OpcodeArray[Count] = 0xA000; + } +} + +void LineF(void) +{ + int Count; + + /* Line F */ + + Align(); + fprintf(fp, "%s:\n",GenerateLabel(0xF000,0)); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + Exception(0x0B,0xF000); + + for (Count=0xF000;Count<0x10000;Count++) + { + OpcodeArray[Count] = 0xF000; + } +} + +/* + * Moves To/From CCR and SR + * + * (Move from CCR is 68010 command) + * + */ + +void movesr(void) +{ + int Opcode, BaseCode ; + int type, mode, sreg ; + int Dest ; + char allow[] = "0-2345678-------" ; + char Size; + + for (type = 0 ; type < 4 ; type++) + for (mode = 0 ; mode < 8 ; mode++) + for (sreg = 0 ; sreg < 8 ; sreg++) + { + Opcode = 0x40c0 | (type << 9) | ( mode << 3 ) | sreg ; + + /* To has extra modes */ + + if (type > 1) + { + allow[0x9] = '9'; + allow[0xa] = 'a'; + allow[0xb] = 'b' ; + } + + if ((type == 0) | (type == 3)) + Size = 'W'; /* SR */ + else + Size = 'B'; /* CCR */ + + BaseCode = Opcode & 0x46f8 ; + + if (mode == 7) + BaseCode |= sreg ; + + Dest = EAtoAMN(BaseCode, FALSE); + + if (allow[Dest&0xf] != '-') + { + if (OpcodeArray[BaseCode] == -2) + { + char TrueLabel[16]; + + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + + if ((Dest >= 2) && (Dest <=10)) + SavePreviousPC(); + + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + if (type > 1) /* move to */ + TimingCycles += 12 ; + else + { + if (mode < 2) + TimingCycles += 6 ; + else + TimingCycles += 8 ; + } + + /* If Move to SR then must be in Supervisor Mode */ + + if (type == 3) + { + sprintf(TrueLabel,GenerateLabel(0,1)); + + fprintf(fp, "\t\t test byte [%s],20h \t\t\t; Supervisor Mode ?\n",REG_SRH); + fprintf(fp, "\t\t je near %s\n\n",TrueLabel); + } + + /* 68010 Command ? */ + if (type==1) CheckCPUtype(1); + + + if (mode < 7) + { + fprintf(fp, "\t\t and ecx,byte 7\n"); + } + + /* Always read/write word 2 bytes */ + if (type < 2) + { + ReadCCR(Size,EBX); + EffectiveAddressWrite(Dest & 15,'W',ECX,TRUE,"---DS-B",TRUE); + } + else + { + EffectiveAddressRead(Dest & 15,'W',ECX,EAX,"----S-B",FALSE); + WriteCCR(Size); + } + Completed(); + + /* Exception if not Supervisor Mode */ + + if (type == 3) + { + /* Was in User Mode - Exception */ + + fprintf(fp, "%s:\n",TrueLabel); + Exception(8,BaseCode); + } + } + + OpcodeArray[Opcode] = BaseCode ; + } + } +} + +/* + * Decimal mode Add / Subtracts + * + */ + +void abcd_sbcd(void) +{ + int Opcode, BaseCode ; + int regx,type,rm,regy,mode ; + int ModeModX; + int ModeModY; + char *Label; + + for (type = 0 ; type < 2 ; type ++) /* 0=sbcd, 1=abcd */ + for (regx = 0 ; regx < 8 ; regx++) + for (rm = 0 ; rm < 2 ; rm++) + for (regy = 0 ; regy < 8 ; regy++) + { + Opcode = 0x8100 | (type<<14) | (regx<<9) | (rm<<3) | regy ; + BaseCode = Opcode & 0xc108 ; + + ModeModX = 0; + ModeModY = 0; + + if (rm == 0) + mode = 0 ; + else + { + mode = 4 ; + +#ifdef A7ROUTINE + + if (regx == 7) + { + BaseCode |= (regx << 9); + ModeModY = 16; + } + if (regy == 7) + { + BaseCode |= regy; + ModeModX = 16; + } + +#endif + } + + if (OpcodeArray[BaseCode] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + + if (mode == 4) + SavePreviousPC(); + + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + AddEACycles = 0 ; + + if (rm == 0) + TimingCycles += 6 ; + else + TimingCycles += 18 ; + + fprintf(fp, "\t\t mov ebx,ecx\n"); + fprintf(fp, "\t\t and ebx, byte 7\n"); + fprintf(fp, "\t\t shr ecx, byte 9\n"); + fprintf(fp, "\t\t and ecx, byte 7\n"); + + EffectiveAddressRead(mode+ModeModX,'B',EBX,EBX,"--C-S-B",TRUE); + EffectiveAddressRead(mode+ModeModY,'B',ECX,EAX,"-BC-SDB",TRUE); + + CopyX(); + + if (type == 0) + { + fprintf(fp, "\t\t sbb al,bl\n"); + fprintf(fp, "\t\t das\n"); + } + else + { + fprintf(fp, "\t\t adc al,bl\n"); + fprintf(fp, "\t\t daa\n"); + } + + /* Should only clear Zero flag if not zero */ + + Label = GenerateLabel(0,1); + + fprintf(fp, "\t\t mov ebx,edx\n"); + fprintf(fp, "\t\t setc dl\n"); + + fprintf(fp, "\t\t jnz short %s\n\n",Label); + + /* Keep original Zero flag */ + fprintf(fp, "\t\t and bl,40h ; Mask out Old Z\n"); + fprintf(fp, "\t\t or dl,bl ; Copy across\n\n"); + + fprintf(fp, "%s:\n",Label); + + fprintf(fp, "\t\t mov bl,dl\n"); /* copy carry into sign */ + fprintf(fp, "\t\t and bl,1\n"); + fprintf(fp, "\t\t shl bl,7\n"); + fprintf(fp, "\t\t and dl,7Fh\n"); + fprintf(fp, "\t\t or dl,bl\n"); + + fprintf(fp, "\t\t mov [%s],edx\n",REG_X); + + EffectiveAddressWrite(mode,'B',ECX,EAX,"---DS-B",TRUE); + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } +} + +/* + * Rotate Left / Right + * + */ + +void rol_ror(void) +{ + int Opcode, BaseCode ; + int dreg, dr, leng, ir, sreg ; + char Size=' '; + char * Label ; + char * Regname="" ; + char * RegnameECX ; + + for (dreg = 0 ; dreg < 8 ; dreg++) + for (dr = 0 ; dr < 2 ; dr++) + for (leng = 0 ; leng < 3 ; leng++) + for (ir = 0 ; ir < 2 ; ir++) + for (sreg = 0 ; sreg < 8 ; sreg++) + { + Opcode = 0xe018 | (dreg<<9) | (dr<<8) | (leng<<6) | (ir<<5) | sreg ; + BaseCode = Opcode & 0xe1f8 ; + + switch (leng) + { + case 0: + Size = 'B'; + Regname = regnamesshort[0]; + RegnameECX = regnamesshort[ECX]; + break; + case 1: + Size = 'W'; + Regname = regnamesword[0]; + RegnameECX = regnamesword[ECX]; + break; + case 2: + Size = 'L'; + Regname = regnameslong[0]; + RegnameECX = regnameslong[ECX]; + break; + } + + if (OpcodeArray[ BaseCode ] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + if (Size != 'L') + TimingCycles += 6 ; + else + TimingCycles += 8 ; + + fprintf(fp, "\t\t mov ebx,ecx\n"); + fprintf(fp, "\t\t and ebx,byte 7\n"); + fprintf(fp, "\t\t shr ecx,byte 9\n"); + + if (ir == 0) + { + Immediate8(); + } + else + { + fprintf(fp, "\t\t and ecx,byte 7\n"); + EffectiveAddressRead(0,'L',ECX,ECX,"-B--S-B",FALSE); + fprintf(fp, "\t\t and ecx,byte 63\n"); + } + + EffectiveAddressRead(0,Size,EBX,EAX,"-BC-S-B",FALSE); + + /* shift 0 - no time, no shift and clear carry */ + + Label = GenerateLabel(0,1); + fprintf(fp, "\t\t jecxz %s\n",Label); + + /* allow 2 cycles per shift */ + + fprintf(fp, "\t\t mov edx,ecx\n"); + fprintf(fp, "\t\t add edx,edx\n"); + fprintf(fp, "\t\t sub dword [%s],edx\n",ICOUNT); + + if (dr == 0) + fprintf(fp, "\t\t ror %s,cl\n",Regname); + else + fprintf(fp, "\t\t rol %s,cl\n",Regname); + + fprintf(fp, "\t\t setc ch\n"); + + fprintf(fp, "%s:\n",Label); + + SetFlags(Size,EAX,TRUE,FALSE,FALSE); +/* fprintf(fp, "\t\t and dl,254\n"); Test clears Carry */ + fprintf(fp, "\t\t or dl,ch\n"); + + EffectiveAddressWrite(0,Size,EBX,EAX,"--C-S-B",TRUE); + + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } +} + +void rol_ror_ea(void) +{ + int Opcode, BaseCode ; + int dr, mode, sreg ; + int Dest ; + char allow[] = "--2345678-------" ; + + for (dr = 0 ; dr < 2 ; dr++) + for (mode = 0 ; mode < 8 ; mode++) + for (sreg = 0 ; sreg < 8 ; sreg++) + { + Opcode = 0xe6c0 | (dr<<8) | (mode<<3) | sreg ; + BaseCode = Opcode & 0xfff8 ; + + if (mode == 7) + BaseCode |= sreg ; + + Dest = EAtoAMN(BaseCode, FALSE); + + if (allow[Dest&0xf] != '-') + { + if (OpcodeArray[ BaseCode ] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + + if ((Dest >= 2) && (Dest <=10)) + SavePreviousPC(); + + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + TimingCycles += 8 ; + + fprintf(fp, "\t\t and ecx,byte 7\n"); + EffectiveAddressRead(Dest&0xf,'W',ECX,EAX,"--C-SDB",FALSE); + + if (dr == 0) + fprintf(fp, "\t\t ror ax,1\n"); + else + fprintf(fp, "\t\t rol ax,1\n"); + + fprintf(fp, "\t\t setc bl\n"); + SetFlags('W',EAX,TRUE,FALSE,FALSE); +/* fprintf(fp, "\t\t and dl,254\n"); Test clears Carry */ + fprintf(fp, "\t\t or dl,bl\n"); + + EffectiveAddressWrite(Dest&0xf,'W',ECX,EAX,"---DS-B",TRUE); + + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } + } +} + +/* + * Logical Shift Left / Right + * + */ + +void lsl_lsr(void) +{ + int Opcode, BaseCode ; + int dreg, dr, leng, ir, sreg ; + char Size=' '; + char * Regname="" ; + char * RegnameECX="" ; + char * RegnameEDX="" ; + char * Label ; + + for (dreg = 0 ; dreg < 8 ; dreg++) + for (dr = 0 ; dr < 2 ; dr++) + for (leng = 0 ; leng < 3 ; leng++) + for (ir = 0 ; ir < 2 ; ir++) + for (sreg = 0 ; sreg < 8 ; sreg++) + { + Opcode = 0xe008 | (dreg<<9) | (dr<<8) | (leng<<6) | (ir<<5) | sreg ; + BaseCode = Opcode & 0xe1f8 ; + + switch (leng) + { + case 0: + Size = 'B'; + Regname = regnamesshort[0]; + RegnameECX = regnamesshort[ECX]; + RegnameEDX = regnamesshort[EDX]; + break; + case 1: + Size = 'W'; + Regname = regnamesword[0]; + RegnameECX = regnamesword[ECX]; + RegnameEDX = regnamesword[EDX]; + break; + case 2: + Size = 'L'; + Regname = regnameslong[0]; + RegnameECX = regnameslong[ECX]; + RegnameEDX = regnameslong[EDX]; + break; + } + + if (OpcodeArray[ BaseCode ] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + if (Size != 'L') + TimingCycles += 6 ; + else + TimingCycles += 8 ; + + fprintf(fp, "\t\t mov ebx,ecx\n"); + fprintf(fp, "\t\t and ebx,byte 7\n"); + fprintf(fp, "\t\t shr ecx,byte 9\n"); + + if (ir == 0) + { + Immediate8(); + } + else + { + fprintf(fp, "\t\t and ecx,byte 7\n"); + EffectiveAddressRead(0,'L',ECX,ECX,"-B--S-B",FALSE); + fprintf(fp, "\t\t and ecx,byte 63\n"); + } + + /* and 2 cycles per shift */ + + fprintf(fp, "\t\t mov edx,ecx\n"); + fprintf(fp, "\t\t add edx,edx\n"); + fprintf(fp, "\t\t sub dword [%s],edx\n",ICOUNT); + + EffectiveAddressRead(0,Size,EBX,EAX,"-BC-S-B",FALSE); + + /* ASG: on the 68k, the shift count is mod 64; on the x86, the */ + /* shift count is mod 32; we need to check for shifts of 32-63 */ + /* and produce zero */ + Label = GenerateLabel(0,1); + fprintf(fp, "\t\t test cl,0x20\n"); + fprintf(fp, "\t\t jnz %s_BigShift\n",Label); + + fprintf(fp, "%s_Continue:\n",Label); + if (dr == 0) + fprintf(fp, "\t\t shr %s,cl\n",Regname); + else + fprintf(fp, "\t\t shl %s,cl\n",Regname); + + SetFlags(Size,EAX,FALSE,FALSE,FALSE); + + /* Clear Overflow flag */ + fprintf(fp, "\t\t xor dh,dh\n"); + + EffectiveAddressWrite(0,Size,EBX,EAX,"--CDS-B",TRUE); + + /* if shift count is zero clear carry */ + + fprintf(fp, "\t\t jecxz %s\n",Label); + + fprintf(fp, "\t\t mov [%s],edx\n",REG_X); + Completed(); + + Align(); + fprintf(fp, "%s:\n",Label); + fprintf(fp, "\t\t and dl,254\t\t;clear C flag\n"); + Completed(); + + fprintf(fp, "%s_BigShift:\n",Label); + if (dr == 0) + { + fprintf(fp, "\t\t shr %s,16\n",Regname); + fprintf(fp, "\t\t shr %s,16\n",Regname); + } + else + { + fprintf(fp, "\t\t shl %s,16\n",Regname); + fprintf(fp, "\t\t shl %s,16\n",Regname); + } + fprintf(fp, "\t\t jmp %s_Continue\n",Label); + } + + OpcodeArray[Opcode] = BaseCode ; + } +} + +void lsl_lsr_ea(void) +{ + int Opcode, BaseCode ; + int dr, mode, sreg ; + int Dest ; + char allow[] = "--2345678-------" ; + + for (dr = 0 ; dr < 2 ; dr++) + for (mode = 0 ; mode < 8 ; mode++) + for (sreg = 0 ; sreg < 8 ; sreg++) + { + Opcode = 0xe2c0 | (dr<<8) | (mode<<3) | sreg ; + BaseCode = Opcode & 0xfff8 ; + + if (mode == 7) + BaseCode |= sreg ; + + Dest = EAtoAMN(BaseCode, FALSE); + + if (allow[Dest&0xf] != '-') + { + if (OpcodeArray[ BaseCode ] == -2) + { + + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + + if ((Dest >= 2) && (Dest <=10)) + SavePreviousPC(); + + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + TimingCycles += 8 ; + + fprintf(fp, "\t\t and ecx,byte 7\n"); + EffectiveAddressRead(Dest&0xf,'W',ECX,EAX,"--C-SDB",FALSE); + + if (dr == 0) + fprintf(fp, "\t\t shr ax,1\n"); + else + fprintf(fp, "\t\t shl ax,1\n"); + + SetFlags('W',EAX,FALSE,TRUE,FALSE); + + /* Clear Overflow flag */ + + fprintf(fp, "\t\t xor dh,dh\n"); + + EffectiveAddressWrite(Dest&0xf,'W',ECX,EAX,"---DS-B",TRUE); + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } + } +} + +/* + * Rotate Left / Right though Extend + * + */ + +void roxl_roxr(void) +{ + int Opcode, BaseCode ; + int dreg, dr, leng, ir, sreg ; + char Size=' ' ; + char * Regname="" ; + char * RegnameECX="" ; + char * Label ; + + for (dreg = 0 ; dreg < 8 ; dreg++) + for (dr = 0 ; dr < 2 ; dr++) + for (leng = 0 ; leng < 3 ; leng++) + for (ir = 0 ; ir < 2 ; ir++) + for (sreg = 0 ; sreg < 8 ; sreg++) + { + Opcode = 0xe010 | (dreg<<9) | (dr<<8) | (leng<<6) | (ir<<5) | sreg ; + BaseCode = Opcode & 0xe1f8 ; + + switch (leng) + { + case 0: + Size = 'B'; + Regname = regnamesshort[0]; + RegnameECX = regnamesshort[ECX]; + break; + case 1: + Size = 'W'; + Regname = regnamesword[0]; + RegnameECX = regnamesword[ECX]; + break; + case 2: + Size = 'L'; + Regname = regnameslong[0]; + RegnameECX = regnameslong[ECX]; + break; + } + + if (OpcodeArray[ BaseCode ] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + if (Size != 'L') + TimingCycles += 6 ; + else + TimingCycles += 8 ; + + fprintf(fp, "\t\t mov ebx,ecx\n"); + fprintf(fp, "\t\t and ebx,byte 7\n"); + fprintf(fp, "\t\t shr ecx,byte 9\n"); + + if (ir == 0) + { + Immediate8(); + } + else + { + fprintf(fp, "\t\t and ecx,byte 7\n"); + EffectiveAddressRead(0,'L',ECX,ECX,"-B--S-B",FALSE); + fprintf(fp, "\t\t and ecx,byte 63\n"); + } + + /* allow 2 cycles per shift */ + + fprintf(fp, "\t\t mov edx,ecx\n"); + fprintf(fp, "\t\t add edx,edx\n"); + fprintf(fp, "\t\t sub dword [%s],edx\n",ICOUNT); + + EffectiveAddressRead(0,Size,EBX,EAX,"-BC-SDB",FALSE); + + /* move X into C so RCR & RCL can be used */ + /* RCR & RCL only set the carry flag */ + + CopyX(); + + if (dr == 0) + fprintf(fp, "\t\t rcr %s,cl\n",Regname); + else + fprintf(fp, "\t\t rcl %s,cl\n",Regname); + + fprintf(fp, "\t\t setc ch\n"); + SetFlags(Size,EAX,TRUE,FALSE,FALSE); +/* fprintf(fp, "\t\t and dl,254\n"); Test Clears Carry */ + + EffectiveAddressWrite(0,Size,EBX,EAX,"--CDS-B",TRUE); + + /* if shift count is zero clear carry */ + + Label = GenerateLabel(0,1); + fprintf(fp, "\t\t test cl,cl\n"); + fprintf(fp, "\t\t jz %s\n",Label); + + /* Add in Carry Flag */ + + fprintf(fp, "\t\t or dl,ch\n"); + fprintf(fp, "\t\t mov [%s],dl\n",REG_X); + Completed(); + + + /* copy X onto C when shift is zero */ + + Align(); + fprintf(fp, "%s:\n",Label); + fprintf(fp, "\t\t mov ecx,[%s]\n",REG_X); + fprintf(fp, "\t\t and ecx,byte 1\n"); + fprintf(fp, "\t\t or edx,ecx\n"); + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } +} + +void roxl_roxr_ea(void) +{ + int Opcode, BaseCode ; + int dr, mode, sreg ; + int Dest ; + char allow[] = "--2345678-------" ; + + for (dr = 0 ; dr < 2 ; dr++) + for (mode = 0 ; mode < 8 ; mode++) + for (sreg = 0 ; sreg < 8 ; sreg++) + { + Opcode = 0xe4c0 | (dr<<8) | (mode<<3) | sreg ; + BaseCode = Opcode & 0xfff8 ; + + if (mode == 7) + BaseCode |= sreg ; + + Dest = EAtoAMN(BaseCode, FALSE); + + if (allow[Dest&0xf] != '-') + { + if (OpcodeArray[ BaseCode ] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + + if ((Dest >= 2) && (Dest <=10)) + SavePreviousPC(); + + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + TimingCycles += 8 ; + + fprintf(fp, "\t\t and ecx,byte 7\n"); + EffectiveAddressRead(Dest&0xf,'W',ECX,EAX,"--C-SDB",FALSE); + + /* move X into C so RCR & RCL can be used */ + /* RCR & RCL only set the carry flag */ + + CopyX(); + + if (dr == 0) + fprintf(fp, "\t\t rcr ax,1\n"); + else + fprintf(fp, "\t\t rcl ax,1\n"); + + fprintf(fp, "\t\t setc bl\n"); + SetFlags('W',EAX,TRUE,FALSE,FALSE); +/* fprintf(fp, "\t\t and dl,254\n"); - Intel Clears on Test */ + fprintf(fp, "\t\t or dl,bl\n"); + + EffectiveAddressWrite(Dest&0xf,'W',ECX,EAX,"---DS-B",TRUE); + + fprintf(fp, "\t\t mov [%s],edx\n",REG_X); + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } + } +} + +/* + * Arithmetic Shift Left / Right + * + */ + +void asl_asr(void) +{ + int Opcode, BaseCode ; + int dreg, dr, leng, ir, sreg ; + char Size=' '; + char * Sizename="" ; + char * Regname="" ; + char * RegnameEDX="" ; + char * RegnameECX="" ; + char * Label; + + /* Normal routines for codes */ + + for (dreg = 0 ; dreg < 8 ; dreg++) + for (dr = 0 ; dr < 2 ; dr++) + for (leng = 0 ; leng < 3 ; leng++) + for (ir = 0 ; ir < 2 ; ir++) + for (sreg = 0 ; sreg < 8 ; sreg++) + { + Opcode = 0xe000 | (dreg<<9) | (dr<<8) | (leng<<6) | (ir<<5) | sreg ; + BaseCode = Opcode & 0xe1f8 ; + + switch (leng) + { + case 0: + Size = 'B'; + Regname = regnamesshort[0]; + RegnameECX = regnamesshort[ECX]; + RegnameEDX = regnamesshort[EDX]; + break; + case 1: + Size = 'W'; + Regname = regnamesword[0]; + RegnameECX = regnamesword[ECX]; + RegnameEDX = regnamesword[EDX]; + break; + case 2: + Size = 'L'; + Regname = regnameslong[0]; + RegnameECX = regnameslong[ECX]; + RegnameEDX = regnameslong[EDX]; + break; + } + + if (OpcodeArray[ BaseCode ] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + Label = GenerateLabel(0,1); + + if (Size != 'L') + TimingCycles += 6 ; + else + TimingCycles += 8 ; + + fprintf(fp, "\t\t mov ebx,ecx\n"); + fprintf(fp, "\t\t and ebx,byte 7\n"); + fprintf(fp, "\t\t shr ecx,byte 9\n"); + + EffectiveAddressRead(0,Size,EBX,EAX,"-BC-S-B",FALSE); + + if (ir == 0) + { + Immediate8(); + } + else + { + fprintf(fp, "\t\t and ecx,byte 7\n"); + EffectiveAddressRead(0,'L',ECX,ECX,"-B--S-B",FALSE); + fprintf(fp, "\t\t and ecx,byte 63\n"); + fprintf(fp, "\t\t jz short %s\n",Label); + } + + /* allow 2 cycles per shift */ + + fprintf(fp, "\t\t mov edx,ecx\n"); + fprintf(fp, "\t\t add edx,edx\n"); + fprintf(fp, "\t\t sub dword [%s],edx\n",ICOUNT); + + if (dr == 0) + { + /* ASR */ + + /* ASG: on the 68k, the shift count is mod 64; on the x86, the */ + /* shift count is mod 32; we need to check for shifts of 32-63 */ + /* and effectively shift 31 */ + fprintf(fp, "\t\t shrd edx,ecx,6\n"); + fprintf(fp, "\t\t sar edx,31\n"); + fprintf(fp, "\t\t and edx,31\n"); + fprintf(fp, "\t\t or ecx,edx\n"); + + fprintf(fp, "\t\t sar %s,cl\n",Regname); + + /* Mode 0 write does not affect Flags */ + EffectiveAddressWrite(0,Size,EBX,EAX,"---DS-B",TRUE); + + /* Update Flags */ + fprintf(fp, "\t\t lahf\n"); + +#ifdef STALLCHECK + ClearRegister(EDX); + fprintf(fp, "\t\t mov dl,ah\n"); +#else + fprintf(fp, "\t\t movzx edx,ah\n"); +#endif + + fprintf(fp, "\t\t mov [%s],edx\n",REG_X); + } + else + { + /* ASL */ + + /* Check to see if Overflow should be set */ + + fprintf(fp,"\t\t mov edi,eax\t\t; Save It\n"); + + ClearRegister(EDX); + fprintf(fp,"\t\t stc\n"); + fprintf(fp,"\t\t rcr %s,1\t\t; d=1xxxx\n",RegnameEDX); + fprintf(fp,"\t\t sar %s,cl\t\t; d=1CCxx\n",RegnameEDX); + fprintf(fp,"\t\t and eax,edx\n"); + fprintf(fp,"\t\t jz short %s_V\t\t; No Overflow\n",Label); + fprintf(fp,"\t\t cmp eax,edx\n"); + fprintf(fp,"\t\t je short %s_V\t\t; No Overflow\n",Label); + + /* Set Overflow */ + fprintf(fp,"\t\t mov edx,0x800\n"); + fprintf(fp,"\t\t jmp short %s_OV\n",Label); + + fprintf(fp,"%s_V:\n",Label); + ClearRegister(EDX); + + fprintf(fp,"%s_OV:\n",Label); + + /* more than 31 shifts and long */ + + if ((ir==1) && (leng==2)) + { + fprintf(fp,"\t\t test cl,0x20\n"); + fprintf(fp,"\t\t jnz short %s_32\n\n",Label); + } + + fprintf(fp,"\t\t mov eax,edi\t\t; Restore It\n"); + + fprintf(fp, "\t\t sal %s,cl\n",Regname); + + EffectiveAddressWrite(0,Size,EBX,EAX,"---DS-B",TRUE); + fprintf(fp, "\t\t lahf\n"); + fprintf(fp, "\t\t mov dl,ah\n"); + fprintf(fp, "\t\t mov [%s],edx\n",REG_X); + } + Completed(); + + if (ir != 0) + { + Align(); + fprintf(fp, "%s:\n",Label); + + + if (dr == 0) + { + /* ASR - Test clears V and C */ + SetFlags(Size,EAX,TRUE,FALSE,FALSE); + } + else + { + /* ASL - Keep existing Carry flag, Clear V */ + fprintf(fp, "\t\t mov ebx,edx\n"); + fprintf(fp, "\t\t and ebx,byte 1\n"); + SetFlags(Size,EAX,TRUE,FALSE,FALSE); + fprintf(fp, "\t\t or edx,ebx\n"); + + if (leng==2) + { + Completed(); + + /* > 31 Shifts */ + + fprintf(fp, "%s_32:\n",Label); + fprintf(fp, "\t\t mov dl,40h\n"); // Zero flag + ClearRegister(EAX); + EffectiveAddressWrite(0,Size,EBX,EAX,"----S-B",TRUE); + } + } + + Completed(); + } + } + + OpcodeArray[Opcode] = BaseCode ; + } + + /* End with special routines for ASL.x #1,Dx */ + /* To do correct V setting, ASL needs quite a */ + /* bit of additional code. A Shift of one has */ + /* correct flags on Intel, and is very common */ + /* in 68000 programs. */ + + for (leng = 0 ; leng < 3 ; leng++) + for (sreg = 0 ; sreg < 8 ; sreg++) + { + Opcode = 0xe300 | (leng<<6) | sreg ; + BaseCode = Opcode & 0xe3c8 ; + + switch (leng) + { + case 0: + Sizename = "byte"; + break; + case 1: + Sizename = "word"; + break; + case 2: + Sizename = "long"; + break; + } + + if (sreg == 0) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + Label = GenerateLabel(0,1); + + if (Size != 'L') + TimingCycles += 6 ; + else + TimingCycles += 8 ; + + fprintf(fp, "\t\t and ecx,byte 7\n"); + fprintf(fp, "\t\t sal %s [%s+ecx*4],1\n",Sizename,REG_DAT); + SetFlags('L',EAX,FALSE,TRUE,FALSE); + Completed(); + + } + + OpcodeArray[Opcode] = BaseCode ; + } +} + +void asl_asr_ea(void) +{ + int Opcode, BaseCode ; + int dr, mode, sreg ; + int Dest ; + char allow[] = "--2345678-------" ; + + for (dr = 0 ; dr < 2 ; dr++) + for (mode = 0 ; mode < 8 ; mode++) + for (sreg = 0 ; sreg < 8 ; sreg++) + { + Opcode = 0xe0c0 | (dr<<8) | (mode<<3) | sreg ; + BaseCode = Opcode & 0xfff8 ; + + if (mode == 7) + BaseCode |= sreg ; + + Dest = EAtoAMN(BaseCode, FALSE); + + if (allow[Dest&0xf] != '-') + { + if (OpcodeArray[ BaseCode ] == -2) + { + + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + + if ((Dest >= 2) && (Dest <=10)) + SavePreviousPC(); + + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + TimingCycles += 8 ; + + fprintf(fp, "\t\t and ecx,byte 7\n"); + EffectiveAddressRead(Dest&0xf,'W',ECX,EAX,"--C-SDB",FALSE); + + if (dr == 0) + fprintf(fp, "\t\t sar ax,1\n"); + else + fprintf(fp, "\t\t sal ax,1\n"); + + SetFlags('W',EAX,FALSE,TRUE,TRUE); + + EffectiveAddressWrite(Dest&0xf,'W',ECX,EAX,"----S-B",FALSE); + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } + } +} + +/* + * Divide Commands + */ + +void divides(void) +{ + int dreg, type, mode, sreg ; + int Opcode, BaseCode ; + int Dest ; + char allow[] = "0-23456789ab-----" ; + char TrapLabel[16]; + int Cycles; + + int divide_cycles[12] = + { + 38,0,42,42,44,46,50,46,50,46,48,42 + }; + + for (dreg = 0 ; dreg < 8 ; dreg++) + for (type = 0 ; type < 2 ; type++) + for (mode = 0 ; mode < 8 ; mode++) + for (sreg = 0 ; sreg < 8 ; sreg++) + { + Opcode = 0x80c0 | (dreg<<9) | (type<<8) | (mode<<3) | sreg ; + BaseCode = Opcode & 0x81f8 ; + if (mode == 7) + { + BaseCode |= sreg ; + } + + Dest = EAtoAMN(Opcode, FALSE); + if (allow[Dest&0x0f] != '-') + { + if (OpcodeArray[ BaseCode ] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + + if ((Dest >= 2) && (Dest <=10)) + SavePreviousPC(); + + fprintf(fp, "\t\t add esi,byte 2\n\n"); + + + /* Save EDX (in case of overflow) */ + + fprintf(fp, "\t\t and edx,byte -2\n"); + fprintf(fp, "\t\t mov [%s],edx\n",REG_CCR); + + + /* Cycle Timing (if succeeds OK) */ + + Cycles = divide_cycles[Dest & 0x0f] + 95 + (type * 17); + + if (Cycles > 127) + fprintf(fp, "\t\t sub dword [%s],%d\n",ICOUNT,Cycles); + else + fprintf(fp, "\t\t sub dword [%s],byte %d\n",ICOUNT,Cycles); + + if (mode < 7) + { + fprintf(fp, "\t\t mov ebx,ecx\n"); + fprintf(fp, "\t\t and ebx,byte 7\n"); + } + + fprintf(fp, "\t\t shr ecx, byte 9\n"); + fprintf(fp, "\t\t and ecx, byte 7\n"); + + sprintf(TrapLabel, "%s", GenerateLabel(0,1) ) ; + + EffectiveAddressRead(Dest,'W',EBX,EAX,"A-C-SDB",FALSE); /* source */ + + fprintf(fp, "\t\t test ax,ax\n"); + fprintf(fp, "\t\t je near %s_ZERO\t\t;do div by zero trap\n", TrapLabel); + + if (type == 1) /* signed */ + { + fprintf(fp, "\t\t movsx ebx,ax\n"); + } + else + { + fprintf(fp, "\t\t movzx ebx,ax\n"); + } + + EffectiveAddressRead(0,'L',ECX,EAX,"ABC-SDB",FALSE); /* dest */ + + if (type == 1) /* signed */ + { + fprintf(fp, "\t\t cdq\n"); /* EDX:EAX = 64 bit signed */ + fprintf(fp, "\t\t idiv ebx\n"); /* EBX = 32 bit */ + + /* Check for Overflow */ + + fprintf(fp, "\t\t movsx ebx,ax\n"); + fprintf(fp, "\t\t cmp eax,ebx\n"); + fprintf(fp, "\t\t jne short %s_OVER\n",TrapLabel); + } + else + { + ClearRegister(EDX); + fprintf(fp, "\t\t div ebx\n"); + + /* Check for Overflow */ + + fprintf(fp, "\t\t test eax, 0FFFF0000H\n"); + fprintf(fp, "\t\t jnz short %s_OVER\n",TrapLabel); + } + + /* Sort out Result */ + + fprintf(fp, "\t\t shl edx, byte 16\n"); + fprintf(fp, "\t\t mov dx,ax\n"); + fprintf(fp, "\t\t mov [%s+ECX*4],edx\n",REG_DAT); + SetFlags('W',EDX,TRUE,FALSE,FALSE); + + Completed(); + + + /* Overflow */ + + Align(); + fprintf(fp, "%s_OVER:\n",TrapLabel); + fprintf(fp, "\t\t mov edx,[%s]\n",REG_CCR); + fprintf(fp, "\t\t or edx,0x0800\t\t;V flag\n"); + Completed(); + + + /* Division by Zero */ + + Align(); + fprintf(fp, "%s_ZERO:\t\t ;Do divide by zero trap\n", TrapLabel); + + /* Correct cycle counter for error */ + + fprintf(fp, "\t\t add dword [%s],byte %d\n",ICOUNT,95 + (type * 17)); + fprintf(fp, "\t\t mov al,5\n"); + Exception(-1,BaseCode); + Completed(); + } + + OpcodeArray[Opcode] = BaseCode ; + } + } +} + + +/* + * 68010 Extra Opcodes + * + * move from CCR is done above + * + */ + +void ReturnandDeallocate(void) +{ + int BaseCode = 0x4e74 ; + + if (OpcodeArray[BaseCode] == -2) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode,0)); + + CheckCPUtype(1); + + SavePreviousPC(); + + TimingCycles += 16; + + OpcodeArray[BaseCode] = BaseCode ; + + /* Get Return Address */ + + fprintf(fp, "\t\t mov eax,[%s]\n",REG_A7); + Memory_Read('L',EAX,"---D--B",1); + + + /* Get Displacement */ + + Memory_Fetch('W',EBX,TRUE); + + + /* Set PC = New Address */ + + fprintf(fp, "\t\t mov esi,eax\n"); + + + /* Correct Stack for Return Address and Displacement */ + + fprintf(fp, "\t\t add ebx,byte 4\n"); + fprintf(fp, "\t\t add dword [%s],ebx\n",REG_A7); + + MemoryBanking(BaseCode); + Completed(); + } +} + +void MoveControlRegister(void) +{ + int Direction; + int BaseCode = 0x4e7a ; + + for (Direction=0;Direction<2;Direction++) + { + Align(); + fprintf(fp, "%s:\n",GenerateLabel(BaseCode+Direction,0)); + + TimingCycles += 4; /* Assume same as move usp */ + + CheckCPUtype(1); + + fprintf(fp, "\t\t test byte [%s],20h \t\t\t; Supervisor Mode ?\n",REG_SRH); + fprintf(fp, "\t\t jz short OP%d_%4.4x_Trap\n",CPU,BaseCode+Direction); + + fprintf(fp, "\t\t add esi,byte 2\n"); + if (CPU==2) + fprintf(fp, "\t\t xor esi,2\n"); /* ASG */ +#ifdef STALLCHECK + ClearRegister(EBX); + fprintf(fp, "\t\t mov bx,[esi+ebp]\n"); +#else + fprintf(fp, "\t\t movzx ebx,word [esi+ebp]\n"); +#endif + if (CPU==2) + fprintf(fp, "\t\t xor esi,2\n"); /* ASG */ + + fprintf(fp, "\t\t add esi,byte 2\n"); + fprintf(fp, "\t\t mov eax,ebx\n"); + fprintf(fp, "\t\t mov ecx,ebx\n"); + + /* Sort out Register */ + + fprintf(fp, "\t\t shr ebx,12\n"); + + /* Sort out Control Register ID */ + + fprintf(fp, "\t\t and eax,byte 1\n"); + fprintf(fp, "\t\t shr ecx,10\n"); + fprintf(fp, "\t\t and ecx,2\n"); + fprintf(fp, "\t\t or ecx,eax\n"); + + if (Direction==0) + { + /* from Control */ + + fprintf(fp, "\t\t mov eax,[%s+ecx*4]\n",REG_SFC); + fprintf(fp, "\t\t mov %s,eax\n",REG_DAT_EBX); + } + else + { + /* To Control */ + + fprintf(fp, "\t\t mov eax,%s\n",REG_DAT_EBX); + + /* Mask out for SFC & DFC */ + + fprintf(fp, "\t\t test cl,2\n"); + fprintf(fp, "\t\t jne short OP%d_%4.4x_Mask\n",CPU,BaseCode+Direction); + fprintf(fp, "\t\t and eax,byte 7\n"); + fprintf(fp, "OP%d_%4.4x_Mask:\n",CPU,BaseCode+Direction); + + /* Write to control */ + + fprintf(fp, "\t\t mov [%s+ecx*4],eax\n",REG_SFC); + } + + Completed(); + + /* Not Supervisor Mode */ + + Align(); + fprintf(fp, "OP%d_%4.4x_Trap:\n",CPU,BaseCode+Direction); + Exception(8,BaseCode+Direction); + + OpcodeArray[BaseCode+Direction] = BaseCode+Direction; + } +} + +void MoveAddressSpace(void) +{ +} + +/* + * Generate Jump Table + * + */ + +void JumpTable(void) +{ + int Opcode,l,op; + + fprintf(fp, "DD OP%d_1000\n",CPU); + + l = 0 ; + for (Opcode=0x0;Opcode<0x10000;) + { + + op = OpcodeArray[Opcode]; + + fprintf(fp, "DD "); + + l = 1 ; + while (op == OpcodeArray[Opcode+l] && ((Opcode+l) & 0xfff) != 0) + { + l++ ; + } + + Opcode += l ; + + if (l > 255) + { + if (op > -1) + fprintf(fp, "OP%d_%4.4x - OP%d_1000\n",CPU,op,CPU); + else + fprintf(fp, "ILLEGAL - OP%d_1000\n",CPU); + + fprintf(fp, "DW %d\n", l); + } + else + { + if (op > -1) + fprintf(fp, "(OP%d_%4.4x - OP%d_1000) + (%d * 1000000h)\n",CPU,op,CPU,l); + else + fprintf(fp, "(ILLEGAL - OP%d_1000) + (%d * 1000000h)\n",CPU,l); + } + } +} + +void CodeSegmentBegin(void) +{ + +/* Messages */ + + fprintf(fp, "; Make68K - V%s - Copyright 1998, Mike Coates (mame@btinternet.com)\n", VERSION); + fprintf(fp, "; & Darren Olafson (deo@mail.island.net)\n\n"); + +/* Needed code to make it work! */ + + fprintf(fp, "\t\t BITS 32\n\n"); + + fprintf(fp, "\t\t GLOBAL %s_RUN\n",CPUtype); + fprintf(fp, "\t\t GLOBAL %s_RESET\n",CPUtype); + fprintf(fp, "\t\t GLOBAL %s_regs\n",CPUtype); + fprintf(fp, "\t\t GLOBAL %s_COMPTABLE\n",CPUtype); + fprintf(fp, "\t\t GLOBAL %s_OPCODETABLE\n",CPUtype); + + /* ASG - only one interface to memory now */ + fprintf(fp, "\t\t EXTERN _m68k_ICount\n"); + fprintf(fp, "\t\t EXTERN _a68k_memory_intf\n"); + fprintf(fp, "\t\t EXTERN _mem_amask\n"); + + fprintf(fp, "; Vars Mame declares / needs access to\n\n"); + + fprintf(fp, "\t\t EXTERN _mame_debug\n"); + fprintf(fp, "\t\t EXTERN _illegal_op\n"); + fprintf(fp, "\t\t EXTERN _illegal_pc\n"); + + fprintf(fp, "\t\t EXTERN _OP_ROM\n"); + fprintf(fp, "\t\t EXTERN _OP_RAM\n"); + + fprintf(fp, "\t\t EXTERN _opcode_entry\n"); + fprintf(fp, "\t\t EXTERN _cur_mrhard\n"); + +//#ifdef MAME_DEBUG + fprintf(fp, "\t\t EXTERN _m68k_illegal_opcode\n"); +//#endif + +#ifdef OS2 + fprintf(fp, "\t\t SECTION maincode USE32 FLAT CLASS=CODE\n\n"); +#else + fprintf(fp, "\t\t SECTION .text\n\n"); +#endif + + + +/* Reset routine */ + + fprintf(fp, "%s_RESET:\n",CPUtype); + + fprintf(fp, "\t\t pushad\n\n"); + + fprintf(fp, "; Build Jump Table (not optimised!)\n\n"); + + fprintf(fp, "\t\t lea edi,[%s_OPCODETABLE]\t\t; Jump Table\n", CPUtype); + fprintf(fp, "\t\t lea esi,[%s_COMPTABLE]\t\t; RLE Compressed Table\n", CPUtype); + + /* Reference Point in EBP */ + + fprintf(fp, "\t\t mov ebp,[esi]\n"); + fprintf(fp, "\t\t add esi,byte 4\n"); + + fprintf(fp, "RESET0:\n"); + fprintf(fp, "\t\t mov eax,[esi]\n"); + fprintf(fp, "\t\t mov ecx,eax\n"); + fprintf(fp, "\t\t and eax,0xffffff\n"); + fprintf(fp, "\t\t add eax,ebp\n"); + fprintf(fp, "\t\t add esi,byte 4\n"); + + /* if count is zero, then it's a word RLE length */ + + fprintf(fp, "\t\t shr ecx,24\n"); + fprintf(fp, "\t\t jne short RESET1\n"); + +#ifdef STALLCHECK + ClearRegister(ECX); + fprintf(fp, "\t\t mov cx,[esi]\t\t; Repeats\n"); +#else + fprintf(fp, "\t\t movzx ecx,word [esi]\t\t; Repeats\n"); +#endif + + fprintf(fp, "\t\t add esi,byte 2\n"); + fprintf(fp, "\t\t jecxz RESET2\t\t; Finished!\n"); + + fprintf(fp, "RESET1:\n"); + fprintf(fp, "\t\t mov [edi],eax\n"); + fprintf(fp, "\t\t add edi,byte 4\n"); + fprintf(fp, "\t\t dec ecx\n"); + fprintf(fp, "\t\t jnz short RESET1\n"); + fprintf(fp, "\t\t jmp short RESET0\n"); + + fprintf(fp, "RESET2:\n"); + fprintf(fp, "\t\t popad\n"); + fprintf(fp, "\t\t ret\n\n"); + +/* Emulation Entry Point */ + + Align(); + + fprintf(fp, "%s_RUN:\n",CPUtype); + + fprintf(fp, "\t\t pushad\n"); + fprintf(fp, "\t\t mov esi,[%s]\n",REG_PC); + fprintf(fp, "\t\t mov edx,[%s]\n",REG_CCR); + fprintf(fp, "\t\t mov ebp,dword [_OP_ROM]\n"); + + fprintf(fp,"; Check for Interrupt waiting\n\n"); + fprintf(fp,"\t\t test [%s],byte 07H\n",REG_IRQ); + fprintf(fp,"\t\t jne near interrupt\n\n"); + + fprintf(fp, "IntCont:\n"); + + /* See if was only called to check for Interrupt */ + + fprintf(fp, "\t\t test dword [%s],-1\n",ICOUNT); + fprintf(fp, "\t\t js short MainExit\n\n"); + + if(CPU==2) + { + /* 32 Bit */ + fprintf(fp, "\t\t mov eax,2\n"); /* ASG */ + fprintf(fp, "\t\t xor eax,esi\n"); /* ASG */ +#ifdef STALLCHECK + ClearRegister(ECX); + fprintf(fp, "\t\t mov cx,[eax+ebp]\n"); +#else + fprintf(fp, "\t\t movzx ecx,word [eax+ebp]\n"); +#endif + } + else + { + /* 16 Bit Fetch */ +#ifdef STALLCHECK + ClearRegister(ECX); + fprintf(fp, "\t\t mov cx,[esi+ebp]\n"); +#else + fprintf(fp, "\t\t movzx ecx,word [esi+ebp]\n"); +#endif + } + fprintf(fp, "\t\t jmp [%s_OPCODETABLE+ecx*4]\n", CPUtype); + + Align(); + + fprintf(fp, "MainExit:\n"); + fprintf(fp, "\t\t mov [%s],esi\t\t; Save PC\n",REG_PC); + fprintf(fp, "\t\t mov [%s],edx\n",REG_CCR); + fprintf(fp, "\t\t test byte [%s],20H\n",REG_SRH); + fprintf(fp, "\t\t mov eax,[%s]\t\t; Get A7\n",REG_A7); + fprintf(fp, "\t\t jne short ME1\t\t; Mode ?\n"); + fprintf(fp, "\t\t mov [%s],eax\t\t;Save in USP\n",REG_USP); + fprintf(fp, "\t\t jmp short MC68Kexit\n"); + fprintf(fp, "ME1:\n"); + fprintf(fp, "\t\t mov [%s],eax\n",REG_ISP); + fprintf(fp, "MC68Kexit:\n"); + + /* If in Debug mode make normal SR register */ + +#ifdef MAME_DEBUG + + ReadCCR('W', ECX); + fprintf(fp, "\t\t mov [%s],eax\n\n",REG_S); + +#endif + + fprintf(fp, "\t\t popad\n"); + fprintf(fp, "\t\t ret\n"); + +/* Check for Pending Interrupts */ + + Align(); + fprintf(fp, "; Interrupt check\n\n"); + + fprintf(fp, "interrupt:\n"); + + /* check to exclude interrupts */ + + fprintf(fp, "\t\t mov eax,[%s]\n",REG_IRQ); + fprintf(fp, "\t\t and eax,byte 07H\n"); + + fprintf(fp, "\t\t cmp al,7\t\t ; Always take 7\n"); + fprintf(fp, "\t\t je short procint\n\n"); + + fprintf(fp, "\t\t mov ebx,[%s]\t\t; int mask\n",REG_SRH); + fprintf(fp, "\t\t and ebx,byte 07H\n"); + fprintf(fp, "\t\t cmp eax,ebx\n"); + fprintf(fp, "\t\t jle near IntCont\n\n"); + + /* Take pending Interrupt */ + + Align(); + fprintf(fp, "procint:\n"); + fprintf(fp, "\t\t and byte [%s],78h\t\t; remove interrupt & stop\n\n",REG_IRQ); + + /* Get Interrupt Vector from callback */ + + fprintf(fp, "\t\t push eax\t\t; save level\n\n"); + + if (SavedRegs[EBX] == '-') + { + fprintf(fp, "\t\t push EBX\n"); + } + else + { + fprintf(fp, "\t\t mov ebx,eax\n"); + } + + if (SavedRegs[ESI] == '-') + { + fprintf(fp, "\t\t mov [%s],ESI\n",REG_PC); + } + + if (SavedRegs[EDX] == '-') + { + fprintf(fp, "\t\t mov [%s],edx\n",REG_CCR); + } + +/* ----- Win32 uses FASTCALL (By Kenjo)----- */ + +#ifdef FASTCALL + fprintf(fp, "\t\t mov %s, eax\t\t; irq line #\n",FASTCALL_FIRST_REG); + fprintf(fp, "\t\t call dword [%s]\t; get the IRQ level\n", REG_IRQ_CALLBACK); +#else + fprintf(fp, "\t\t push eax\t\t; irq line #\n"); + fprintf(fp, "\t\t call dword [%s]\t; get the IRQ level\n", REG_IRQ_CALLBACK); + fprintf(fp, "\t\t lea esp,[esp+4]\n"); +#endif + + if (SavedRegs[EDX] == '-') + { + fprintf(fp, "\t\t mov edx,[%s]\n",REG_CCR); + } + + if (SavedRegs[ESI] == '-') + { + fprintf(fp, "\t\t mov esi,[%s]\n",REG_PC); + } + + /* Do we want to use normal vector number ? */ + + + fprintf(fp, "\t\t test eax,eax\n"); + fprintf(fp, "\t\t jns short AUTOVECTOR\n"); + + /* Only need EBX restored if default vector to be used */ + + if (SavedRegs[EBX] == '-') + { + fprintf(fp, "\t\t pop EBX\n"); + } + + /* Just get default vector */ + + fprintf(fp, "\t\t mov eax,ebx\n"); + + fprintf(fp, "\t\t add eax,byte 24\t\t; Vector\n\n"); + + fprintf(fp, "AUTOVECTOR:\n\n"); + + Exception(-1,0xFFFF); + + fprintf(fp, "\t\t pop eax\t\t; set Int mask\n"); + fprintf(fp, "\t\t mov bl,byte [%s]\n",REG_SRH); + fprintf(fp, "\t\t and bl,0F8h\n"); + fprintf(fp, "\t\t or bl,al\n"); + fprintf(fp, "\t\t mov byte [%s],bl\n\n",REG_SRH); + fprintf(fp, "\t\t jmp IntCont\n\n"); + +/* Exception Routine */ + + Align(); + fprintf(fp, "Exception:\n"); + fprintf(fp, "\t\t push edx\t\t; Save flags\n"); + fprintf(fp, "\t\t and eax,0FFH\t\t; Zero Extend IRQ Vector\n"); + + fprintf(fp, "\t\t push eax\t\t; Save for Later\n"); + + /* Update Cycle Count */ + + fprintf(fp, "\t\t mov al,[exception_cycles+eax]\t\t; Get Cycles\n"); + fprintf(fp, "\t\t sub [%s],eax\t\t; Decrement ICount\n",ICOUNT); + + ReadCCR('W',ECX); + + fprintf(fp, "\t\t mov edi,[%s]\t\t; Get A7\n",REG_A7); + + fprintf(fp, "\t\t test ah,20H\t; Which Mode ?\n"); + fprintf(fp, "\t\t jne short ExSuperMode\t\t; Supervisor\n"); + + fprintf(fp, "\t\t or byte [%s],20H\t; Set Supervisor Mode\n",REG_SRH); + fprintf(fp, "\t\t mov [%s],edi\t\t; Save in USP\n",REG_USP); + fprintf(fp, "\t\t mov edi,[%s]\t\t; Get ISP\n",REG_ISP); + + /* Write SR first (since it's in a register) */ + + fprintf(fp, "ExSuperMode:\n"); + fprintf(fp, "\t\t sub edi,byte 6\n"); + fprintf(fp, "\t\t mov [%s],edi\t\t; Put in A7\n",REG_A7); + Memory_Write('W',EDI,EAX,"----S-B",2); + + /* Then write PC */ + + fprintf(fp, "\t\t add edi,byte 2\n"); + Memory_Write('L',EDI,ESI,"------B",0); + + /* Get new PC */ + + fprintf(fp, "\t\t pop eax\t\t;Level\n"); + fprintf(fp, "\t\t shl eax,2\n"); + fprintf(fp, "\t\t add eax,[%s]\n",REG_VBR); /* 68010+ Vector Base */ + + /* Direct Read */ + + Memory_Read('L',EAX,"------B",0); + + fprintf(fp, "\t\t mov esi,eax\t\t;Set PC\n"); + fprintf(fp, "\t\t pop edx\t\t; Restore flags\n"); + + /* Sort out any bank changes */ + MemoryBanking(1); + + fprintf(fp, "\t\t ret\n"); +} + +void CodeSegmentEnd(void) +{ +#ifdef OS2 + fprintf(fp, "\t\t SECTION maindata USE32 FLAT CLASS=DATA\n\n"); +#else + fprintf(fp, "\t\t SECTION .data\n"); +#endif + + fprintf(fp, "\n\t\t align 16\n"); + fprintf(fp, "%s_ICount\n",CPUtype); + fprintf(fp, "asm_count\t DD 0\n\n"); + + /* Memory structure for 68000 registers */ + /* Same layout as structure in CPUDEFS.H */ + + fprintf(fp, "\n\n; Register Structure\n\n"); + fprintf(fp, "%s_regs\n",CPUtype); + + fprintf(fp, "R_D0\t DD 0\t\t\t ; Data Registers\n"); + fprintf(fp, "R_D1\t DD 0\n"); + fprintf(fp, "R_D2\t DD 0\n"); + fprintf(fp, "R_D3\t DD 0\n"); + fprintf(fp, "R_D4\t DD 0\n"); + fprintf(fp, "R_D5\t DD 0\n"); + fprintf(fp, "R_D6\t DD 0\n"); + fprintf(fp, "R_D7\t DD 0\n\n"); + + fprintf(fp, "R_A0\t DD 0\t\t\t ; Address Registers\n"); + fprintf(fp, "R_A1\t DD 0\n"); + fprintf(fp, "R_A2\t DD 0\n"); + fprintf(fp, "R_A3\t DD 0\n"); + fprintf(fp, "R_A4\t DD 0\n"); + fprintf(fp, "R_A5\t DD 0\n"); + fprintf(fp, "R_A6\t DD 0\n"); + fprintf(fp, "R_A7\t DD 0\n\n"); + + fprintf(fp, "R_ISP\t DD 0\t\t\t ; Supervisor Stack\n"); + fprintf(fp, "R_SR_H\t DD 0\t\t\t ; Status Register High TuSuuIII\n"); + fprintf(fp, "R_CCR\t DD 0\t\t\t ; CCR Register in Intel Format\n"); + fprintf(fp, "R_XC\t DD 0\t\t\t ; Extended Carry uuuuuuuX\n"); + + fprintf(fp, "R_PC\t DD 0\t\t\t ; Program Counter\n"); + fprintf(fp, "R_IRQ\t DD 0\t\t\t ; IRQ Request Level\n\n"); + fprintf(fp, "R_SR\t DD 0\t\t\t ; Motorola Format SR\n\n"); + + fprintf(fp, "R_IRQ_CALLBACK\t DD 0\t\t\t ; irq callback (get vector)\n\n"); + + fprintf(fp, "R_PPC\t DD 0\t\t\t ; Previous Program Counter\n"); + + fprintf(fp, "R_RESET_CALLBACK\t DD 0\t\t\t ; Reset Callback\n"); + + fprintf(fp, "R_SFC\t DD 0\t\t\t ; Source Function Call\n"); + fprintf(fp, "R_DFC\t DD 0\t\t\t ; Destination Function Call\n"); + fprintf(fp, "R_USP\t DD 0\t\t\t ; User Stack\n"); + fprintf(fp, "R_VBR\t DD 0\t\t\t ; Vector Base\n"); + + fprintf(fp, "asmbank\t DD 0\n\n"); + fprintf(fp, "CPUversion\t DD 0\n\n"); + fprintf(fp, "FullPC\t DD 0\n\n"); + + /* Extra space for variables mame uses for debugger */ + + fprintf(fp, "\t\t DD 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n"); + fprintf(fp, "\t\t DD 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n"); + fprintf(fp, "\t\t DD 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n"); + fprintf(fp, "\t\t DD 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n"); + fprintf(fp, "\t\t DD 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n"); + fprintf(fp, "\t\t DD 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n"); + fprintf(fp, "\t\t DD 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n"); + fprintf(fp, "\t\t DD 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n\n"); + + /* Safe Memory Locations */ + + fprintf(fp, "\t\t ALIGN 16\n"); + + fprintf(fp, "\n\nIntelFlag\t\t\t\t; Intel Flag Lookup Table\n"); + fprintf(fp, "\t\t DD 0000h,0001h,0800h,0801h,0040h,0041h,0840h,0841h\n"); + fprintf(fp, "\t\t DD 0080h,0081h,0880h,0881h,00C0h,00C1h,08C0h,08C1h\n"); + fprintf(fp, "\t\t DD 0100h,0101h,0900h,0901h,0140h,0141h,0940h,0941h\n"); + fprintf(fp, "\t\t DD 0180h,0181h,0980h,0981h,01C0h,01C1h,09C0h,09C1h\n"); + +#if 0 + fprintf(fp, "\n\nImmTable\n"); + fprintf(fp, "\t\t DD 8,1,2,3,4,5,6,7\n\n"); +#endif + + + + /* Exception Timing Table */ + + fprintf(fp, "exception_cycles\n"); + fprintf(fp, "\t\t DB 0, 0, 0, 0, 38, 42, 44, 38, 38, 0, 38, 38, 0, 0, 0, 0\n"); + fprintf(fp, "\t\t DB 0, 0, 0, 0, 0, 0, 0, 0, 46, 46, 46, 46, 46, 46, 46, 46\n"); + fprintf(fp, "\t\t DB 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38\n\n"); + + fprintf(fp, "; RLE Compressed Jump Table\n\n"); + + fprintf(fp, "%s_COMPTABLE\n\n", CPUtype); + + fprintf(fp, "%cinclude '%s'\n\n",'%', comptab); + + fprintf(fp, "\t\tDW 0,0,0\n\n"); + + +/* If Win32, put the table area in .data section (Kenjo) */ + +#ifdef WIN32 + + fprintf(fp, "%s_OPCODETABLE\tTIMES 65536 DD 0\n\n", CPUtype); + +#else + +#ifdef OS2 + fprintf(fp, "\t\t SECTION tempdata USE32 FLAT CLASS=BSS\n\n"); +#else + fprintf(fp, "\t\t SECTION .bss\n"); +#endif + + fprintf(fp, "%s_OPCODETABLE\tRESD 65536\n\n", CPUtype); + +#endif + +} + +void EmitCode(void) +{ + CodeSegmentBegin(); + + /* Instructions */ + + moveinstructions(); /* 1000 to 3FFF MOVE.X */ + immediate(); /* 0### XXX.I */ + bitdynamic(); /* 0### dynamic bit operations */ + movep(); /* 0### Move Peripheral */ + bitstatic(); /* 08## static bit operations */ + LoadEffectiveAddress(); /* 4### */ + PushEffectiveAddress(); /* ???? */ + movesr(); /* 4#C# */ + opcode5(); /* 5000 to 5FFF ADDQ,SUBQ,Scc and DBcc */ + branchinstructions(); /* 6000 to 6FFF Bcc,BSR */ + moveq(); /* 7000 to 7FFF MOVEQ */ + abcd_sbcd(); /* 8### Decimal Add/Sub */ + typelogicalmath(); /* Various ranges */ + addx_subx(); + divides(); + swap(); + not(); /* also neg negx clr */ + moveusp(); + chk(); + exg(); + cmpm(); + mul(); + ReturnandRestore(); + rts(); + jmp_jsr(); + nbcd(); + tas(); + trap(); + trapv(); + reset(); + nop(); + stop(); + ext(); + ReturnFromException(); + tst(); + movem_reg_ea(); + movem_ea_reg(); + link(); + unlinkasm(); + asl_asr(); /* E### Shift Commands */ + asl_asr_ea(); + roxl_roxr(); + roxl_roxr_ea(); + lsl_lsr(); + lsl_lsr_ea(); + rol_ror(); + rol_ror_ea(); + LineA(); /* A000 to AFFF Line A */ + LineF(); /* F000 to FFFF Line F */ + illegal_opcode(); + + ReturnandDeallocate(); /* 68010 Commands */ + MoveControlRegister(); + MoveAddressSpace(); + + if(CPU==2) /* 68020 Commands */ + { + divl(); + mull(); + bfext(); + } + + CodeSegmentEnd(); +} + +int main(int argc, char **argv) +{ + int dwLoop; + + printf("\nMake68K - V%s - Copyright 1998, Mike Coates (mame@btinternet.com)\n", VERSION); + printf(" 1999, & Darren Olafson (deo@mail.island.net)\n"); + printf(" 2000\n"); + + if (argc != 4 && argc != 5) + { + printf("Usage: %s outfile jumptable-outfile type [ppro]\n", argv[0]); + exit(1); + } + + printf("Building 680%s 2001\n\n",argv[3]); + + for (dwLoop=0;dwLoop<65536;) OpcodeArray[dwLoop++] = -2; + + codebuf=malloc(64); + if (!codebuf) + { + printf ("Memory allocation error\n"); + exit(3); + } + + /* Emit the code */ + fp = fopen(argv[1], "w"); + if (!fp) + { + fprintf(stderr, "Can't open %s for writing\n", argv[1]); + exit(1); + } + + comptab = argv[2]; + + + CPUtype = malloc(64); +#ifdef OS2 + sprintf(CPUtype,"M680%s",argv[3]); +#else + sprintf(CPUtype,"_M680%s",argv[3]); +#endif + + if(argv[3][0]=='2') CPU = 2; + if(argc > 4 && !stricmp(argv[4], "ppro")) + { + ppro = 1; + printf("Generating ppro opcodes\n"); + } + + EmitCode(); + + fclose(fp); + + printf("\n%d Unique Opcodes\n",Opcount); + + /* output Jump table to separate file */ + fp = fopen(argv[2], "w"); + if (!fp) + { + fprintf(stderr, "Can't open %s for writing\n", argv[2]); + exit(1); + } + + JumpTable(); + + fclose(fp); + + exit(0); +} diff --git a/cpu/musashi/m68k.h b/cpu/musashi/m68k.h new file mode 100644 index 00000000..6de1fab5 --- /dev/null +++ b/cpu/musashi/m68k.h @@ -0,0 +1,371 @@ +#ifndef M68K__HEADER +#define M68K__HEADER + +/* ======================================================================== */ +/* ========================= LICENSING & COPYRIGHT ======================== */ +/* ======================================================================== */ +/* + * MUSASHI + * Version 3.3 + * + * A portable Motorola M680x0 processor emulation engine. + * Copyright 1998-2001 Karl Stenerud. All rights reserved. + * + * This code may be freely used for non-commercial purposes as long as this + * copyright notice remains unaltered in the source code and any binary files + * containing this code in compiled form. + * + * All other lisencing terms must be negotiated with the author + * (Karl Stenerud). + * + * The latest version of this code can be obtained at: + * http://kstenerud.cjb.net + */ + +/* ======================================================================== */ +/* ============================= CONFIGURATION ============================ */ +/* ======================================================================== */ + +/* Import the configuration for this build */ +#include "m68kconf.h" + + +/* ======================================================================== */ +/* ============================ GENERAL DEFINES =========================== */ + +/* ======================================================================== */ + +/* There are 7 levels of interrupt to the 68K. + * A transition from < 7 to 7 will cause a non-maskable interrupt (NMI). + */ +#define M68K_IRQ_NONE 0 +#define M68K_IRQ_1 1 +#define M68K_IRQ_2 2 +#define M68K_IRQ_3 3 +#define M68K_IRQ_4 4 +#define M68K_IRQ_5 5 +#define M68K_IRQ_6 6 +#define M68K_IRQ_7 7 + + +/* Special interrupt acknowledge values. + * Use these as special returns from the interrupt acknowledge callback + * (specified later in this header). + */ + +/* Causes an interrupt autovector (0x18 + interrupt level) to be taken. + * This happens in a real 68K if VPA or AVEC is asserted during an interrupt + * acknowledge cycle instead of DTACK. + */ +#define M68K_INT_ACK_AUTOVECTOR 0xffffffff + +/* Causes the spurious interrupt vector (0x18) to be taken + * This happens in a real 68K if BERR is asserted during the interrupt + * acknowledge cycle (i.e. no devices responded to the acknowledge). + */ +#define M68K_INT_ACK_SPURIOUS 0xfffffffe + + +/* CPU types for use in m68k_set_cpu_type() */ +enum +{ + M68K_CPU_TYPE_INVALID, + M68K_CPU_TYPE_68000, + M68K_CPU_TYPE_68008, + M68K_CPU_TYPE_68010, + M68K_CPU_TYPE_68EC020, + M68K_CPU_TYPE_68020, + M68K_CPU_TYPE_68030, /* Supported by disassembler ONLY */ + M68K_CPU_TYPE_68040 /* Supported by disassembler ONLY */ +}; + +/* Registers used by m68k_get_reg() and m68k_set_reg() */ +typedef enum +{ + /* Real registers */ + M68K_REG_D0, /* Data registers */ + M68K_REG_D1, + M68K_REG_D2, + M68K_REG_D3, + M68K_REG_D4, + M68K_REG_D5, + M68K_REG_D6, + M68K_REG_D7, + M68K_REG_A0, /* Address registers */ + M68K_REG_A1, + M68K_REG_A2, + M68K_REG_A3, + M68K_REG_A4, + M68K_REG_A5, + M68K_REG_A6, + M68K_REG_A7, + M68K_REG_PC, /* Program Counter */ + M68K_REG_SR, /* Status Register */ + M68K_REG_SP, /* The current Stack Pointer (located in A7) */ + M68K_REG_USP, /* User Stack Pointer */ + M68K_REG_ISP, /* Interrupt Stack Pointer */ + M68K_REG_MSP, /* Master Stack Pointer */ + M68K_REG_SFC, /* Source Function Code */ + M68K_REG_DFC, /* Destination Function Code */ + M68K_REG_VBR, /* Vector Base Register */ + M68K_REG_CACR, /* Cache Control Register */ + M68K_REG_CAAR, /* Cache Address Register */ + + /* Assumed registers */ + /* These are cheat registers which emulate the 1-longword prefetch + * present in the 68000 and 68010. + */ + M68K_REG_PREF_ADDR, /* Last prefetch address */ + M68K_REG_PREF_DATA, /* Last prefetch data */ + + /* Convenience registers */ + M68K_REG_PPC, /* Previous value in the program counter */ + M68K_REG_IR, /* Instruction register */ + M68K_REG_CPU_TYPE /* Type of CPU being run */ +} m68k_register_t; + +/* ======================================================================== */ +/* ====================== FUNCTIONS CALLED BY THE CPU ===================== */ +/* ======================================================================== */ + +/* You will have to implement these functions */ + +/* read/write functions called by the CPU to access memory. + * while values used are 32 bits, only the appropriate number + * of bits are relevant (i.e. in write_memory_8, only the lower 8 bits + * of value should be written to memory). + * + * NOTE: I have separated the immediate and PC-relative memory fetches + * from the other memory fetches because some systems require + * differentiation between PROGRAM and DATA fetches (usually + * for security setups such as encryption). + * This separation can either be achieved by setting + * M68K_SEPARATE_READS in m68kconf.h and defining + * the read functions, or by setting M68K_EMULATE_FC and + * making a function code callback function. + * Using the callback offers better emulation coverage + * because you can also monitor whether the CPU is in SYSTEM or + * USER mode, but it is also slower. + */ + +/* Read from anywhere */ +unsigned int m68k_read_memory_8(unsigned int address); +unsigned int m68k_read_memory_16(unsigned int address); +unsigned int m68k_read_memory_32(unsigned int address); + +/* Read data immediately following the PC */ +unsigned int m68k_read_immediate_16(unsigned int address); +unsigned int m68k_read_immediate_32(unsigned int address); + +/* Read data relative to the PC */ +unsigned int m68k_read_pcrelative_8(unsigned int address); +unsigned int m68k_read_pcrelative_16(unsigned int address); +unsigned int m68k_read_pcrelative_32(unsigned int address); + +/* Memory access for the disassembler */ +unsigned int m68k_read_disassembler_8 (unsigned int address); +unsigned int m68k_read_disassembler_16 (unsigned int address); +unsigned int m68k_read_disassembler_32 (unsigned int address); + +/* Write to anywhere */ +void m68k_write_memory_8(unsigned int address, unsigned int value); +void m68k_write_memory_16(unsigned int address, unsigned int value); +void m68k_write_memory_32(unsigned int address, unsigned int value); + +/* Special call to simulate undocumented 68k behavior when move.l with a + * predecrement destination mode is executed. + * To simulate real 68k behavior, first write the high word to + * [address+2], and then write the low word to [address]. + * + * Enable this functionality with M68K_SIMULATE_PD_WRITES in m68kconf.h. + */ +void m68k_write_memory_32_pd(unsigned int address, unsigned int value); + + + +/* ======================================================================== */ +/* ============================== CALLBACKS =============================== */ +/* ======================================================================== */ + +/* These functions allow you to set callbacks to the host when specific events + * occur. Note that you must enable the corresponding value in m68kconf.h + * in order for these to do anything useful. + * Note: I have defined default callbacks which are used if you have enabled + * the corresponding #define in m68kconf.h but either haven't assigned a + * callback or have assigned a callback of NULL. + */ + +/* Set the callback for an interrupt acknowledge. + * You must enable M68K_EMULATE_INT_ACK in m68kconf.h. + * The CPU will call the callback with the interrupt level being acknowledged. + * The host program must return either a vector from 0x02-0xff, or one of the + * special interrupt acknowledge values specified earlier in this header. + * If this is not implemented, the CPU will always assume an autovectored + * interrupt, and will automatically clear the interrupt request when it + * services the interrupt. + * Default behavior: return M68K_INT_ACK_AUTOVECTOR. + */ +void m68k_set_int_ack_callback(int (*callback)(int int_level)); + + +/* Set the callback for a breakpoint acknowledge (68010+). + * You must enable M68K_EMULATE_BKPT_ACK in m68kconf.h. + * The CPU will call the callback with whatever was in the data field of the + * BKPT instruction for 68020+, or 0 for 68010. + * Default behavior: do nothing. + */ +void m68k_set_bkpt_ack_callback(void (*callback)(unsigned int data)); + + +/* Set the callback for the RESET instruction. + * You must enable M68K_EMULATE_RESET in m68kconf.h. + * The CPU calls this callback every time it encounters a RESET instruction. + * Default behavior: do nothing. + */ +void m68k_set_reset_instr_callback(void (*callback)(void)); + + +/* Set the callback for the CMPI.L #v, Dn instruction. + * You must enable M68K_CMPILD_HAS_CALLBACK in m68kconf.h. + * The CPU calls this callback every time it encounters a CMPI.L #v, Dn instruction. + * Default behavior: do nothing. + */ +void m68k_set_cmpild_instr_callback(void (*callback)(unsigned int val, int reg)); + + +/* Set the callback for the RTE instruction. + * You must enable M68K_RTE_HAS_CALLBACK in m68kconf.h. + * The CPU calls this callback every time it encounters a RTE instruction. + * Default behavior: do nothing. + */ +void m68k_set_rte_instr_callback(void (*callback)(void)); + + +/* Set the callback for informing of a large PC change. + * You must enable M68K_MONITOR_PC in m68kconf.h. + * The CPU calls this callback with the new PC value every time the PC changes + * by a large value (currently set for changes by longwords). + * Default behavior: do nothing. + */ +void m68k_set_pc_changed_callback(void (*callback)(unsigned int new_pc)); + + +/* Set the callback for CPU function code changes. + * You must enable M68K_EMULATE_FC in m68kconf.h. + * The CPU calls this callback with the function code before every memory + * access to set the CPU's function code according to what kind of memory + * access it is (supervisor/user, program/data and such). + * Default behavior: do nothing. + */ +void m68k_set_fc_callback(void (*callback)(unsigned int new_fc)); + + +/* Set a callback for the instruction cycle of the CPU. + * You must enable M68K_INSTRUCTION_HOOK in m68kconf.h. + * The CPU calls this callback just before fetching the opcode in the + * instruction cycle. + * Default behavior: do nothing. + */ +void m68k_set_instr_hook_callback(void (*callback)(void)); + + + +/* ======================================================================== */ +/* ====================== FUNCTIONS TO ACCESS THE CPU ===================== */ +/* ======================================================================== */ + +/* Use this function to set the CPU type you want to emulate. + * Currently supported types are: M68K_CPU_TYPE_68000, M68K_CPU_TYPE_68008, + * M68K_CPU_TYPE_68010, M68K_CPU_TYPE_EC020, and M68K_CPU_TYPE_68020. + */ +void m68k_set_cpu_type(unsigned int cpu_type); + +/* Do whatever initialisations the core requires. Should be called + * at least once at init time. + */ +void m68k_init(void); + +/* Pulse the RESET pin on the CPU. + * You *MUST* reset the CPU at least once to initialize the emulation + * Note: If you didn't call m68k_set_cpu_type() before resetting + * the CPU for the first time, the CPU will be set to + * M68K_CPU_TYPE_68000. + */ +void m68k_pulse_reset(void); + +/* execute num_cycles worth of instructions. returns number of cycles used */ +int m68k_execute(int num_cycles); + +/* These functions let you read/write/modify the number of cycles left to run + * while m68k_execute() is running. + * These are useful if the 68k accesses a memory-mapped port on another device + * that requires immediate processing by another CPU. + */ +int m68k_cycles_run(void); /* Number of cycles run so far */ +int m68k_cycles_remaining(void); /* Number of cycles left */ +void m68k_modify_timeslice(int cycles); /* Modify cycles left */ +void m68k_end_timeslice(void); /* End timeslice now */ + +/* Set the IPL0-IPL2 pins on the CPU (IRQ). + * A transition from < 7 to 7 will cause a non-maskable interrupt (NMI). + * Setting IRQ to 0 will clear an interrupt request. + */ +void m68k_set_irq(unsigned int int_level); + + +/* Halt the CPU as if you pulsed the HALT pin. */ +void m68k_pulse_halt(void); + + +/* Context switching to allow multiple CPUs */ + +/* Get the size of the cpu context in bytes */ +unsigned int m68k_context_size(void); + +/* Get a cpu context */ +unsigned int m68k_get_context(void* dst); + +/* set the current cpu context */ +void m68k_set_context(void* dst); + +/* Register the CPU state information */ +void m68k_state_register(const char *type, int index); + + +/* Peek at the internals of a CPU context. This can either be a context + * retrieved using m68k_get_context() or the currently running context. + * If context is NULL, the currently running CPU context will be used. + */ +unsigned int m68k_get_reg(void* context, m68k_register_t reg); + +/* Poke values into the internals of the currently running CPU context */ +void m68k_set_reg(m68k_register_t reg, unsigned int value); + +/* Check if an instruction is valid for the specified CPU type */ +unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cpu_type); + +/* Disassemble 1 instruction using the epecified CPU type at pc. Stores + * disassembly in str_buff and returns the size of the instruction in bytes. + */ +unsigned int m68k_disassemble(char* str_buff, unsigned int pc, unsigned int cpu_type); + +/* Same as above but accepts raw opcode data directly rather than fetching + * via the read/write interfaces. + */ +unsigned int m68k_disassemble_raw(char* str_buff, unsigned int pc, unsigned char* opdata, unsigned char* argdata, int length, unsigned int cpu_type); + + +/* ======================================================================== */ +/* ============================== MAME STUFF ============================== */ +/* ======================================================================== */ + +#if M68K_COMPILE_FOR_MAME == OPT_ON +#include "m68kmame.h" +#endif /* M68K_COMPILE_FOR_MAME */ + + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ + +#endif /* M68K__HEADER */ diff --git a/cpu/musashi/m68k_in.c b/cpu/musashi/m68k_in.c new file mode 100644 index 00000000..5fa68a9d --- /dev/null +++ b/cpu/musashi/m68k_in.c @@ -0,0 +1,10636 @@ +/* +must fix: + callm + chk +*/ +/* ======================================================================== */ +/* ========================= LICENSING & COPYRIGHT ======================== */ +/* ======================================================================== */ +/* + * MUSASHI + * Version 3.3 + * + * A portable Motorola M680x0 processor emulation engine. + * Copyright 1998-2001 Karl Stenerud. All rights reserved. + * + * This code may be freely used for non-commercial purposes as long as this + * copyright notice remains unaltered in the source code and any binary files + * containing this code in compiled form. + * + * All other lisencing terms must be negotiated with the author + * (Karl Stenerud). + * + * The latest version of this code can be obtained at: + * http://kstenerud.cjb.net + */ + +/* Special thanks to Bart Trzynadlowski for his insight into the + * undocumented features of this chip: + * + * http://dynarec.com/~bart/files/68knotes.txt + */ + + +/* Input file for m68kmake + * ----------------------- + * + * All sections begin with 80 X's in a row followed by an end-of-line + * sequence. + * After this, m68kmake will expect to find one of the following section + * identifiers: + * M68KMAKE_PROTOTYPE_HEADER - header for opcode handler prototypes + * M68KMAKE_PROTOTYPE_FOOTER - footer for opcode handler prototypes + * M68KMAKE_TABLE_HEADER - header for opcode handler jumptable + * M68KMAKE_TABLE_FOOTER - footer for opcode handler jumptable + * M68KMAKE_TABLE_BODY - the table itself + * M68KMAKE_OPCODE_HANDLER_HEADER - header for opcode handler implementation + * M68KMAKE_OPCODE_HANDLER_FOOTER - footer for opcode handler implementation + * M68KMAKE_OPCODE_HANDLER_BODY - body section for opcode handler implementation + * + * NOTE: M68KMAKE_OPCODE_HANDLER_BODY must be last in the file and + * M68KMAKE_TABLE_BODY must be second last in the file. + * + * The M68KMAKE_OPHANDLER_BODY section contains the opcode handler + * primitives themselves. Each opcode handler begins with: + * M68KMAKE_OP(A, B, C, D) + * + * where A is the opcode handler name, B is the size of the operation, + * C denotes any special processing mode, and D denotes a specific + * addressing mode. + * For C and D where nothing is specified, use "." + * + * Example: + * M68KMAKE_OP(abcd, 8, rr, .) abcd, size 8, register to register, default EA + * M68KMAKE_OP(abcd, 8, mm, ax7) abcd, size 8, memory to memory, register X is A7 + * M68KMAKE_OP(tst, 16, ., pcix) tst, size 16, PCIX addressing + * + * All opcode handler primitives end with a closing curly brace "}" at column 1 + * + * NOTE: Do not place a M68KMAKE_OP() directive inside the opcode handler, + * and do not put a closing curly brace at column 1 unless it is + * marking the end of the handler! + * + * Inside the handler, m68kmake will recognize M68KMAKE_GET_OPER_xx_xx, + * M68KMAKE_GET_EA_xx_xx, and M68KMAKE_CC directives, and create multiple + * opcode handlers to handle variations in the opcode handler. + * Note: M68KMAKE_CC will only be interpreted in condition code opcodes. + * As well, M68KMAKE_GET_EA_xx_xx and M68KMAKE_GET_OPER_xx_xx will only + * be interpreted on instructions where the corresponding table entry + * specifies multiple effective addressing modes. + * Example: + * clr 32 . . 0100001010...... A+-DXWL... U U U 12 6 4 + * + * This table entry says that the clr.l opcde has 7 variations (A+-DXWL). + * It is run in user or supervisor mode for all CPUs, and uses 12 cycles for + * 68000, 6 cycles for 68010, and 4 cycles for 68020. + */ + +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +M68KMAKE_PROTOTYPE_HEADER + +#ifndef M68KOPS__HEADER +#define M68KOPS__HEADER + +/* ======================================================================== */ +/* ============================ OPCODE HANDLERS =========================== */ +/* ======================================================================== */ + + + +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +M68KMAKE_PROTOTYPE_FOOTER + + +/* Build the opcode handler table */ +void m68ki_build_opcode_table(void); + +extern void (*m68ki_instruction_jump_table[0x10000])(void); /* opcode handler jump table */ +extern unsigned char m68ki_cycles[][0x10000]; + + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ + +#endif /* M68KOPS__HEADER */ + + + +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +M68KMAKE_TABLE_HEADER + +/* ======================================================================== */ +/* ========================= OPCODE TABLE BUILDER ========================= */ +/* ======================================================================== */ + +#include "m68kops.h" + +#define NUM_CPU_TYPES 4 + +void (*m68ki_instruction_jump_table[0x10000])(void); /* opcode handler jump table */ +unsigned char m68ki_cycles[NUM_CPU_TYPES][0x10000]; /* Cycles used by CPU type */ + +/* This is used to generate the opcode handler jump table */ +typedef struct +{ + void (*opcode_handler)(void); /* handler function */ + unsigned int mask; /* mask on opcode */ + unsigned int match; /* what to match after masking */ + unsigned char cycles[NUM_CPU_TYPES]; /* cycles each cpu type takes */ +} opcode_handler_struct; + + +/* Opcode handler table */ +static opcode_handler_struct m68k_opcode_handler_table[] = +{ +/* function mask match 000 010 020 040 */ + + + +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +M68KMAKE_TABLE_FOOTER + + {0, 0, 0, {0, 0, 0, 0}} +}; + + +/* Build the opcode handler jump table */ +void m68ki_build_opcode_table(void) +{ + opcode_handler_struct *ostruct; + int instr; + int i; + int j; + int k; + + for(i = 0; i < 0x10000; i++) + { + /* default to illegal */ + m68ki_instruction_jump_table[i] = m68k_op_illegal; + for(k=0;kmask != 0xff00) + { + for(i = 0;i < 0x10000;i++) + { + if((i & ostruct->mask) == ostruct->match) + { + m68ki_instruction_jump_table[i] = ostruct->opcode_handler; + for(k=0;kcycles[k]; + } + } + ostruct++; + } + while(ostruct->mask == 0xff00) + { + for(i = 0;i <= 0xff;i++) + { + m68ki_instruction_jump_table[ostruct->match | i] = ostruct->opcode_handler; + for(k=0;kmatch | i] = ostruct->cycles[k]; + } + ostruct++; + } + while(ostruct->mask == 0xf1f8) + { + for(i = 0;i < 8;i++) + { + for(j = 0;j < 8;j++) + { + instr = ostruct->match | (i << 9) | j; + m68ki_instruction_jump_table[instr] = ostruct->opcode_handler; + for(k=0;kcycles[k]; + } + } + ostruct++; + } + while(ostruct->mask == 0xfff0) + { + for(i = 0;i <= 0x0f;i++) + { + m68ki_instruction_jump_table[ostruct->match | i] = ostruct->opcode_handler; + for(k=0;kmatch | i] = ostruct->cycles[k]; + } + ostruct++; + } + while(ostruct->mask == 0xf1ff) + { + for(i = 0;i <= 0x07;i++) + { + m68ki_instruction_jump_table[ostruct->match | (i << 9)] = ostruct->opcode_handler; + for(k=0;kmatch | (i << 9)] = ostruct->cycles[k]; + } + ostruct++; + } + while(ostruct->mask == 0xfff8) + { + for(i = 0;i <= 0x07;i++) + { + m68ki_instruction_jump_table[ostruct->match | i] = ostruct->opcode_handler; + for(k=0;kmatch | i] = ostruct->cycles[k]; + } + ostruct++; + } + while(ostruct->mask == 0xffff) + { + m68ki_instruction_jump_table[ostruct->match] = ostruct->opcode_handler; + for(k=0;kmatch] = ostruct->cycles[k]; + ostruct++; + } +} + + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ + + + +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +M68KMAKE_OPCODE_HANDLER_HEADER + +#include "m68kcpu.h" + +/* ======================================================================== */ +/* ========================= INSTRUCTION HANDLERS ========================= */ +/* ======================================================================== */ + + + +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +M68KMAKE_OPCODE_HANDLER_FOOTER + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ + + + +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +M68KMAKE_TABLE_BODY + +The following table is arranged as follows: + +name: Opcode mnemonic + +size: Operation size + +spec proc: Special processing mode: + .: normal + s: static operand + r: register operand + rr: register to register + mm: memory to memory + er: effective address to register + re: register to effective address + dd: data register to data register + da: data register to address register + aa: address register to address register + cr: control register to register + rc: register to control register + toc: to condition code register + tos: to status register + tou: to user stack pointer + frc: from condition code register + frs: from status register + fru: from user stack pointer + * for move.x, the special processing mode is a specific + destination effective addressing mode. + +spec ea: Specific effective addressing mode: + .: normal + i: immediate + d: data register + a: address register + ai: address register indirect + pi: address register indirect with postincrement + pd: address register indirect with predecrement + di: address register indirect with displacement + ix: address register indirect with index + aw: absolute word address + al: absolute long address + pcdi: program counter relative with displacement + pcix: program counter relative with index + a7: register specified in instruction is A7 + ax7: register field X of instruction is A7 + ay7: register field Y of instruction is A7 + axy7: register fields X and Y of instruction are A7 + +bit pattern: Pattern to recognize this opcode. "." means don't care. + +allowed ea: List of allowed addressing modes: + .: not present + A: address register indirect + +: ARI (address register indirect) with postincrement + -: ARI with predecrement + D: ARI with displacement + X: ARI with index + W: absolute word address + L: absolute long address + d: program counter indirect with displacement + x: program counter indirect with index + I: immediate +mode: CPU operating mode for each cpu type. U = user or supervisor, + S = supervisor only, "." = opcode not present. + +cpu cycles: Base number of cycles required to execute this opcode on the + specified CPU type. + Use "." if CPU does not have this opcode. + + + + spec spec allowed ea mode cpu cycles +name size proc ea bit pattern A+-DXWLdxI 0 1 2 4 000 010 020 040 comments +====== ==== ==== ==== ================ ========== = = = = === === === === ============= +M68KMAKE_TABLE_START +1010 0 . . 1010............ .......... U U U U 4 4 4 4 +1111 0 . . 1111............ .......... U U U U 4 4 4 4 +abcd 8 rr . 1100...100000... .......... U U U U 6 6 4 4 +abcd 8 mm ax7 1100111100001... .......... U U U U 18 18 16 16 +abcd 8 mm ay7 1100...100001111 .......... U U U U 18 18 16 16 +abcd 8 mm axy7 1100111100001111 .......... U U U U 18 18 16 16 +abcd 8 mm . 1100...100001... .......... U U U U 18 18 16 16 +add 8 er d 1101...000000... .......... U U U U 4 4 2 2 +add 8 er . 1101...000...... A+-DXWLdxI U U U U 4 4 2 2 +add 16 er d 1101...001000... .......... U U U U 4 4 2 2 +add 16 er a 1101...001001... .......... U U U U 4 4 2 2 +add 16 er . 1101...001...... A+-DXWLdxI U U U U 4 4 2 2 +add 32 er d 1101...010000... .......... U U U U 6 6 2 2 +add 32 er a 1101...010001... .......... U U U U 6 6 2 2 +add 32 er . 1101...010...... A+-DXWLdxI U U U U 6 6 2 2 +add 8 re . 1101...100...... A+-DXWL... U U U U 8 8 4 4 +add 16 re . 1101...101...... A+-DXWL... U U U U 8 8 4 4 +add 32 re . 1101...110...... A+-DXWL... U U U U 12 12 4 4 +adda 16 . d 1101...011000... .......... U U U U 8 8 2 2 +adda 16 . a 1101...011001... .......... U U U U 8 8 2 2 +adda 16 . . 1101...011...... A+-DXWLdxI U U U U 8 8 2 2 +adda 32 . d 1101...111000... .......... U U U U 6 6 2 2 +adda 32 . a 1101...111001... .......... U U U U 6 6 2 2 +adda 32 . . 1101...111...... A+-DXWLdxI U U U U 6 6 2 2 +addi 8 . d 0000011000000... .......... U U U U 8 8 2 2 +addi 8 . . 0000011000...... A+-DXWL... U U U U 12 12 4 4 +addi 16 . d 0000011001000... .......... U U U U 8 8 2 2 +addi 16 . . 0000011001...... A+-DXWL... U U U U 12 12 4 4 +addi 32 . d 0000011010000... .......... U U U U 16 14 2 2 +addi 32 . . 0000011010...... A+-DXWL... U U U U 20 20 4 4 +addq 8 . d 0101...000000... .......... U U U U 4 4 2 2 +addq 8 . . 0101...000...... A+-DXWL... U U U U 8 8 4 4 +addq 16 . d 0101...001000... .......... U U U U 4 4 2 2 +addq 16 . a 0101...001001... .......... U U U U 4 4 2 2 +addq 16 . . 0101...001...... A+-DXWL... U U U U 8 8 4 4 +addq 32 . d 0101...010000... .......... U U U U 8 8 2 2 +addq 32 . a 0101...010001... .......... U U U U 8 8 2 2 +addq 32 . . 0101...010...... A+-DXWL... U U U U 12 12 4 4 +addx 8 rr . 1101...100000... .......... U U U U 4 4 2 2 +addx 16 rr . 1101...101000... .......... U U U U 4 4 2 2 +addx 32 rr . 1101...110000... .......... U U U U 8 6 2 2 +addx 8 mm ax7 1101111100001... .......... U U U U 18 18 12 12 +addx 8 mm ay7 1101...100001111 .......... U U U U 18 18 12 12 +addx 8 mm axy7 1101111100001111 .......... U U U U 18 18 12 12 +addx 8 mm . 1101...100001... .......... U U U U 18 18 12 12 +addx 16 mm . 1101...101001... .......... U U U U 18 18 12 12 +addx 32 mm . 1101...110001... .......... U U U U 30 30 12 12 +and 8 er d 1100...000000... .......... U U U U 4 4 2 2 +and 8 er . 1100...000...... A+-DXWLdxI U U U U 4 4 2 2 +and 16 er d 1100...001000... .......... U U U U 4 4 2 2 +and 16 er . 1100...001...... A+-DXWLdxI U U U U 4 4 2 2 +and 32 er d 1100...010000... .......... U U U U 6 6 2 2 +and 32 er . 1100...010...... A+-DXWLdxI U U U U 6 6 2 2 +and 8 re . 1100...100...... A+-DXWL... U U U U 8 8 4 4 +and 16 re . 1100...101...... A+-DXWL... U U U U 8 8 4 4 +and 32 re . 1100...110...... A+-DXWL... U U U U 12 12 4 4 +andi 16 toc . 0000001000111100 .......... U U U U 20 16 12 12 +andi 16 tos . 0000001001111100 .......... S S S S 20 16 12 12 +andi 8 . d 0000001000000... .......... U U U U 8 8 2 2 +andi 8 . . 0000001000...... A+-DXWL... U U U U 12 12 4 4 +andi 16 . d 0000001001000... .......... U U U U 8 8 2 2 +andi 16 . . 0000001001...... A+-DXWL... U U U U 12 12 4 4 +andi 32 . d 0000001010000... .......... U U U U 14 14 2 2 +andi 32 . . 0000001010...... A+-DXWL... U U U U 20 20 4 4 +asr 8 s . 1110...000000... .......... U U U U 6 6 6 6 +asr 16 s . 1110...001000... .......... U U U U 6 6 6 6 +asr 32 s . 1110...010000... .......... U U U U 8 8 6 6 +asr 8 r . 1110...000100... .......... U U U U 6 6 6 6 +asr 16 r . 1110...001100... .......... U U U U 6 6 6 6 +asr 32 r . 1110...010100... .......... U U U U 8 8 6 6 +asr 16 . . 1110000011...... A+-DXWL... U U U U 8 8 5 5 +asl 8 s . 1110...100000... .......... U U U U 6 6 8 8 +asl 16 s . 1110...101000... .......... U U U U 6 6 8 8 +asl 32 s . 1110...110000... .......... U U U U 8 8 8 8 +asl 8 r . 1110...100100... .......... U U U U 6 6 8 8 +asl 16 r . 1110...101100... .......... U U U U 6 6 8 8 +asl 32 r . 1110...110100... .......... U U U U 8 8 8 8 +asl 16 . . 1110000111...... A+-DXWL... U U U U 8 8 6 6 +bcc 8 . . 0110............ .......... U U U U 10 10 6 6 +bcc 16 . . 0110....00000000 .......... U U U U 10 10 6 6 +bcc 32 . . 0110....11111111 .......... U U U U 10 10 6 6 +bchg 8 r . 0000...101...... A+-DXWL... U U U U 8 8 4 4 +bchg 32 r d 0000...101000... .......... U U U U 8 8 4 4 +bchg 8 s . 0000100001...... A+-DXWL... U U U U 12 12 4 4 +bchg 32 s d 0000100001000... .......... U U U U 12 12 4 4 +bclr 8 r . 0000...110...... A+-DXWL... U U U U 8 10 4 4 +bclr 32 r d 0000...110000... .......... U U U U 10 10 4 4 +bclr 8 s . 0000100010...... A+-DXWL... U U U U 12 12 4 4 +bclr 32 s d 0000100010000... .......... U U U U 14 14 4 4 +bfchg 32 . d 1110101011000... .......... . . U U . . 12 12 timing not quite correct +bfchg 32 . . 1110101011...... A..DXWL... . . U U . . 20 20 +bfclr 32 . d 1110110011000... .......... . . U U . . 12 12 +bfclr 32 . . 1110110011...... A..DXWL... . . U U . . 20 20 +bfexts 32 . d 1110101111000... .......... . . U U . . 8 8 +bfexts 32 . . 1110101111...... A..DXWLdx. . . U U . . 15 15 +bfextu 32 . d 1110100111000... .......... . . U U . . 8 8 +bfextu 32 . . 1110100111...... A..DXWLdx. . . U U . . 15 15 +bfffo 32 . d 1110110111000... .......... . . U U . . 18 18 +bfffo 32 . . 1110110111...... A..DXWLdx. . . U U . . 28 28 +bfins 32 . d 1110111111000... .......... . . U U . . 10 10 +bfins 32 . . 1110111111...... A..DXWL... . . U U . . 17 17 +bfset 32 . d 1110111011000... .......... . . U U . . 12 12 +bfset 32 . . 1110111011...... A..DXWL... . . U U . . 20 20 +bftst 32 . d 1110100011000... .......... . . U U . . 6 6 +bftst 32 . . 1110100011...... A..DXWLdx. . . U U . . 13 13 +bkpt 0 . . 0100100001001... .......... . U U U . 10 10 10 +bra 8 . . 01100000........ .......... U U U U 10 10 10 10 +bra 16 . . 0110000000000000 .......... U U U U 10 10 10 10 +bra 32 . . 0110000011111111 .......... U U U U 10 10 10 10 +bset 32 r d 0000...111000... .......... U U U U 8 8 4 4 +bset 8 r . 0000...111...... A+-DXWL... U U U U 8 8 4 4 +bset 8 s . 0000100011...... A+-DXWL... U U U U 12 12 4 4 +bset 32 s d 0000100011000... .......... U U U U 12 12 4 4 +bsr 8 . . 01100001........ .......... U U U U 18 18 7 7 +bsr 16 . . 0110000100000000 .......... U U U U 18 18 7 7 +bsr 32 . . 0110000111111111 .......... U U U U 18 18 7 7 +btst 8 r . 0000...100...... A+-DXWLdxI U U U U 4 4 4 4 +btst 32 r d 0000...100000... .......... U U U U 6 6 4 4 +btst 8 s . 0000100000...... A+-DXWLdx. U U U U 8 8 4 4 +btst 32 s d 0000100000000... .......... U U U U 10 10 4 4 +callm 32 . . 0000011011...... A..DXWLdx. . . U U . . 60 60 not properly emulated +cas 8 . . 0000101011...... A+-DXWL... . . U U . . 12 12 +cas 16 . . 0000110011...... A+-DXWL... . . U U . . 12 12 +cas 32 . . 0000111011...... A+-DXWL... . . U U . . 12 12 +cas2 16 . . 0000110011111100 .......... . . U U . . 12 12 +cas2 32 . . 0000111011111100 .......... . . U U . . 12 12 +chk 16 . d 0100...110000... .......... U U U U 10 8 8 8 +chk 16 . . 0100...110...... A+-DXWLdxI U U U U 10 8 8 8 +chk 32 . d 0100...100000... .......... . . U U . . 8 8 +chk 32 . . 0100...100...... A+-DXWLdxI . . U U . . 8 8 +chk2cmp2 8 . pcdi 0000000011111010 .......... . . U U . . 23 23 +chk2cmp2 8 . pcix 0000000011111011 .......... . . U U . . 23 23 +chk2cmp2 8 . . 0000000011...... A..DXWL... . . U U . . 18 18 +chk2cmp2 16 . pcdi 0000001011111010 .......... . . U U . . 23 23 +chk2cmp2 16 . pcix 0000001011111011 .......... . . U U . . 23 23 +chk2cmp2 16 . . 0000001011...... A..DXWL... . . U U . . 18 18 +chk2cmp2 32 . pcdi 0000010011111010 .......... . . U U . . 23 23 +chk2cmp2 32 . pcix 0000010011111011 .......... . . U U . . 23 23 +chk2cmp2 32 . . 0000010011...... A..DXWL... . . U U . . 18 18 +clr 8 . d 0100001000000... .......... U U U U 4 4 2 2 +clr 8 . . 0100001000...... A+-DXWL... U U U U 6 4 4 4 notaz hack: changed 000 cycles 8 -> 6 like in starscream for Fatal Rewind +clr 16 . d 0100001001000... .......... U U U U 4 4 2 2 +clr 16 . . 0100001001...... A+-DXWL... U U U U 6 4 4 4 ditto +clr 32 . d 0100001010000... .......... U U U U 6 6 2 2 +clr 32 . . 0100001010...... A+-DXWL... U U U U 12 6 4 4 +cmp 8 . d 1011...000000... .......... U U U U 4 4 2 2 +cmp 8 . . 1011...000...... A+-DXWLdxI U U U U 4 4 2 2 +cmp 16 . d 1011...001000... .......... U U U U 4 4 2 2 +cmp 16 . a 1011...001001... .......... U U U U 4 4 2 2 +cmp 16 . . 1011...001...... A+-DXWLdxI U U U U 4 4 2 2 +cmp 32 . d 1011...010000... .......... U U U U 6 6 2 2 +cmp 32 . a 1011...010001... .......... U U U U 6 6 2 2 +cmp 32 . . 1011...010...... A+-DXWLdxI U U U U 6 6 2 2 +cmpa 16 . d 1011...011000... .......... U U U U 6 6 4 4 +cmpa 16 . a 1011...011001... .......... U U U U 6 6 4 4 +cmpa 16 . . 1011...011...... A+-DXWLdxI U U U U 6 6 4 4 +cmpa 32 . d 1011...111000... .......... U U U U 6 6 4 4 +cmpa 32 . a 1011...111001... .......... U U U U 6 6 4 4 +cmpa 32 . . 1011...111...... A+-DXWLdxI U U U U 6 6 4 4 +cmpi 8 . d 0000110000000... .......... U U U U 8 8 2 2 +cmpi 8 . . 0000110000...... A+-DXWL... U U U U 8 8 2 2 +cmpi 8 . pcdi 0000110000111010 .......... . . U U . . 7 7 +cmpi 8 . pcix 0000110000111011 .......... . . U U . . 9 9 +cmpi 16 . d 0000110001000... .......... U U U U 8 8 2 2 +cmpi 16 . . 0000110001...... A+-DXWL... U U U U 8 8 2 2 +cmpi 16 . pcdi 0000110001111010 .......... . . U U . . 7 7 +cmpi 16 . pcix 0000110001111011 .......... . . U U . . 9 9 +cmpi 32 . d 0000110010000... .......... U U U U 14 12 2 2 +cmpi 32 . . 0000110010...... A+-DXWL... U U U U 12 12 2 2 +cmpi 32 . pcdi 0000110010111010 .......... . . U U . . 7 7 +cmpi 32 . pcix 0000110010111011 .......... . . U U . . 9 9 +cmpm 8 . ax7 1011111100001... .......... U U U U 12 12 9 9 +cmpm 8 . ay7 1011...100001111 .......... U U U U 12 12 9 9 +cmpm 8 . axy7 1011111100001111 .......... U U U U 12 12 9 9 +cmpm 8 . . 1011...100001... .......... U U U U 12 12 9 9 +cmpm 16 . . 1011...101001... .......... U U U U 12 12 9 9 +cmpm 32 . . 1011...110001... .......... U U U U 20 20 9 9 +cpbcc 32 . . 1111...01....... .......... . . U . . . 4 . unemulated +cpdbcc 32 . . 1111...001001... .......... . . U . . . 4 . unemulated +cpgen 32 . . 1111...000...... .......... . . U . . . 4 . unemulated +cpscc 32 . . 1111...001...... .......... . . U . . . 4 . unemulated +cptrapcc 32 . . 1111...001111... .......... . . U . . . 4 . unemulated +dbt 16 . . 0101000011001... .......... U U U U 12 12 6 6 +dbf 16 . . 0101000111001... .......... U U U U 12 12 6 6 +dbcc 16 . . 0101....11001... .......... U U U U 12 12 6 6 +divs 16 . d 1000...111000... .......... U U U U 158 122 56 56 +divs 16 . . 1000...111...... A+-DXWLdxI U U U U 158 122 56 56 +divu 16 . d 1000...011000... .......... U U U U 140 108 44 44 +divu 16 . . 1000...011...... A+-DXWLdxI U U U U 140 108 44 44 +divl 32 . d 0100110001000... .......... . . U U . . 84 84 +divl 32 . . 0100110001...... A+-DXWLdxI . . U U . . 84 84 +eor 8 . d 1011...100000... .......... U U U U 4 4 2 2 +eor 8 . . 1011...100...... A+-DXWL... U U U U 8 8 4 4 +eor 16 . d 1011...101000... .......... U U U U 4 4 2 2 +eor 16 . . 1011...101...... A+-DXWL... U U U U 8 8 4 4 +eor 32 . d 1011...110000... .......... U U U U 8 6 2 2 +eor 32 . . 1011...110...... A+-DXWL... U U U U 12 12 4 4 +eori 16 toc . 0000101000111100 .......... U U U U 20 16 12 12 +eori 16 tos . 0000101001111100 .......... S S S S 20 16 12 12 +eori 8 . d 0000101000000... .......... U U U U 8 8 2 2 +eori 8 . . 0000101000...... A+-DXWL... U U U U 12 12 4 4 +eori 16 . d 0000101001000... .......... U U U U 8 8 2 2 +eori 16 . . 0000101001...... A+-DXWL... U U U U 12 12 4 4 +eori 32 . d 0000101010000... .......... U U U U 16 14 2 2 +eori 32 . . 0000101010...... A+-DXWL... U U U U 20 20 4 4 +exg 32 dd . 1100...101000... .......... U U U U 6 6 2 2 +exg 32 aa . 1100...101001... .......... U U U U 6 6 2 2 +exg 32 da . 1100...110001... .......... U U U U 6 6 2 2 +ext 16 . . 0100100010000... .......... U U U U 4 4 4 4 +ext 32 . . 0100100011000... .......... U U U U 4 4 4 4 +extb 32 . . 0100100111000... .......... . . U U . . 4 4 +illegal 0 . . 0100101011111100 .......... U U U U 4 4 4 4 +jmp 32 . . 0100111011...... A..DXWLdx. U U U U 4 4 0 0 +jsr 32 . . 0100111010...... A..DXWLdx. U U U U 12 12 0 0 +lea 32 . . 0100...111...... A..DXWLdx. U U U U 0 0 2 2 +link 16 . a7 0100111001010111 .......... U U U U 16 16 5 5 +link 16 . . 0100111001010... .......... U U U U 16 16 5 5 +link 32 . a7 0100100000001111 .......... . . U U . . 6 6 +link 32 . . 0100100000001... .......... . . U U . . 6 6 +lsr 8 s . 1110...000001... .......... U U U U 6 6 4 4 +lsr 16 s . 1110...001001... .......... U U U U 6 6 4 4 +lsr 32 s . 1110...010001... .......... U U U U 8 8 4 4 +lsr 8 r . 1110...000101... .......... U U U U 6 6 6 6 +lsr 16 r . 1110...001101... .......... U U U U 6 6 6 6 +lsr 32 r . 1110...010101... .......... U U U U 8 8 6 6 +lsr 16 . . 1110001011...... A+-DXWL... U U U U 8 8 5 5 +lsl 8 s . 1110...100001... .......... U U U U 6 6 4 4 +lsl 16 s . 1110...101001... .......... U U U U 6 6 4 4 +lsl 32 s . 1110...110001... .......... U U U U 8 8 4 4 +lsl 8 r . 1110...100101... .......... U U U U 6 6 6 6 +lsl 16 r . 1110...101101... .......... U U U U 6 6 6 6 +lsl 32 r . 1110...110101... .......... U U U U 8 8 6 6 +lsl 16 . . 1110001111...... A+-DXWL... U U U U 8 8 5 5 +move 8 d d 0001...000000... .......... U U U U 4 4 2 2 +move 8 d . 0001...000...... A+-DXWLdxI U U U U 4 4 2 2 +move 8 ai d 0001...010000... .......... U U U U 8 8 4 4 +move 8 ai . 0001...010...... A+-DXWLdxI U U U U 8 8 4 4 +move 8 pi d 0001...011000... .......... U U U U 8 8 4 4 +move 8 pi . 0001...011...... A+-DXWLdxI U U U U 8 8 4 4 +move 8 pi7 d 0001111011000... .......... U U U U 8 8 4 4 +move 8 pi7 . 0001111011...... A+-DXWLdxI U U U U 8 8 4 4 +move 8 pd d 0001...100000... .......... U U U U 8 8 5 5 +move 8 pd . 0001...100...... A+-DXWLdxI U U U U 8 8 5 5 +move 8 pd7 d 0001111100000... .......... U U U U 8 8 5 5 +move 8 pd7 . 0001111100...... A+-DXWLdxI U U U U 8 8 5 5 +move 8 di d 0001...101000... .......... U U U U 12 12 5 5 +move 8 di . 0001...101...... A+-DXWLdxI U U U U 12 12 5 5 +move 8 ix d 0001...110000... .......... U U U U 14 14 7 7 +move 8 ix . 0001...110...... A+-DXWLdxI U U U U 14 14 7 7 +move 8 aw d 0001000111000... .......... U U U U 12 12 4 4 +move 8 aw . 0001000111...... A+-DXWLdxI U U U U 12 12 4 4 +move 8 al d 0001001111000... .......... U U U U 16 16 6 6 +move 8 al . 0001001111...... A+-DXWLdxI U U U U 16 16 6 6 +move 16 d d 0011...000000... .......... U U U U 4 4 2 2 +move 16 d a 0011...000001... .......... U U U U 4 4 2 2 +move 16 d . 0011...000...... A+-DXWLdxI U U U U 4 4 2 2 +move 16 ai d 0011...010000... .......... U U U U 8 8 4 4 +move 16 ai a 0011...010001... .......... U U U U 8 8 4 4 +move 16 ai . 0011...010...... A+-DXWLdxI U U U U 8 8 4 4 +move 16 pi d 0011...011000... .......... U U U U 8 8 4 4 +move 16 pi a 0011...011001... .......... U U U U 8 8 4 4 +move 16 pi . 0011...011...... A+-DXWLdxI U U U U 8 8 4 4 +move 16 pd d 0011...100000... .......... U U U U 8 8 5 5 +move 16 pd a 0011...100001... .......... U U U U 8 8 5 5 +move 16 pd . 0011...100...... A+-DXWLdxI U U U U 8 8 5 5 +move 16 di d 0011...101000... .......... U U U U 12 12 5 5 +move 16 di a 0011...101001... .......... U U U U 12 12 5 5 +move 16 di . 0011...101...... A+-DXWLdxI U U U U 12 12 5 5 +move 16 ix d 0011...110000... .......... U U U U 14 14 7 7 +move 16 ix a 0011...110001... .......... U U U U 14 14 7 7 +move 16 ix . 0011...110...... A+-DXWLdxI U U U U 14 14 7 7 +move 16 aw d 0011000111000... .......... U U U U 12 12 4 4 +move 16 aw a 0011000111001... .......... U U U U 12 12 4 4 +move 16 aw . 0011000111...... A+-DXWLdxI U U U U 12 12 4 4 +move 16 al d 0011001111000... .......... U U U U 16 16 6 6 +move 16 al a 0011001111001... .......... U U U U 16 16 6 6 +move 16 al . 0011001111...... A+-DXWLdxI U U U U 16 16 6 6 +move 32 d d 0010...000000... .......... U U U U 4 4 2 2 +move 32 d a 0010...000001... .......... U U U U 4 4 2 2 +move 32 d . 0010...000...... A+-DXWLdxI U U U U 4 4 2 2 +move 32 ai d 0010...010000... .......... U U U U 12 12 4 4 +move 32 ai a 0010...010001... .......... U U U U 12 12 4 4 +move 32 ai . 0010...010...... A+-DXWLdxI U U U U 12 12 4 4 +move 32 pi d 0010...011000... .......... U U U U 12 12 4 4 +move 32 pi a 0010...011001... .......... U U U U 12 12 4 4 +move 32 pi . 0010...011...... A+-DXWLdxI U U U U 12 12 4 4 +move 32 pd d 0010...100000... .......... U U U U 12 14 5 5 +move 32 pd a 0010...100001... .......... U U U U 12 14 5 5 +move 32 pd . 0010...100...... A+-DXWLdxI U U U U 12 14 5 5 +move 32 di d 0010...101000... .......... U U U U 16 16 5 5 +move 32 di a 0010...101001... .......... U U U U 16 16 5 5 +move 32 di . 0010...101...... A+-DXWLdxI U U U U 16 16 5 5 +move 32 ix d 0010...110000... .......... U U U U 18 18 7 7 +move 32 ix a 0010...110001... .......... U U U U 18 18 7 7 +move 32 ix . 0010...110...... A+-DXWLdxI U U U U 18 18 7 7 +move 32 aw d 0010000111000... .......... U U U U 16 16 4 4 +move 32 aw a 0010000111001... .......... U U U U 16 16 4 4 +move 32 aw . 0010000111...... A+-DXWLdxI U U U U 16 16 4 4 +move 32 al d 0010001111000... .......... U U U U 20 20 6 6 +move 32 al a 0010001111001... .......... U U U U 20 20 6 6 +move 32 al . 0010001111...... A+-DXWLdxI U U U U 20 20 6 6 +movea 16 . d 0011...001000... .......... U U U U 4 4 2 2 +movea 16 . a 0011...001001... .......... U U U U 4 4 2 2 +movea 16 . . 0011...001...... A+-DXWLdxI U U U U 4 4 2 2 +movea 32 . d 0010...001000... .......... U U U U 4 4 2 2 +movea 32 . a 0010...001001... .......... U U U U 4 4 2 2 +movea 32 . . 0010...001...... A+-DXWLdxI U U U U 4 4 2 2 +move 16 frc d 0100001011000... .......... . U U U . 4 4 4 +move 16 frc . 0100001011...... A+-DXWL... . U U U . 8 4 4 +move 16 toc d 0100010011000... .......... U U U U 12 12 4 4 +move 16 toc . 0100010011...... A+-DXWLdxI U U U U 12 12 4 4 +move 16 frs d 0100000011000... .......... U S S S 6 4 8 8 U only for 000 +move 16 frs . 0100000011...... A+-DXWL... U S S S 8 8 8 8 U only for 000 +move 16 tos d 0100011011000... .......... S S S S 12 12 8 8 +move 16 tos . 0100011011...... A+-DXWLdxI S S S S 12 12 8 8 +move 32 fru . 0100111001101... .......... S S S S 4 6 2 2 +move 32 tou . 0100111001100... .......... S S S S 4 6 2 2 +movec 32 cr . 0100111001111010 .......... . S S S . 12 6 6 +movec 32 rc . 0100111001111011 .......... . S S S . 10 12 12 +movem 16 re pd 0100100010100... .......... U U U U 8 8 4 4 +movem 16 re . 0100100010...... A..DXWL... U U U U 8 8 4 4 +movem 32 re pd 0100100011100... .......... U U U U 8 8 4 4 +movem 32 re . 0100100011...... A..DXWL... U U U U 8 8 4 4 +movem 16 er pi 0100110010011... .......... U U U U 12 12 8 8 +movem 16 er pcdi 0100110010111010 .......... U U U U 16 16 9 9 +movem 16 er pcix 0100110010111011 .......... U U U U 18 18 11 11 +movem 16 er . 0100110010...... A..DXWL... U U U U 12 12 8 8 +movem 32 er pi 0100110011011... .......... U U U U 12 12 8 8 +movem 32 er pcdi 0100110011111010 .......... U U U U 16 16 9 9 +movem 32 er pcix 0100110011111011 .......... U U U U 18 18 11 11 +movem 32 er . 0100110011...... A..DXWL... U U U U 12 12 8 8 +movep 16 er . 0000...100001... .......... U U U U 16 16 12 12 +movep 32 er . 0000...101001... .......... U U U U 24 24 18 18 +movep 16 re . 0000...110001... .......... U U U U 16 16 11 11 +movep 32 re . 0000...111001... .......... U U U U 24 24 17 17 +moveq 32 . . 0111...0........ .......... U U U U 4 4 2 2 +moves 8 . . 0000111000...... A+-DXWL... . S S S . 14 5 5 +moves 16 . . 0000111001...... A+-DXWL... . S S S . 14 5 5 +moves 32 . . 0000111010...... A+-DXWL... . S S S . 16 5 5 +move16 32 . . 1111011000100... .......... . . . U . . . 4 TODO: correct timing +muls 16 . d 1100...111000... .......... U U U U 54 32 27 27 +muls 16 . . 1100...111...... A+-DXWLdxI U U U U 54 32 27 27 +mulu 16 . d 1100...011000... .......... U U U U 54 30 27 27 +mulu 16 . . 1100...011...... A+-DXWLdxI U U U U 54 30 27 27 +mull 32 . d 0100110000000... .......... . . U U . . 43 43 +mull 32 . . 0100110000...... A+-DXWLdxI . . U U . . 43 43 +nbcd 8 . d 0100100000000... .......... U U U U 6 6 6 6 +nbcd 8 . . 0100100000...... A+-DXWL... U U U U 8 8 6 6 +neg 8 . d 0100010000000... .......... U U U U 4 4 2 2 +neg 8 . . 0100010000...... A+-DXWL... U U U U 8 8 4 4 +neg 16 . d 0100010001000... .......... U U U U 4 4 2 2 +neg 16 . . 0100010001...... A+-DXWL... U U U U 8 8 4 4 +neg 32 . d 0100010010000... .......... U U U U 6 6 2 2 +neg 32 . . 0100010010...... A+-DXWL... U U U U 12 12 4 4 +negx 8 . d 0100000000000... .......... U U U U 4 4 2 2 +negx 8 . . 0100000000...... A+-DXWL... U U U U 8 8 4 4 +negx 16 . d 0100000001000... .......... U U U U 4 4 2 2 +negx 16 . . 0100000001...... A+-DXWL... U U U U 8 8 4 4 +negx 32 . d 0100000010000... .......... U U U U 6 6 2 2 +negx 32 . . 0100000010...... A+-DXWL... U U U U 12 12 4 4 +nop 0 . . 0100111001110001 .......... U U U U 4 4 2 2 +not 8 . d 0100011000000... .......... U U U U 4 4 2 2 +not 8 . . 0100011000...... A+-DXWL... U U U U 8 8 4 4 +not 16 . d 0100011001000... .......... U U U U 4 4 2 2 +not 16 . . 0100011001...... A+-DXWL... U U U U 8 8 4 4 +not 32 . d 0100011010000... .......... U U U U 6 6 2 2 +not 32 . . 0100011010...... A+-DXWL... U U U U 12 12 4 4 +or 8 er d 1000...000000... .......... U U U U 4 4 2 2 +or 8 er . 1000...000...... A+-DXWLdxI U U U U 4 4 2 2 +or 16 er d 1000...001000... .......... U U U U 4 4 2 2 +or 16 er . 1000...001...... A+-DXWLdxI U U U U 4 4 2 2 +or 32 er d 1000...010000... .......... U U U U 6 6 2 2 +or 32 er . 1000...010...... A+-DXWLdxI U U U U 6 6 2 2 +or 8 re . 1000...100...... A+-DXWL... U U U U 8 8 4 4 +or 16 re . 1000...101...... A+-DXWL... U U U U 8 8 4 4 +or 32 re . 1000...110...... A+-DXWL... U U U U 12 12 4 4 +ori 16 toc . 0000000000111100 .......... U U U U 20 16 12 12 +ori 16 tos . 0000000001111100 .......... S S S S 20 16 12 12 +ori 8 . d 0000000000000... .......... U U U U 8 8 2 2 +ori 8 . . 0000000000...... A+-DXWL... U U U U 12 12 4 4 +ori 16 . d 0000000001000... .......... U U U U 8 8 2 2 +ori 16 . . 0000000001...... A+-DXWL... U U U U 12 12 4 4 +ori 32 . d 0000000010000... .......... U U U U 16 14 2 2 +ori 32 . . 0000000010...... A+-DXWL... U U U U 20 20 4 4 +pack 16 rr . 1000...101000... .......... . . U U . . 6 6 +pack 16 mm ax7 1000111101001... .......... . . U U . . 13 13 +pack 16 mm ay7 1000...101001111 .......... . . U U . . 13 13 +pack 16 mm axy7 1000111101001111 .......... . . U U . . 13 13 +pack 16 mm . 1000...101001... .......... . . U U . . 13 13 +pea 32 . . 0100100001...... A..DXWLdx. U U U U 6 6 5 5 +pflush 32 . . 1111010100011000 .......... . . . S . . . 4 TODO: correct timing +reset 0 . . 0100111001110000 .......... S S S S 0 0 0 0 +ror 8 s . 1110...000011... .......... U U U U 6 6 8 8 +ror 16 s . 1110...001011... .......... U U U U 6 6 8 8 +ror 32 s . 1110...010011... .......... U U U U 8 8 8 8 +ror 8 r . 1110...000111... .......... U U U U 6 6 8 8 +ror 16 r . 1110...001111... .......... U U U U 6 6 8 8 +ror 32 r . 1110...010111... .......... U U U U 8 8 8 8 +ror 16 . . 1110011011...... A+-DXWL... U U U U 8 8 7 7 +rol 8 s . 1110...100011... .......... U U U U 6 6 8 8 +rol 16 s . 1110...101011... .......... U U U U 6 6 8 8 +rol 32 s . 1110...110011... .......... U U U U 8 8 8 8 +rol 8 r . 1110...100111... .......... U U U U 6 6 8 8 +rol 16 r . 1110...101111... .......... U U U U 6 6 8 8 +rol 32 r . 1110...110111... .......... U U U U 8 8 8 8 +rol 16 . . 1110011111...... A+-DXWL... U U U U 8 8 7 7 +roxr 8 s . 1110...000010... .......... U U U U 6 6 12 12 +roxr 16 s . 1110...001010... .......... U U U U 6 6 12 12 +roxr 32 s . 1110...010010... .......... U U U U 8 8 12 12 +roxr 8 r . 1110...000110... .......... U U U U 6 6 12 12 +roxr 16 r . 1110...001110... .......... U U U U 6 6 12 12 +roxr 32 r . 1110...010110... .......... U U U U 8 8 12 12 +roxr 16 . . 1110010011...... A+-DXWL... U U U U 8 8 5 5 +roxl 8 s . 1110...100010... .......... U U U U 6 6 12 12 +roxl 16 s . 1110...101010... .......... U U U U 6 6 12 12 +roxl 32 s . 1110...110010... .......... U U U U 8 8 12 12 +roxl 8 r . 1110...100110... .......... U U U U 6 6 12 12 +roxl 16 r . 1110...101110... .......... U U U U 6 6 12 12 +roxl 32 r . 1110...110110... .......... U U U U 8 8 12 12 +roxl 16 . . 1110010111...... A+-DXWL... U U U U 8 8 5 5 +rtd 32 . . 0100111001110100 .......... . U U U . 16 10 10 +rte 32 . . 0100111001110011 .......... S S S S 20 24 20 20 bus fault not emulated +rtm 32 . . 000001101100.... .......... . . U U . . 19 19 not properly emulated +rtr 32 . . 0100111001110111 .......... U U U U 20 20 14 14 +rts 32 . . 0100111001110101 .......... U U U U 16 16 10 10 +sbcd 8 rr . 1000...100000... .......... U U U U 6 6 4 4 +sbcd 8 mm ax7 1000111100001... .......... U U U U 18 18 16 16 +sbcd 8 mm ay7 1000...100001111 .......... U U U U 18 18 16 16 +sbcd 8 mm axy7 1000111100001111 .......... U U U U 18 18 16 16 +sbcd 8 mm . 1000...100001... .......... U U U U 18 18 16 16 +st 8 . d 0101000011000... .......... U U U U 6 4 4 4 +st 8 . . 0101000011...... A+-DXWL... U U U U 8 8 6 6 +sf 8 . d 0101000111000... .......... U U U U 4 4 4 4 +sf 8 . . 0101000111...... A+-DXWL... U U U U 8 8 6 6 +scc 8 . d 0101....11000... .......... U U U U 4 4 4 4 +scc 8 . . 0101....11...... A+-DXWL... U U U U 8 8 6 6 +stop 0 . . 0100111001110010 .......... S S S S 4 4 8 8 +sub 8 er d 1001...000000... .......... U U U U 4 4 2 2 +sub 8 er . 1001...000...... A+-DXWLdxI U U U U 4 4 2 2 +sub 16 er d 1001...001000... .......... U U U U 4 4 2 2 +sub 16 er a 1001...001001... .......... U U U U 4 4 2 2 +sub 16 er . 1001...001...... A+-DXWLdxI U U U U 4 4 2 2 +sub 32 er d 1001...010000... .......... U U U U 6 6 2 2 +sub 32 er a 1001...010001... .......... U U U U 6 6 2 2 +sub 32 er . 1001...010...... A+-DXWLdxI U U U U 6 6 2 2 +sub 8 re . 1001...100...... A+-DXWL... U U U U 8 8 4 4 +sub 16 re . 1001...101...... A+-DXWL... U U U U 8 8 4 4 +sub 32 re . 1001...110...... A+-DXWL... U U U U 12 12 4 4 +suba 16 . d 1001...011000... .......... U U U U 8 8 2 2 +suba 16 . a 1001...011001... .......... U U U U 8 8 2 2 +suba 16 . . 1001...011...... A+-DXWLdxI U U U U 8 8 2 2 +suba 32 . d 1001...111000... .......... U U U U 6 6 2 2 +suba 32 . a 1001...111001... .......... U U U U 6 6 2 2 +suba 32 . . 1001...111...... A+-DXWLdxI U U U U 6 6 2 2 +subi 8 . d 0000010000000... .......... U U U U 8 8 2 2 +subi 8 . . 0000010000...... A+-DXWL... U U U U 12 12 4 4 +subi 16 . d 0000010001000... .......... U U U U 8 8 2 2 +subi 16 . . 0000010001...... A+-DXWL... U U U U 12 12 4 4 +subi 32 . d 0000010010000... .......... U U U U 16 14 2 2 +subi 32 . . 0000010010...... A+-DXWL... U U U U 20 20 4 4 +subq 8 . d 0101...100000... .......... U U U U 4 4 2 2 +subq 8 . . 0101...100...... A+-DXWL... U U U U 8 8 4 4 +subq 16 . d 0101...101000... .......... U U U U 4 4 2 2 +subq 16 . a 0101...101001... .......... U U U U 8 4 2 2 +subq 16 . . 0101...101...... A+-DXWL... U U U U 8 8 4 4 +subq 32 . d 0101...110000... .......... U U U U 8 8 2 2 +subq 32 . a 0101...110001... .......... U U U U 8 8 2 2 +subq 32 . . 0101...110...... A+-DXWL... U U U U 12 12 4 4 +subx 8 rr . 1001...100000... .......... U U U U 4 4 2 2 +subx 16 rr . 1001...101000... .......... U U U U 4 4 2 2 +subx 32 rr . 1001...110000... .......... U U U U 8 6 2 2 +subx 8 mm ax7 1001111100001... .......... U U U U 18 18 12 12 +subx 8 mm ay7 1001...100001111 .......... U U U U 18 18 12 12 +subx 8 mm axy7 1001111100001111 .......... U U U U 18 18 12 12 +subx 8 mm . 1001...100001... .......... U U U U 18 18 12 12 +subx 16 mm . 1001...101001... .......... U U U U 18 18 12 12 +subx 32 mm . 1001...110001... .......... U U U U 30 30 12 12 +swap 32 . . 0100100001000... .......... U U U U 4 4 4 4 +tas 8 . d 0100101011000... .......... U U U U 4 4 4 4 +tas 8 . . 0100101011...... A+-DXWL... U U U U 14 14 12 12 +trap 0 . . 010011100100.... .......... U U U U 4 4 4 4 +trapt 0 . . 0101000011111100 .......... . . U U . . 4 4 +trapt 16 . . 0101000011111010 .......... . . U U . . 6 6 +trapt 32 . . 0101000011111011 .......... . . U U . . 8 8 +trapf 0 . . 0101000111111100 .......... . . U U . . 4 4 +trapf 16 . . 0101000111111010 .......... . . U U . . 6 6 +trapf 32 . . 0101000111111011 .......... . . U U . . 8 8 +trapcc 0 . . 0101....11111100 .......... . . U U . . 4 4 +trapcc 16 . . 0101....11111010 .......... . . U U . . 6 6 +trapcc 32 . . 0101....11111011 .......... . . U U . . 8 8 +trapv 0 . . 0100111001110110 .......... U U U U 4 4 4 4 +tst 8 . d 0100101000000... .......... U U U U 4 4 2 2 +tst 8 . . 0100101000...... A+-DXWL... U U U U 4 4 2 2 +tst 8 . pcdi 0100101000111010 .......... . . U U . . 7 7 +tst 8 . pcix 0100101000111011 .......... . . U U . . 9 9 +tst 8 . i 0100101000111100 .......... . . U U . . 6 6 +tst 16 . d 0100101001000... .......... U U U U 4 4 2 2 +tst 16 . a 0100101001001... .......... . . U U . . 2 2 +tst 16 . . 0100101001...... A+-DXWL... U U U U 4 4 2 2 +tst 16 . pcdi 0100101001111010 .......... . . U U . . 7 7 +tst 16 . pcix 0100101001111011 .......... . . U U . . 9 9 +tst 16 . i 0100101001111100 .......... . . U U . . 6 6 +tst 32 . d 0100101010000... .......... U U U U 4 4 2 2 +tst 32 . a 0100101010001... .......... . . U U . . 2 2 +tst 32 . . 0100101010...... A+-DXWL... U U U U 4 4 2 2 +tst 32 . pcdi 0100101010111010 .......... . . U U . . 7 7 +tst 32 . pcix 0100101010111011 .......... . . U U . . 9 9 +tst 32 . i 0100101010111100 .......... . . U U . . 6 6 +unlk 32 . a7 0100111001011111 .......... U U U U 12 12 6 6 +unlk 32 . . 0100111001011... .......... U U U U 12 12 6 6 +unpk 16 rr . 1000...110000... .......... . . U U . . 8 8 +unpk 16 mm ax7 1000111110001... .......... . . U U . . 13 13 +unpk 16 mm ay7 1000...110001111 .......... . . U U . . 13 13 +unpk 16 mm axy7 1000111110001111 .......... . . U U . . 13 13 +unpk 16 mm . 1000...110001... .......... . . U U . . 13 13 + + + +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +M68KMAKE_OPCODE_HANDLER_BODY + +M68KMAKE_OP(1010, 0, ., .) +{ + m68ki_exception_1010(); +} + + +M68KMAKE_OP(1111, 0, ., .) +{ + m68ki_exception_1111(); +} + + +M68KMAKE_OP(abcd, 8, rr, .) +{ + uint* r_dst = &DX; + uint src = DY; + uint dst = *r_dst; + uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(); + + FLAG_V = ~res; /* Undefined V behavior */ + + if(res > 9) + res += 6; + res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); + FLAG_X = FLAG_C = (res > 0x99) << 8; + if(FLAG_C) + res -= 0xa0; + + FLAG_V &= res; /* Undefined V behavior part II */ + FLAG_N = NFLAG_8(res); /* Undefined N behavior */ + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; +} + + +M68KMAKE_OP(abcd, 8, mm, ax7) +{ + uint src = OPER_AY_PD_8(); + uint ea = EA_A7_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(); + + FLAG_V = ~res; /* Undefined V behavior */ + + if(res > 9) + res += 6; + res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); + FLAG_X = FLAG_C = (res > 0x99) << 8; + if(FLAG_C) + res -= 0xa0; + + FLAG_V &= res; /* Undefined V behavior part II */ + FLAG_N = NFLAG_8(res); /* Undefined N behavior */ + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +M68KMAKE_OP(abcd, 8, mm, ay7) +{ + uint src = OPER_A7_PD_8(); + uint ea = EA_AX_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(); + + FLAG_V = ~res; /* Undefined V behavior */ + + if(res > 9) + res += 6; + res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); + FLAG_X = FLAG_C = (res > 0x99) << 8; + if(FLAG_C) + res -= 0xa0; + + FLAG_V &= res; /* Undefined V behavior part II */ + FLAG_N = NFLAG_8(res); /* Undefined N behavior */ + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +M68KMAKE_OP(abcd, 8, mm, axy7) +{ + uint src = OPER_A7_PD_8(); + uint ea = EA_A7_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(); + + FLAG_V = ~res; /* Undefined V behavior */ + + if(res > 9) + res += 6; + res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); + FLAG_X = FLAG_C = (res > 0x99) << 8; + if(FLAG_C) + res -= 0xa0; + + FLAG_V &= res; /* Undefined V behavior part II */ + FLAG_N = NFLAG_8(res); /* Undefined N behavior */ + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +M68KMAKE_OP(abcd, 8, mm, .) +{ + uint src = OPER_AY_PD_8(); + uint ea = EA_AX_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(); + + FLAG_V = ~res; /* Undefined V behavior */ + + if(res > 9) + res += 6; + res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); + FLAG_X = FLAG_C = (res > 0x99) << 8; + if(FLAG_C) + res -= 0xa0; + + FLAG_V &= res; /* Undefined V behavior part II */ + FLAG_N = NFLAG_8(res); /* Undefined N behavior */ + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +M68KMAKE_OP(add, 8, er, d) +{ + uint* r_dst = &DX; + uint src = MASK_OUT_ABOVE_8(DY); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +M68KMAKE_OP(add, 8, er, .) +{ + uint* r_dst = &DX; + uint src = M68KMAKE_GET_OPER_AY_8; + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +M68KMAKE_OP(add, 16, er, d) +{ + uint* r_dst = &DX; + uint src = MASK_OUT_ABOVE_16(DY); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +M68KMAKE_OP(add, 16, er, a) +{ + uint* r_dst = &DX; + uint src = MASK_OUT_ABOVE_16(AY); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +M68KMAKE_OP(add, 16, er, .) +{ + uint* r_dst = &DX; + uint src = M68KMAKE_GET_OPER_AY_16; + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +M68KMAKE_OP(add, 32, er, d) +{ + uint* r_dst = &DX; + uint src = DY; + uint dst = *r_dst; + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +M68KMAKE_OP(add, 32, er, a) +{ + uint* r_dst = &DX; + uint src = AY; + uint dst = *r_dst; + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +M68KMAKE_OP(add, 32, er, .) +{ + uint* r_dst = &DX; + uint src = M68KMAKE_GET_OPER_AY_32; + uint dst = *r_dst; + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +M68KMAKE_OP(add, 8, re, .) +{ + uint ea = M68KMAKE_GET_EA_AY_8; + uint src = MASK_OUT_ABOVE_8(DX); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +M68KMAKE_OP(add, 16, re, .) +{ + uint ea = M68KMAKE_GET_EA_AY_16; + uint src = MASK_OUT_ABOVE_16(DX); + uint dst = m68ki_read_16(ea); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +M68KMAKE_OP(add, 32, re, .) +{ + uint ea = M68KMAKE_GET_EA_AY_32; + uint src = DX; + uint dst = m68ki_read_32(ea); + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +M68KMAKE_OP(adda, 16, ., d) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + MAKE_INT_16(DY)); +} + + +M68KMAKE_OP(adda, 16, ., a) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + MAKE_INT_16(AY)); +} + + +M68KMAKE_OP(adda, 16, ., .) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + MAKE_INT_16(M68KMAKE_GET_OPER_AY_16)); +} + + +M68KMAKE_OP(adda, 32, ., d) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + DY); +} + + +M68KMAKE_OP(adda, 32, ., a) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + AY); +} + + +M68KMAKE_OP(adda, 32, ., .) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + M68KMAKE_GET_OPER_AY_32); +} + + +M68KMAKE_OP(addi, 8, ., d) +{ + uint* r_dst = &DY; + uint src = OPER_I_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +M68KMAKE_OP(addi, 8, ., .) +{ + uint src = OPER_I_8(); + uint ea = M68KMAKE_GET_EA_AY_8; + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +M68KMAKE_OP(addi, 16, ., d) +{ + uint* r_dst = &DY; + uint src = OPER_I_16(); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +M68KMAKE_OP(addi, 16, ., .) +{ + uint src = OPER_I_16(); + uint ea = M68KMAKE_GET_EA_AY_16; + uint dst = m68ki_read_16(ea); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +M68KMAKE_OP(addi, 32, ., d) +{ + uint* r_dst = &DY; + uint src = OPER_I_32(); + uint dst = *r_dst; + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +M68KMAKE_OP(addi, 32, ., .) +{ + uint src = OPER_I_32(); + uint ea = M68KMAKE_GET_EA_AY_32; + uint dst = m68ki_read_32(ea); + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +M68KMAKE_OP(addq, 8, ., d) +{ + uint* r_dst = &DY; + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +M68KMAKE_OP(addq, 8, ., .) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = M68KMAKE_GET_EA_AY_8; + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +M68KMAKE_OP(addq, 16, ., d) +{ + uint* r_dst = &DY; + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +M68KMAKE_OP(addq, 16, ., a) +{ + uint* r_dst = &AY; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + (((REG_IR >> 9) - 1) & 7) + 1); +} + + +M68KMAKE_OP(addq, 16, ., .) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = M68KMAKE_GET_EA_AY_16; + uint dst = m68ki_read_16(ea); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +M68KMAKE_OP(addq, 32, ., d) +{ + uint* r_dst = &DY; + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint dst = *r_dst; + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +M68KMAKE_OP(addq, 32, ., a) +{ + uint* r_dst = &AY; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + (((REG_IR >> 9) - 1) & 7) + 1); +} + + +M68KMAKE_OP(addq, 32, ., .) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = M68KMAKE_GET_EA_AY_32; + uint dst = m68ki_read_32(ea); + uint res = src + dst; + + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +M68KMAKE_OP(addx, 8, rr, .) +{ + uint* r_dst = &DX; + uint src = MASK_OUT_ABOVE_8(DY); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = src + dst + XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; +} + + +M68KMAKE_OP(addx, 16, rr, .) +{ + uint* r_dst = &DX; + uint src = MASK_OUT_ABOVE_16(DY); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = src + dst + XFLAG_AS_1(); + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + + res = MASK_OUT_ABOVE_16(res); + FLAG_Z |= res; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; +} + + +M68KMAKE_OP(addx, 32, rr, .) +{ + uint* r_dst = &DX; + uint src = DY; + uint dst = *r_dst; + uint res = src + dst + XFLAG_AS_1(); + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + + res = MASK_OUT_ABOVE_32(res); + FLAG_Z |= res; + + *r_dst = res; +} + + +M68KMAKE_OP(addx, 8, mm, ax7) +{ + uint src = OPER_AY_PD_8(); + uint ea = EA_A7_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst + XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +M68KMAKE_OP(addx, 8, mm, ay7) +{ + uint src = OPER_A7_PD_8(); + uint ea = EA_AX_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst + XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +M68KMAKE_OP(addx, 8, mm, axy7) +{ + uint src = OPER_A7_PD_8(); + uint ea = EA_A7_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst + XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +M68KMAKE_OP(addx, 8, mm, .) +{ + uint src = OPER_AY_PD_8(); + uint ea = EA_AX_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst + XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +M68KMAKE_OP(addx, 16, mm, .) +{ + uint src = OPER_AY_PD_16(); + uint ea = EA_AX_PD_16(); + uint dst = m68ki_read_16(ea); + uint res = src + dst + XFLAG_AS_1(); + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + + res = MASK_OUT_ABOVE_16(res); + FLAG_Z |= res; + + m68ki_write_16(ea, res); +} + + +M68KMAKE_OP(addx, 32, mm, .) +{ + uint src = OPER_AY_PD_32(); + uint ea = EA_AX_PD_32(); + uint dst = m68ki_read_32(ea); + uint res = src + dst + XFLAG_AS_1(); + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + + res = MASK_OUT_ABOVE_32(res); + FLAG_Z |= res; + + m68ki_write_32(ea, res); +} + + +M68KMAKE_OP(and, 8, er, d) +{ + FLAG_Z = MASK_OUT_ABOVE_8(DX &= (DY | 0xffffff00)); + + FLAG_N = NFLAG_8(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(and, 8, er, .) +{ + FLAG_Z = MASK_OUT_ABOVE_8(DX &= (M68KMAKE_GET_OPER_AY_8 | 0xffffff00)); + + FLAG_N = NFLAG_8(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(and, 16, er, d) +{ + FLAG_Z = MASK_OUT_ABOVE_16(DX &= (DY | 0xffff0000)); + + FLAG_N = NFLAG_16(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(and, 16, er, .) +{ + FLAG_Z = MASK_OUT_ABOVE_16(DX &= (M68KMAKE_GET_OPER_AY_16 | 0xffff0000)); + + FLAG_N = NFLAG_16(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(and, 32, er, d) +{ + FLAG_Z = DX &= DY; + + FLAG_N = NFLAG_32(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(and, 32, er, .) +{ + FLAG_Z = DX &= M68KMAKE_GET_OPER_AY_32; + + FLAG_N = NFLAG_32(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(and, 8, re, .) +{ + uint ea = M68KMAKE_GET_EA_AY_8; + uint res = DX & m68ki_read_8(ea); + + FLAG_N = NFLAG_8(res); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +M68KMAKE_OP(and, 16, re, .) +{ + uint ea = M68KMAKE_GET_EA_AY_16; + uint res = DX & m68ki_read_16(ea); + + FLAG_N = NFLAG_16(res); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +M68KMAKE_OP(and, 32, re, .) +{ + uint ea = M68KMAKE_GET_EA_AY_32; + uint res = DX & m68ki_read_32(ea); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_32(ea, res); +} + + +M68KMAKE_OP(andi, 8, ., d) +{ + FLAG_Z = MASK_OUT_ABOVE_8(DY &= (OPER_I_8() | 0xffffff00)); + + FLAG_N = NFLAG_8(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(andi, 8, ., .) +{ + uint src = OPER_I_8(); + uint ea = M68KMAKE_GET_EA_AY_8; + uint res = src & m68ki_read_8(ea); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_8(ea, res); +} + + +M68KMAKE_OP(andi, 16, ., d) +{ + FLAG_Z = MASK_OUT_ABOVE_16(DY &= (OPER_I_16() | 0xffff0000)); + + FLAG_N = NFLAG_16(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(andi, 16, ., .) +{ + uint src = OPER_I_16(); + uint ea = M68KMAKE_GET_EA_AY_16; + uint res = src & m68ki_read_16(ea); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_16(ea, res); +} + + +M68KMAKE_OP(andi, 32, ., d) +{ + FLAG_Z = DY &= (OPER_I_32()); + + FLAG_N = NFLAG_32(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(andi, 32, ., .) +{ + uint src = OPER_I_32(); + uint ea = M68KMAKE_GET_EA_AY_32; + uint res = src & m68ki_read_32(ea); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_32(ea, res); +} + + +M68KMAKE_OP(andi, 16, toc, .) +{ + m68ki_set_ccr(m68ki_get_ccr() & OPER_I_16()); +} + + +M68KMAKE_OP(andi, 16, tos, .) +{ + if(FLAG_S) + { + uint src = OPER_I_16(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr(m68ki_get_sr() & src); + return; + } + m68ki_exception_privilege_violation(); +} + + +M68KMAKE_OP(asr, 8, s, .) +{ + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_8(*r_dst); + uint res = src >> shift; + + if(shift != 0) + USE_CYCLES(shift<> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_16(*r_dst); + uint res = src >> shift; + + if(shift != 0) + USE_CYCLES(shift<> 9) - 1) & 7) + 1; + uint src = *r_dst; + uint res = src >> shift; + + if(shift != 0) + USE_CYCLES(shift<> shift; + + if(shift != 0) + { + USE_CYCLES(shift<> shift; + + if(shift != 0) + { + USE_CYCLES(shift<> (shift - 1))<<8; + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + if(GET_MSB_16(src)) + { + *r_dst |= 0xffff; + FLAG_C = CFLAG_SET; + FLAG_X = XFLAG_SET; + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + return; + } + + *r_dst &= 0xffff0000; + FLAG_C = CFLAG_CLEAR; + FLAG_X = XFLAG_CLEAR; + FLAG_N = NFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_16(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(asr, 32, r, .) +{ + uint* r_dst = &DY; + uint shift = DX & 0x3f; + uint src = *r_dst; + uint res = src >> shift; + + if(shift != 0) + { + USE_CYCLES(shift<> (shift - 1))<<8; + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + if(GET_MSB_32(src)) + { + *r_dst = 0xffffffff; + FLAG_C = CFLAG_SET; + FLAG_X = XFLAG_SET; + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + return; + } + + *r_dst = 0; + FLAG_C = CFLAG_CLEAR; + FLAG_X = XFLAG_CLEAR; + FLAG_N = NFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_32(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(asr, 16, ., .) +{ + uint ea = M68KMAKE_GET_EA_AY_16; + uint src = m68ki_read_16(ea); + uint res = src >> 1; + + if(GET_MSB_16(src)) + res |= 0x8000; + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = FLAG_X = src << 8; +} + + +M68KMAKE_OP(asl, 8, s, .) +{ + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_8(*r_dst); + uint res = MASK_OUT_ABOVE_8(src << shift); + + if(shift != 0) + USE_CYCLES(shift<> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_16(*r_dst); + uint res = MASK_OUT_ABOVE_16(src << shift); + + if(shift != 0) + USE_CYCLES(shift<> (8-shift); + src &= m68ki_shift_16_table[shift + 1]; + FLAG_V = (!(src == 0 || src == m68ki_shift_16_table[shift + 1]))<<7; +} + + +M68KMAKE_OP(asl, 32, s, .) +{ + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint src = *r_dst; + uint res = MASK_OUT_ABOVE_32(src << shift); + + if(shift != 0) + USE_CYCLES(shift<> (24-shift); + src &= m68ki_shift_32_table[shift + 1]; + FLAG_V = (!(src == 0 || src == m68ki_shift_32_table[shift + 1]))<<7; +} + + +M68KMAKE_OP(asl, 8, r, .) +{ + uint* r_dst = &DY; + uint shift = DX & 0x3f; + uint src = MASK_OUT_ABOVE_8(*r_dst); + uint res = MASK_OUT_ABOVE_8(src << shift); + + if(shift != 0) + { + USE_CYCLES(shift<> 8; + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + src &= m68ki_shift_16_table[shift + 1]; + FLAG_V = (!(src == 0 || src == m68ki_shift_16_table[shift + 1]))<<7; + return; + } + + *r_dst &= 0xffff0000; + FLAG_X = FLAG_C = ((shift == 16 ? src & 1 : 0))<<8; + FLAG_N = NFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; + FLAG_V = (!(src == 0))<<7; + return; + } + + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_16(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(asl, 32, r, .) +{ + uint* r_dst = &DY; + uint shift = DX & 0x3f; + uint src = *r_dst; + uint res = MASK_OUT_ABOVE_32(src << shift); + + if(shift != 0) + { + USE_CYCLES(shift<> (32 - shift)) << 8; + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + src &= m68ki_shift_32_table[shift + 1]; + FLAG_V = (!(src == 0 || src == m68ki_shift_32_table[shift + 1]))<<7; + return; + } + + *r_dst = 0; + FLAG_X = FLAG_C = ((shift == 32 ? src & 1 : 0))<<8; + FLAG_N = NFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; + FLAG_V = (!(src == 0))<<7; + return; + } + + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_32(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(asl, 16, ., .) +{ + uint ea = M68KMAKE_GET_EA_AY_16; + uint src = m68ki_read_16(ea); + uint res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_X = FLAG_C = src >> 7; + src &= 0xc000; + FLAG_V = (!(src == 0 || src == 0xc000))<<7; +} + + +M68KMAKE_OP(bcc, 8, ., .) +{ + if(M68KMAKE_CC) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); +} + + +M68KMAKE_OP(bcc, 16, ., .) +{ + if(M68KMAKE_CC) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_BCC_NOTAKE_W); +} + + +M68KMAKE_OP(bcc, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(M68KMAKE_CC) + { + uint offset = OPER_I_32(); + REG_PC -= 4; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32(offset); + return; + } + REG_PC += 4; + return; + } + else + { + if(M68KMAKE_CC) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); + } +} + + +M68KMAKE_OP(bchg, 32, r, d) +{ + uint* r_dst = &DY; + uint mask = 1 << (DX & 0x1f); + + FLAG_Z = *r_dst & mask; + *r_dst ^= mask; +} + + +M68KMAKE_OP(bchg, 8, r, .) +{ + uint ea = M68KMAKE_GET_EA_AY_8; + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src ^ mask); +} + + +M68KMAKE_OP(bchg, 32, s, d) +{ + uint* r_dst = &DY; + uint mask = 1 << (OPER_I_8() & 0x1f); + + FLAG_Z = *r_dst & mask; + *r_dst ^= mask; +} + + +M68KMAKE_OP(bchg, 8, s, .) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = M68KMAKE_GET_EA_AY_8; + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src ^ mask); +} + + +M68KMAKE_OP(bclr, 32, r, d) +{ + uint* r_dst = &DY; + uint mask = 1 << (DX & 0x1f); + + FLAG_Z = *r_dst & mask; + *r_dst &= ~mask; +} + + +M68KMAKE_OP(bclr, 8, r, .) +{ + uint ea = M68KMAKE_GET_EA_AY_8; + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src & ~mask); +} + + +M68KMAKE_OP(bclr, 32, s, d) +{ + uint* r_dst = &DY; + uint mask = 1 << (OPER_I_8() & 0x1f); + + FLAG_Z = *r_dst & mask; + *r_dst &= ~mask; +} + + +M68KMAKE_OP(bclr, 8, s, .) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = M68KMAKE_GET_EA_AY_8; + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src & ~mask); +} + + +M68KMAKE_OP(bfchg, 32, ., d) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint offset = (word2>>6)&31; + uint width = word2; + uint* data = &DY; + uint64 mask; + + + if(BIT_B(word2)) + offset = REG_D[offset&7]; + if(BIT_5(word2)) + width = REG_D[width&7]; + + offset &= 31; + width = ((width-1) & 31) + 1; + + mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask = ROR_32(mask, offset); + + FLAG_N = NFLAG_32(*data<>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = M68KMAKE_GET_EA_AY_8; + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = NFLAG_32(data_long << offset); + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + m68ki_write_32(ea, data_long ^ mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + m68ki_write_8(ea+4, data_byte ^ mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(bfclr, 32, ., d) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint offset = (word2>>6)&31; + uint width = word2; + uint* data = &DY; + uint64 mask; + + + if(BIT_B(word2)) + offset = REG_D[offset&7]; + if(BIT_5(word2)) + width = REG_D[width&7]; + + + offset &= 31; + width = ((width-1) & 31) + 1; + + + mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask = ROR_32(mask, offset); + + FLAG_N = NFLAG_32(*data<>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = M68KMAKE_GET_EA_AY_8; + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = NFLAG_32(data_long << offset); + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + m68ki_write_32(ea, data_long & ~mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + m68ki_write_8(ea+4, data_byte & ~mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(bfexts, 32, ., d) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint offset = (word2>>6)&31; + uint width = word2; + uint64 data = DY; + + + if(BIT_B(word2)) + offset = REG_D[offset&7]; + if(BIT_5(word2)) + width = REG_D[width&7]; + + offset &= 31; + width = ((width-1) & 31) + 1; + + data = ROL_32(data, offset); + FLAG_N = NFLAG_32(data); + data = MAKE_INT_32(data) >> (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + REG_D[(word2>>12)&7] = data; + + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(bfexts, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint data; + uint ea = M68KMAKE_GET_EA_AY_8; + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = m68ki_read_32(ea); + + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8(ea+4) << offset) >> 8; + + FLAG_N = NFLAG_32(data); + data = MAKE_INT_32(data) >> (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + REG_D[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(bfextu, 32, ., d) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint offset = (word2>>6)&31; + uint width = word2; + uint64 data = DY; + + + if(BIT_B(word2)) + offset = REG_D[offset&7]; + if(BIT_5(word2)) + width = REG_D[width&7]; + + offset &= 31; + width = ((width-1) & 31) + 1; + + data = ROL_32(data, offset); + FLAG_N = NFLAG_32(data); + data >>= 32 - width; + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + REG_D[(word2>>12)&7] = data; + + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(bfextu, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint data; + uint ea = M68KMAKE_GET_EA_AY_8; + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = m68ki_read_32(ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8(ea+4) << offset) >> 8; + + FLAG_N = NFLAG_32(data); + data >>= (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + REG_D[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(bfffo, 32, ., d) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint offset = (word2>>6)&31; + uint width = word2; + uint64 data = DY; + uint bit; + + + if(BIT_B(word2)) + offset = REG_D[offset&7]; + if(BIT_5(word2)) + width = REG_D[width&7]; + + offset &= 31; + width = ((width-1) & 31) + 1; + + data = ROL_32(data, offset); + FLAG_N = NFLAG_32(data); + data >>= 32 - width; + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + for(bit = 1<<(width-1);bit && !(data & bit);bit>>= 1) + offset++; + + REG_D[(word2>>12)&7] = offset; + + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(bfffo, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + sint local_offset; + uint width = word2; + uint data; + uint bit; + uint ea = M68KMAKE_GET_EA_AY_8; + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + local_offset = offset % 8; + if(local_offset < 0) + { + local_offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = m68ki_read_32(ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8(ea+4) << local_offset) >> 8; + + FLAG_N = NFLAG_32(data); + data >>= (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + for(bit = 1<<(width-1);bit && !(data & bit);bit>>= 1) + offset++; + + REG_D[(word2>>12)&7] = offset; + + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(bfins, 32, ., d) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint offset = (word2>>6)&31; + uint width = word2; + uint* data = &DY; + uint64 mask; + uint64 insert = REG_D[(word2>>12)&7]; + + + if(BIT_B(word2)) + offset = REG_D[offset&7]; + if(BIT_5(word2)) + width = REG_D[width&7]; + + + offset &= 31; + width = ((width-1) & 31) + 1; + + + mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask = ROR_32(mask, offset); + + insert = MASK_OUT_ABOVE_32(insert << (32 - width)); + FLAG_N = NFLAG_32(insert); + FLAG_Z = insert; + insert = ROR_32(insert, offset); + + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + *data &= ~mask; + *data |= insert; + + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(bfins, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint insert_base = REG_D[(word2>>12)&7]; + uint insert_long; + uint insert_byte; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = M68KMAKE_GET_EA_AY_8; + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + insert_base = MASK_OUT_ABOVE_32(insert_base << (32 - width)); + FLAG_N = NFLAG_32(insert_base); + FLAG_Z = insert_base; + insert_long = insert_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + m68ki_write_32(ea, (data_long & ~mask_long) | insert_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + insert_byte = MASK_OUT_ABOVE_8(insert_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + m68ki_write_8(ea+4, (data_byte & ~mask_byte) | insert_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(bfset, 32, ., d) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint offset = (word2>>6)&31; + uint width = word2; + uint* data = &DY; + uint64 mask; + + + if(BIT_B(word2)) + offset = REG_D[offset&7]; + if(BIT_5(word2)) + width = REG_D[width&7]; + + + offset &= 31; + width = ((width-1) & 31) + 1; + + + mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask = ROR_32(mask, offset); + + FLAG_N = NFLAG_32(*data<>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = M68KMAKE_GET_EA_AY_8; + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = NFLAG_32(data_long << offset); + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + m68ki_write_32(ea, data_long | mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + m68ki_write_8(ea+4, data_byte | mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(bftst, 32, ., d) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint offset = (word2>>6)&31; + uint width = word2; + uint* data = &DY; + uint64 mask; + + + if(BIT_B(word2)) + offset = REG_D[offset&7]; + if(BIT_5(word2)) + width = REG_D[width&7]; + + + offset &= 31; + width = ((width-1) & 31) + 1; + + + mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask = ROR_32(mask, offset); + + FLAG_N = NFLAG_32(*data<>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = M68KMAKE_GET_EA_AY_8; + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = ((data_long & (0x80000000 >> offset))<>24; + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(bkpt, 0, ., .) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + m68ki_bkpt_ack(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE) ? REG_IR & 7 : 0); /* auto-disable (see m68kcpu.h) */ + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(bra, 8, ., .) +{ + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); +// if(REG_PC == REG_PPC) +// USE_ALL_CYCLES(); +} + + +M68KMAKE_OP(bra, 16, ., .) +{ + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); +// if(REG_PC == REG_PPC) +// USE_ALL_CYCLES(); +} + + +M68KMAKE_OP(bra, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint offset = OPER_I_32(); + REG_PC -= 4; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32(offset); + if(REG_PC == REG_PPC) + USE_ALL_CYCLES(); + return; + } + else + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); +// if(REG_PC == REG_PPC) +// USE_ALL_CYCLES(); + } +} + + +M68KMAKE_OP(bset, 32, r, d) +{ + uint* r_dst = &DY; + uint mask = 1 << (DX & 0x1f); + + FLAG_Z = *r_dst & mask; + *r_dst |= mask; +} + + +M68KMAKE_OP(bset, 8, r, .) +{ + uint ea = M68KMAKE_GET_EA_AY_8; + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src | mask); +} + + +M68KMAKE_OP(bset, 32, s, d) +{ + uint* r_dst = &DY; + uint mask = 1 << (OPER_I_8() & 0x1f); + + FLAG_Z = *r_dst & mask; + *r_dst |= mask; +} + + +M68KMAKE_OP(bset, 8, s, .) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = M68KMAKE_GET_EA_AY_8; + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src | mask); +} + + +M68KMAKE_OP(bsr, 8, ., .) +{ + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32(REG_PC); + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); +} + + +M68KMAKE_OP(bsr, 16, ., .) +{ + uint offset = OPER_I_16(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32(REG_PC); + REG_PC -= 2; + m68ki_branch_16(offset); +} + + +M68KMAKE_OP(bsr, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint offset = OPER_I_32(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32(REG_PC); + REG_PC -= 4; + m68ki_branch_32(offset); + return; + } + else + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32(REG_PC); + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + } +} + + +M68KMAKE_OP(btst, 32, r, d) +{ + FLAG_Z = DY & (1 << (DX & 0x1f)); +} + + +M68KMAKE_OP(btst, 8, r, .) +{ + FLAG_Z = M68KMAKE_GET_OPER_AY_8 & (1 << (DX & 7)); +} + + +M68KMAKE_OP(btst, 32, s, d) +{ + FLAG_Z = DY & (1 << (OPER_I_8() & 0x1f)); +} + + +M68KMAKE_OP(btst, 8, s, .) +{ + uint bit = OPER_I_8() & 7; + + FLAG_Z = M68KMAKE_GET_OPER_AY_8 & (1 << bit); +} + + +M68KMAKE_OP(callm, 32, ., .) +{ + /* note: watch out for pcrelative modes */ + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + { + uint ea = M68KMAKE_GET_EA_AY_32; + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + REG_PC += 2; +(void)ea; /* just to avoid an 'unused variable' warning */ + M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", + m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, + m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(cas, 8, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = M68KMAKE_GET_EA_AY_8; + uint dest = m68ki_read_8(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - MASK_OUT_ABOVE_8(*compare); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(*compare, dest, res); + FLAG_C = CFLAG_8(res); + + if(COND_NE()) + *compare = MASK_OUT_BELOW_8(*compare) | dest; + else + { + USE_CYCLES(3); + m68ki_write_8(ea, MASK_OUT_ABOVE_8(REG_D[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(cas, 16, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = M68KMAKE_GET_EA_AY_16; + uint dest = m68ki_read_16(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - MASK_OUT_ABOVE_16(*compare); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(*compare, dest, res); + FLAG_C = CFLAG_16(res); + + if(COND_NE()) + *compare = MASK_OUT_BELOW_16(*compare) | dest; + else + { + USE_CYCLES(3); + m68ki_write_16(ea, MASK_OUT_ABOVE_16(REG_D[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(cas, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = M68KMAKE_GET_EA_AY_32; + uint dest = m68ki_read_32(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - *compare; + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(*compare, dest, res); + FLAG_C = CFLAG_SUB_32(*compare, dest, res); + + if(COND_NE()) + *compare = dest; + else + { + USE_CYCLES(3); + m68ki_write_32(ea, REG_D[(word2 >> 6) & 7]); + } + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(cas2, 16, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_32(); + uint* compare1 = ®_D[(word2 >> 16) & 7]; + uint ea1 = REG_DA[(word2 >> 28) & 15]; + uint dest1 = m68ki_read_16(ea1); + uint res1 = dest1 - MASK_OUT_ABOVE_16(*compare1); + uint* compare2 = ®_D[word2 & 7]; + uint ea2 = REG_DA[(word2 >> 12) & 15]; + uint dest2 = m68ki_read_16(ea2); + uint res2; + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_16(res1); + FLAG_Z = MASK_OUT_ABOVE_16(res1); + FLAG_V = VFLAG_SUB_16(*compare1, dest1, res1); + FLAG_C = CFLAG_16(res1); + + if(COND_EQ()) + { + res2 = dest2 - MASK_OUT_ABOVE_16(*compare2); + + FLAG_N = NFLAG_16(res2); + FLAG_Z = MASK_OUT_ABOVE_16(res2); + FLAG_V = VFLAG_SUB_16(*compare2, dest2, res2); + FLAG_C = CFLAG_16(res2); + + if(COND_EQ()) + { + USE_CYCLES(3); + m68ki_write_16(ea1, REG_D[(word2 >> 22) & 7]); + m68ki_write_16(ea2, REG_D[(word2 >> 6) & 7]); + return; + } + } + *compare1 = BIT_1F(word2) ? MAKE_INT_16(dest1) : MASK_OUT_BELOW_16(*compare1) | dest1; + *compare2 = BIT_F(word2) ? MAKE_INT_16(dest2) : MASK_OUT_BELOW_16(*compare2) | dest2; + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(cas2, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_32(); + uint* compare1 = ®_D[(word2 >> 16) & 7]; + uint ea1 = REG_DA[(word2 >> 28) & 15]; + uint dest1 = m68ki_read_32(ea1); + uint res1 = dest1 - *compare1; + uint* compare2 = ®_D[word2 & 7]; + uint ea2 = REG_DA[(word2 >> 12) & 15]; + uint dest2 = m68ki_read_32(ea2); + uint res2; + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_32(res1); + FLAG_Z = MASK_OUT_ABOVE_32(res1); + FLAG_V = VFLAG_SUB_32(*compare1, dest1, res1); + FLAG_C = CFLAG_SUB_32(*compare1, dest1, res1); + + if(COND_EQ()) + { + res2 = dest2 - *compare2; + + FLAG_N = NFLAG_32(res2); + FLAG_Z = MASK_OUT_ABOVE_32(res2); + FLAG_V = VFLAG_SUB_32(*compare2, dest2, res2); + FLAG_C = CFLAG_SUB_32(*compare2, dest2, res2); + + if(COND_EQ()) + { + USE_CYCLES(3); + m68ki_write_32(ea1, REG_D[(word2 >> 22) & 7]); + m68ki_write_32(ea2, REG_D[(word2 >> 6) & 7]); + return; + } + } + *compare1 = dest1; + *compare2 = dest2; + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(chk, 16, ., d) +{ + sint src = MAKE_INT_16(DX); + sint bound = MAKE_INT_16(DY); + + FLAG_Z = ZFLAG_16(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); +} + + +M68KMAKE_OP(chk, 16, ., .) +{ + sint src = MAKE_INT_16(DX); + sint bound = MAKE_INT_16(M68KMAKE_GET_OPER_AY_16); + + FLAG_Z = ZFLAG_16(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); +} + + +M68KMAKE_OP(chk, 32, ., d) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + sint src = MAKE_INT_32(DX); + sint bound = MAKE_INT_32(DY); + + FLAG_Z = ZFLAG_32(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(chk, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + sint src = MAKE_INT_32(DX); + sint bound = MAKE_INT_32(M68KMAKE_GET_OPER_AY_32); + + FLAG_Z = ZFLAG_32(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(chk2cmp2, 8, ., pcdi) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]&0xff; + uint ea = EA_PCDI_8(); + uint lower_bound = m68ki_read_pcrel_8(ea); + uint upper_bound = m68ki_read_pcrel_8(ea + 1); + + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound); + else + FLAG_C = compare - lower_bound; + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + + FLAG_C = upper_bound - compare; + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(chk2cmp2, 8, ., pcix) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]&0xff; + uint ea = EA_PCIX_8(); + uint lower_bound = m68ki_read_pcrel_8(ea); + uint upper_bound = m68ki_read_pcrel_8(ea + 1); + + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound); + else + FLAG_C = compare - lower_bound; + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + + FLAG_C = upper_bound - compare; + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(chk2cmp2, 8, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]&0xff; + uint ea = M68KMAKE_GET_EA_AY_8; + uint lower_bound = m68ki_read_8(ea); + uint upper_bound = m68ki_read_8(ea + 1); + + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound); + else + FLAG_C = compare - lower_bound; + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + + FLAG_C = upper_bound - compare; + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(chk2cmp2, 16, ., pcdi) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]&0xffff; + uint ea = EA_PCDI_16(); + uint lower_bound = m68ki_read_pcrel_16(ea); + uint upper_bound = m68ki_read_pcrel_16(ea + 2); + + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound); + else + FLAG_C = compare - lower_bound; + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + FLAG_C = CFLAG_16(FLAG_C); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare); + else + FLAG_C = upper_bound - compare; + FLAG_C = CFLAG_16(FLAG_C); + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(chk2cmp2, 16, ., pcix) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]&0xffff; + uint ea = EA_PCIX_16(); + uint lower_bound = m68ki_read_pcrel_16(ea); + uint upper_bound = m68ki_read_pcrel_16(ea + 2); + + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound); + else + FLAG_C = compare - lower_bound; + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + FLAG_C = CFLAG_16(FLAG_C); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare); + else + FLAG_C = upper_bound - compare; + FLAG_C = CFLAG_16(FLAG_C); + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(chk2cmp2, 16, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]&0xffff; + uint ea = M68KMAKE_GET_EA_AY_16; + uint lower_bound = m68ki_read_16(ea); + uint upper_bound = m68ki_read_16(ea + 2); + + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound); + else + FLAG_C = compare - lower_bound; + + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + FLAG_C = CFLAG_16(FLAG_C); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare); + else + FLAG_C = upper_bound - compare; + + FLAG_C = CFLAG_16(FLAG_C); + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(chk2cmp2, 32, ., pcdi) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]; + uint ea = EA_PCDI_32(); + uint lower_bound = m68ki_read_pcrel_32(ea); + uint upper_bound = m68ki_read_pcrel_32(ea + 4); + + FLAG_C = compare - lower_bound; + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + FLAG_C = CFLAG_SUB_32(lower_bound, compare, FLAG_C); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + + FLAG_C = upper_bound - compare; + FLAG_C = CFLAG_SUB_32(compare, upper_bound, FLAG_C); + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(chk2cmp2, 32, ., pcix) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]; + uint ea = EA_PCIX_32(); + uint lower_bound = m68ki_read_pcrel_32(ea); + uint upper_bound = m68ki_read_pcrel_32(ea + 4); + + FLAG_C = compare - lower_bound; + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + FLAG_C = CFLAG_SUB_32(lower_bound, compare, FLAG_C); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + + FLAG_C = upper_bound - compare; + FLAG_C = CFLAG_SUB_32(compare, upper_bound, FLAG_C); + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(chk2cmp2, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]; + uint ea = M68KMAKE_GET_EA_AY_32; + uint lower_bound = m68ki_read_32(ea); + uint upper_bound = m68ki_read_32(ea + 4); + + FLAG_C = compare - lower_bound; + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + FLAG_C = CFLAG_SUB_32(lower_bound, compare, FLAG_C); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + + FLAG_C = upper_bound - compare; + FLAG_C = CFLAG_SUB_32(compare, upper_bound, FLAG_C); + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(clr, 8, ., d) +{ + DY &= 0xffffff00; + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +M68KMAKE_OP(clr, 8, ., .) +{ + m68ki_write_8(M68KMAKE_GET_EA_AY_8, 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +M68KMAKE_OP(clr, 16, ., d) +{ + DY &= 0xffff0000; + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +M68KMAKE_OP(clr, 16, ., .) +{ + m68ki_write_16(M68KMAKE_GET_EA_AY_16, 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +M68KMAKE_OP(clr, 32, ., d) +{ + DY = 0; + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +M68KMAKE_OP(clr, 32, ., .) +{ + m68ki_write_32(M68KMAKE_GET_EA_AY_32, 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +M68KMAKE_OP(cmp, 8, ., d) +{ + uint src = MASK_OUT_ABOVE_8(DY); + uint dst = MASK_OUT_ABOVE_8(DX); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +M68KMAKE_OP(cmp, 8, ., .) +{ + uint src = M68KMAKE_GET_OPER_AY_8; + uint dst = MASK_OUT_ABOVE_8(DX); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +M68KMAKE_OP(cmp, 16, ., d) +{ + uint src = MASK_OUT_ABOVE_16(DY); + uint dst = MASK_OUT_ABOVE_16(DX); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +M68KMAKE_OP(cmp, 16, ., a) +{ + uint src = MASK_OUT_ABOVE_16(AY); + uint dst = MASK_OUT_ABOVE_16(DX); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +M68KMAKE_OP(cmp, 16, ., .) +{ + uint src = M68KMAKE_GET_OPER_AY_16; + uint dst = MASK_OUT_ABOVE_16(DX); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +M68KMAKE_OP(cmp, 32, ., d) +{ + uint src = DY; + uint dst = DX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +M68KMAKE_OP(cmp, 32, ., a) +{ + uint src = AY; + uint dst = DX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +M68KMAKE_OP(cmp, 32, ., .) +{ + uint src = M68KMAKE_GET_OPER_AY_32; + uint dst = DX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +M68KMAKE_OP(cmpa, 16, ., d) +{ + uint src = MAKE_INT_16(DY); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +M68KMAKE_OP(cmpa, 16, ., a) +{ + uint src = MAKE_INT_16(AY); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +M68KMAKE_OP(cmpa, 16, ., .) +{ + uint src = MAKE_INT_16(M68KMAKE_GET_OPER_AY_16); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +M68KMAKE_OP(cmpa, 32, ., d) +{ + uint src = DY; + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +M68KMAKE_OP(cmpa, 32, ., a) +{ + uint src = AY; + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +M68KMAKE_OP(cmpa, 32, ., .) +{ + uint src = M68KMAKE_GET_OPER_AY_32; + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +M68KMAKE_OP(cmpi, 8, ., d) +{ + uint src = OPER_I_8(); + uint dst = MASK_OUT_ABOVE_8(DY); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +M68KMAKE_OP(cmpi, 8, ., .) +{ + uint src = OPER_I_8(); + uint dst = M68KMAKE_GET_OPER_AY_8; + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +M68KMAKE_OP(cmpi, 8, ., pcdi) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint src = OPER_I_8(); + uint dst = OPER_PCDI_8(); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(cmpi, 8, ., pcix) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint src = OPER_I_8(); + uint dst = OPER_PCIX_8(); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(cmpi, 16, ., d) +{ + uint src = OPER_I_16(); + uint dst = MASK_OUT_ABOVE_16(DY); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +M68KMAKE_OP(cmpi, 16, ., .) +{ + uint src = OPER_I_16(); + uint dst = M68KMAKE_GET_OPER_AY_16; + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +M68KMAKE_OP(cmpi, 16, ., pcdi) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint src = OPER_I_16(); + uint dst = OPER_PCDI_16(); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(cmpi, 16, ., pcix) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint src = OPER_I_16(); + uint dst = OPER_PCIX_16(); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(cmpi, 32, ., d) +{ + uint src = OPER_I_32(); + uint dst = DY; + uint res = dst - src; + + m68ki_cmpild_callback(src, REG_IR & 7); /* auto-disable (see m68kcpu.h) */ + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +M68KMAKE_OP(cmpi, 32, ., .) +{ + uint src = OPER_I_32(); + uint dst = M68KMAKE_GET_OPER_AY_32; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +M68KMAKE_OP(cmpi, 32, ., pcdi) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint src = OPER_I_32(); + uint dst = OPER_PCDI_32(); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(cmpi, 32, ., pcix) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint src = OPER_I_32(); + uint dst = OPER_PCIX_32(); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(cmpm, 8, ., ax7) +{ + uint src = OPER_AY_PI_8(); + uint dst = OPER_A7_PI_8(); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +M68KMAKE_OP(cmpm, 8, ., ay7) +{ + uint src = OPER_A7_PI_8(); + uint dst = OPER_AX_PI_8(); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +M68KMAKE_OP(cmpm, 8, ., axy7) +{ + uint src = OPER_A7_PI_8(); + uint dst = OPER_A7_PI_8(); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +M68KMAKE_OP(cmpm, 8, ., .) +{ + uint src = OPER_AY_PI_8(); + uint dst = OPER_AX_PI_8(); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +M68KMAKE_OP(cmpm, 16, ., .) +{ + uint src = OPER_AY_PI_16(); + uint dst = OPER_AX_PI_16(); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +M68KMAKE_OP(cmpm, 32, ., .) +{ + uint src = OPER_AY_PI_32(); + uint dst = OPER_AX_PI_32(); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +M68KMAKE_OP(cpbcc, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", + m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, + m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); + return; + } + m68ki_exception_1111(); +} + + +M68KMAKE_OP(cpdbcc, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", + m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, + m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); + return; + } + m68ki_exception_1111(); +} + + +M68KMAKE_OP(cpgen, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", + m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, + m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); + return; + } + m68ki_exception_1111(); +} + + +M68KMAKE_OP(cpscc, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", + m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, + m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); + return; + } + m68ki_exception_1111(); +} + + +M68KMAKE_OP(cptrapcc, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", + m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, + m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); + return; + } + m68ki_exception_1111(); +} + + +M68KMAKE_OP(dbt, 16, ., .) +{ + REG_PC += 2; +} + + +M68KMAKE_OP(dbf, 16, ., .) +{ + uint* r_dst = &DY; + uint res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + USE_CYCLES(CYC_DBCC_F_NOEXP); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_DBCC_F_EXP); +} + + +M68KMAKE_OP(dbcc, 16, ., .) +{ + if(M68KMAKE_NOT_CC) + { + uint* r_dst = &DY; + uint res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + USE_CYCLES(CYC_DBCC_F_NOEXP); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_DBCC_F_EXP); + return; + } + REG_PC += 2; +} + + +M68KMAKE_OP(divs, 16, ., d) +{ + uint* r_dst = &DX; + sint src = MAKE_INT_16(DY); + sint quotient; + sint remainder; + + if(src != 0) + { + if((uint32)*r_dst == 0x80000000 && src == -1) + { + FLAG_Z = 0; + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +M68KMAKE_OP(divs, 16, ., .) +{ + uint* r_dst = &DX; + sint src = MAKE_INT_16(M68KMAKE_GET_OPER_AY_16); + sint quotient; + sint remainder; + + if(src != 0) + { + if((uint32)*r_dst == 0x80000000 && src == -1) + { + FLAG_Z = 0; + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +M68KMAKE_OP(divu, 16, ., d) +{ + uint* r_dst = &DX; + uint src = MASK_OUT_ABOVE_16(DY); + + if(src != 0) + { + uint quotient = *r_dst / src; + uint remainder = *r_dst % src; + + if(quotient < 0x10000) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +M68KMAKE_OP(divu, 16, ., .) +{ + uint* r_dst = &DX; + uint src = M68KMAKE_GET_OPER_AY_16; + + if(src != 0) + { + uint quotient = *r_dst / src; + uint remainder = *r_dst % src; + + if(quotient < 0x10000) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +M68KMAKE_OP(divl, 32, ., d) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 divisor = DY; + uint64 dividend = 0; + uint64 quotient = 0; + uint64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D[word2 & 7]; + dividend <<= 32; + dividend |= REG_D[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)dividend / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)dividend % (sint64)((sint32)divisor)); + if((sint64)quotient != (sint64)((sint32)quotient)) + { + FLAG_V = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + FLAG_V = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)((sint32)dividend) / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)((sint32)dividend) % (sint64)((sint32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint divisor = DY; + uint dividend_hi = REG_D[word2 & 7]; + uint dividend_lo = REG_D[(word2 >> 12) & 7]; + uint quotient = 0; + uint remainder = 0; + uint dividend_neg = 0; + uint divisor_neg = 0; + sint i; + uint overflow; + + if(divisor != 0) + { + /* quad / long : long quotient, long remainder */ + if(BIT_A(word2)) + { + if(BIT_B(word2)) /* signed */ + { + /* special case in signed divide */ + if(dividend_hi == 0 && dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + REG_D[word2 & 7] = 0; + REG_D[(word2 >> 12) & 7] = 0x80000000; + + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + if(GET_MSB_32(dividend_hi)) + { + dividend_neg = 1; + dividend_hi = (uint)MASK_OUT_ABOVE_32((-(sint)dividend_hi) - (dividend_lo != 0)); + dividend_lo = (uint)MASK_OUT_ABOVE_32(-(sint)dividend_lo); + } + if(GET_MSB_32(divisor)) + { + divisor_neg = 1; + divisor = (uint)MASK_OUT_ABOVE_32(-(sint)divisor); + + } + } + + /* if the upper long is greater than the divisor, we're overflowing. */ + if(dividend_hi >= divisor) + { + FLAG_V = VFLAG_SET; + return; + } + + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + remainder = (remainder << 1) + ((dividend_hi >> i) & 1); + if(remainder >= divisor) + { + remainder -= divisor; + quotient++; + } + } + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + overflow = GET_MSB_32(remainder); + remainder = (remainder << 1) + ((dividend_lo >> i) & 1); + if(remainder >= divisor || overflow) + { + remainder -= divisor; + quotient++; + } + } + + if(BIT_B(word2)) /* signed */ + { + if(quotient > 0x7fffffff) + { + FLAG_V = VFLAG_SET; + return; + } + if(dividend_neg) + { + remainder = (uint)MASK_OUT_ABOVE_32(-(sint)remainder); + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + if(divisor_neg) + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + + /* long / long: long quotient, maybe long remainder */ + if(BIT_B(word2)) /* signed */ + { + /* Special case in divide */ + if(dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + REG_D[(word2 >> 12) & 7] = 0x80000000; + REG_D[word2 & 7] = 0; + return; + } + REG_D[word2 & 7] = MAKE_INT_32(dividend_lo) % MAKE_INT_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MAKE_INT_32(dividend_lo) / MAKE_INT_32(divisor); + } + else + { + REG_D[word2 & 7] = MASK_OUT_ABOVE_32(dividend_lo) % MASK_OUT_ABOVE_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(dividend_lo) / MASK_OUT_ABOVE_32(divisor); + } + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#endif +} + + +M68KMAKE_OP(divl, 32, ., .) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 divisor = M68KMAKE_GET_OPER_AY_32; + uint64 dividend = 0; + uint64 quotient = 0; + uint64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D[word2 & 7]; + dividend <<= 32; + dividend |= REG_D[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)dividend / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)dividend % (sint64)((sint32)divisor)); + if((sint64)quotient != (sint64)((sint32)quotient)) + { + FLAG_V = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + FLAG_V = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)((sint32)dividend) / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)((sint32)dividend) % (sint64)((sint32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint divisor = M68KMAKE_GET_OPER_AY_32; + uint dividend_hi = REG_D[word2 & 7]; + uint dividend_lo = REG_D[(word2 >> 12) & 7]; + uint quotient = 0; + uint remainder = 0; + uint dividend_neg = 0; + uint divisor_neg = 0; + sint i; + uint overflow; + + if(divisor != 0) + { + /* quad / long : long quotient, long remainder */ + if(BIT_A(word2)) + { + if(BIT_B(word2)) /* signed */ + { + /* special case in signed divide */ + if(dividend_hi == 0 && dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + REG_D[word2 & 7] = 0; + REG_D[(word2 >> 12) & 7] = 0x80000000; + + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + if(GET_MSB_32(dividend_hi)) + { + dividend_neg = 1; + dividend_hi = (uint)MASK_OUT_ABOVE_32((-(sint)dividend_hi) - (dividend_lo != 0)); + dividend_lo = (uint)MASK_OUT_ABOVE_32(-(sint)dividend_lo); + } + if(GET_MSB_32(divisor)) + { + divisor_neg = 1; + divisor = (uint)MASK_OUT_ABOVE_32(-(sint)divisor); + + } + } + + /* if the upper long is greater than the divisor, we're overflowing. */ + if(dividend_hi >= divisor) + { + FLAG_V = VFLAG_SET; + return; + } + + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + remainder = (remainder << 1) + ((dividend_hi >> i) & 1); + if(remainder >= divisor) + { + remainder -= divisor; + quotient++; + } + } + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + overflow = GET_MSB_32(remainder); + remainder = (remainder << 1) + ((dividend_lo >> i) & 1); + if(remainder >= divisor || overflow) + { + remainder -= divisor; + quotient++; + } + } + + if(BIT_B(word2)) /* signed */ + { + if(quotient > 0x7fffffff) + { + FLAG_V = VFLAG_SET; + return; + } + if(dividend_neg) + { + remainder = (uint)MASK_OUT_ABOVE_32(-(sint)remainder); + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + if(divisor_neg) + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + + /* long / long: long quotient, maybe long remainder */ + if(BIT_B(word2)) /* signed */ + { + /* Special case in divide */ + if(dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + REG_D[(word2 >> 12) & 7] = 0x80000000; + REG_D[word2 & 7] = 0; + return; + } + REG_D[word2 & 7] = MAKE_INT_32(dividend_lo) % MAKE_INT_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MAKE_INT_32(dividend_lo) / MAKE_INT_32(divisor); + } + else + { + REG_D[word2 & 7] = MASK_OUT_ABOVE_32(dividend_lo) % MASK_OUT_ABOVE_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(dividend_lo) / MASK_OUT_ABOVE_32(divisor); + } + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#endif +} + + +M68KMAKE_OP(eor, 8, ., d) +{ + uint res = MASK_OUT_ABOVE_8(DY ^= MASK_OUT_ABOVE_8(DX)); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(eor, 8, ., .) +{ + uint ea = M68KMAKE_GET_EA_AY_8; + uint res = MASK_OUT_ABOVE_8(DX ^ m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(eor, 16, ., d) +{ + uint res = MASK_OUT_ABOVE_16(DY ^= MASK_OUT_ABOVE_16(DX)); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(eor, 16, ., .) +{ + uint ea = M68KMAKE_GET_EA_AY_16; + uint res = MASK_OUT_ABOVE_16(DX ^ m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(eor, 32, ., d) +{ + uint res = DY ^= DX; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(eor, 32, ., .) +{ + uint ea = M68KMAKE_GET_EA_AY_32; + uint res = DX ^ m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(eori, 8, ., d) +{ + uint res = MASK_OUT_ABOVE_8(DY ^= OPER_I_8()); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(eori, 8, ., .) +{ + uint src = OPER_I_8(); + uint ea = M68KMAKE_GET_EA_AY_8; + uint res = src ^ m68ki_read_8(ea); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(eori, 16, ., d) +{ + uint res = MASK_OUT_ABOVE_16(DY ^= OPER_I_16()); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(eori, 16, ., .) +{ + uint src = OPER_I_16(); + uint ea = M68KMAKE_GET_EA_AY_16; + uint res = src ^ m68ki_read_16(ea); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(eori, 32, ., d) +{ + uint res = DY ^= OPER_I_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(eori, 32, ., .) +{ + uint src = OPER_I_32(); + uint ea = M68KMAKE_GET_EA_AY_32; + uint res = src ^ m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(eori, 16, toc, .) +{ + m68ki_set_ccr(m68ki_get_ccr() ^ OPER_I_16()); +} + + +M68KMAKE_OP(eori, 16, tos, .) +{ + if(FLAG_S) + { + uint src = OPER_I_16(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr(m68ki_get_sr() ^ src); + return; + } + m68ki_exception_privilege_violation(); +} + + +M68KMAKE_OP(exg, 32, dd, .) +{ + uint* reg_a = &DX; + uint* reg_b = &DY; + uint tmp = *reg_a; + *reg_a = *reg_b; + *reg_b = tmp; +} + + +M68KMAKE_OP(exg, 32, aa, .) +{ + uint* reg_a = &AX; + uint* reg_b = &AY; + uint tmp = *reg_a; + *reg_a = *reg_b; + *reg_b = tmp; +} + + +M68KMAKE_OP(exg, 32, da, .) +{ + uint* reg_a = &DX; + uint* reg_b = &AY; + uint tmp = *reg_a; + *reg_a = *reg_b; + *reg_b = tmp; +} + + +M68KMAKE_OP(ext, 16, ., .) +{ + uint* r_dst = &DY; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | MASK_OUT_ABOVE_8(*r_dst) | (GET_MSB_8(*r_dst) ? 0xff00 : 0); + + FLAG_N = NFLAG_16(*r_dst); + FLAG_Z = MASK_OUT_ABOVE_16(*r_dst); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(ext, 32, ., .) +{ + uint* r_dst = &DY; + + *r_dst = MASK_OUT_ABOVE_16(*r_dst) | (GET_MSB_16(*r_dst) ? 0xffff0000 : 0); + + FLAG_N = NFLAG_32(*r_dst); + FLAG_Z = *r_dst; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(extb, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint* r_dst = &DY; + + *r_dst = MASK_OUT_ABOVE_8(*r_dst) | (GET_MSB_8(*r_dst) ? 0xffffff00 : 0); + + FLAG_N = NFLAG_32(*r_dst); + FLAG_Z = *r_dst; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(illegal, 0, ., .) +{ + m68ki_exception_illegal(); +} + +M68KMAKE_OP(jmp, 32, ., .) +{ + m68ki_jump(M68KMAKE_GET_EA_AY_32); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(REG_PC == REG_PPC) + USE_ALL_CYCLES(); +} + + +M68KMAKE_OP(jsr, 32, ., .) +{ + uint ea = M68KMAKE_GET_EA_AY_32; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32(MAKE_INT_24(REG_PC)); // notaz: Cyclone can't handle 32bit PC and I neet to debug it + m68ki_jump(ea); +} + + +M68KMAKE_OP(lea, 32, ., .) +{ + AX = M68KMAKE_GET_EA_AY_32; +} + + +M68KMAKE_OP(link, 16, ., a7) +{ + REG_A[7] -= 4; + m68ki_write_32(REG_A[7], REG_A[7]); + REG_A[7] = MASK_OUT_ABOVE_32(REG_A[7] + MAKE_INT_16(OPER_I_16())); +} + + +M68KMAKE_OP(link, 16, ., .) +{ + uint* r_dst = &AY; + + m68ki_push_32(*r_dst); + *r_dst = REG_A[7]; + REG_A[7] = MASK_OUT_ABOVE_32(REG_A[7] + MAKE_INT_16(OPER_I_16())); +} + + +M68KMAKE_OP(link, 32, ., a7) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + REG_A[7] -= 4; + m68ki_write_32(REG_A[7], REG_A[7]); + REG_A[7] = MASK_OUT_ABOVE_32(REG_A[7] + OPER_I_32()); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(link, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint* r_dst = &AY; + + m68ki_push_32(*r_dst); + *r_dst = REG_A[7]; + REG_A[7] = MASK_OUT_ABOVE_32(REG_A[7] + OPER_I_32()); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(lsr, 8, s, .) +{ + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_8(*r_dst); + uint res = src >> shift; + + if(shift != 0) + USE_CYCLES(shift<> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_16(*r_dst); + uint res = src >> shift; + + if(shift != 0) + USE_CYCLES(shift<> 9) - 1) & 7) + 1; + uint src = *r_dst; + uint res = src >> shift; + + if(shift != 0) + USE_CYCLES(shift<> shift; + + if(shift != 0) + { + USE_CYCLES(shift<> shift; + + if(shift != 0) + { + USE_CYCLES(shift<> (shift - 1))<<8; + FLAG_N = NFLAG_CLEAR; + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + *r_dst &= 0xffff0000; + FLAG_X = XFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_16(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(lsr, 32, r, .) +{ + uint* r_dst = &DY; + uint shift = DX & 0x3f; + uint src = *r_dst; + uint res = src >> shift; + + if(shift != 0) + { + USE_CYCLES(shift<> (shift - 1))<<8; + FLAG_N = NFLAG_CLEAR; + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + *r_dst = 0; + FLAG_X = FLAG_C = (shift == 32 ? GET_MSB_32(src)>>23 : 0); + FLAG_N = NFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_32(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(lsr, 16, ., .) +{ + uint ea = M68KMAKE_GET_EA_AY_16; + uint src = m68ki_read_16(ea); + uint res = src >> 1; + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_CLEAR; + FLAG_Z = res; + FLAG_C = FLAG_X = src << 8; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(lsl, 8, s, .) +{ + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_8(*r_dst); + uint res = MASK_OUT_ABOVE_8(src << shift); + + if(shift != 0) + USE_CYCLES(shift<> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_16(*r_dst); + uint res = MASK_OUT_ABOVE_16(src << shift); + + if(shift != 0) + USE_CYCLES(shift<> (8-shift); + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(lsl, 32, s, .) +{ + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint src = *r_dst; + uint res = MASK_OUT_ABOVE_32(src << shift); + + if(shift != 0) + USE_CYCLES(shift<> (24-shift); + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(lsl, 8, r, .) +{ + uint* r_dst = &DY; + uint shift = DX & 0x3f; + uint src = MASK_OUT_ABOVE_8(*r_dst); + uint res = MASK_OUT_ABOVE_8(src << shift); + + if(shift != 0) + { + USE_CYCLES(shift<> 8; + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + *r_dst &= 0xffff0000; + FLAG_X = XFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_16(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(lsl, 32, r, .) +{ + uint* r_dst = &DY; + uint shift = DX & 0x3f; + uint src = *r_dst; + uint res = MASK_OUT_ABOVE_32(src << shift); + + if(shift != 0) + { + USE_CYCLES(shift<> (32 - shift)) << 8; + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + *r_dst = 0; + FLAG_X = FLAG_C = ((shift == 32 ? src & 1 : 0))<<8; + FLAG_N = NFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_32(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(lsl, 16, ., .) +{ + uint ea = M68KMAKE_GET_EA_AY_16; + uint src = m68ki_read_16(ea); + uint res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_X = FLAG_C = src >> 7; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, d, d) +{ + uint res = MASK_OUT_ABOVE_8(DY); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, d, .) +{ + uint res = M68KMAKE_GET_OPER_AY_8; + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, ai, d) +{ + uint res = MASK_OUT_ABOVE_8(DY); + uint ea = EA_AX_AI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, ai, .) +{ + uint res = M68KMAKE_GET_OPER_AY_8; + uint ea = EA_AX_AI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, pi7, d) +{ + uint res = MASK_OUT_ABOVE_8(DY); + uint ea = EA_A7_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, pi, d) +{ + uint res = MASK_OUT_ABOVE_8(DY); + uint ea = EA_AX_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, pi7, .) +{ + uint res = M68KMAKE_GET_OPER_AY_8; + uint ea = EA_A7_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, pi, .) +{ + uint res = M68KMAKE_GET_OPER_AY_8; + uint ea = EA_AX_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, pd7, d) +{ + uint res = MASK_OUT_ABOVE_8(DY); + uint ea = EA_A7_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, pd, d) +{ + uint res = MASK_OUT_ABOVE_8(DY); + uint ea = EA_AX_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, pd7, .) +{ + uint res = M68KMAKE_GET_OPER_AY_8; + uint ea = EA_A7_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, pd, .) +{ + uint res = M68KMAKE_GET_OPER_AY_8; + uint ea = EA_AX_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, di, d) +{ + uint res = MASK_OUT_ABOVE_8(DY); + uint ea = EA_AX_DI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, di, .) +{ + uint res = M68KMAKE_GET_OPER_AY_8; + uint ea = EA_AX_DI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, ix, d) +{ + uint res = MASK_OUT_ABOVE_8(DY); + uint ea = EA_AX_IX_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, ix, .) +{ + uint res = M68KMAKE_GET_OPER_AY_8; + uint ea = EA_AX_IX_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, aw, d) +{ + uint res = MASK_OUT_ABOVE_8(DY); + uint ea = EA_AW_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, aw, .) +{ + uint res = M68KMAKE_GET_OPER_AY_8; + uint ea = EA_AW_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, al, d) +{ + uint res = MASK_OUT_ABOVE_8(DY); + uint ea = EA_AL_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, al, .) +{ + uint res = M68KMAKE_GET_OPER_AY_8; + uint ea = EA_AL_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, d, d) +{ + uint res = MASK_OUT_ABOVE_16(DY); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, d, a) +{ + uint res = MASK_OUT_ABOVE_16(AY); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, d, .) +{ + uint res = M68KMAKE_GET_OPER_AY_16; + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, ai, d) +{ + uint res = MASK_OUT_ABOVE_16(DY); + uint ea = EA_AX_AI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, ai, a) +{ + uint res = MASK_OUT_ABOVE_16(AY); + uint ea = EA_AX_AI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, ai, .) +{ + uint res = M68KMAKE_GET_OPER_AY_16; + uint ea = EA_AX_AI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, pi, d) +{ + uint res = MASK_OUT_ABOVE_16(DY); + uint ea = EA_AX_PI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, pi, a) +{ + uint res = MASK_OUT_ABOVE_16(AY); + uint ea = EA_AX_PI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, pi, .) +{ + uint res = M68KMAKE_GET_OPER_AY_16; + uint ea = EA_AX_PI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, pd, d) +{ + uint res = MASK_OUT_ABOVE_16(DY); + uint ea = EA_AX_PD_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, pd, a) +{ + uint res = MASK_OUT_ABOVE_16(AY); + uint ea = EA_AX_PD_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, pd, .) +{ + uint res = M68KMAKE_GET_OPER_AY_16; + uint ea = EA_AX_PD_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, di, d) +{ + uint res = MASK_OUT_ABOVE_16(DY); + uint ea = EA_AX_DI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, di, a) +{ + uint res = MASK_OUT_ABOVE_16(AY); + uint ea = EA_AX_DI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, di, .) +{ + uint res = M68KMAKE_GET_OPER_AY_16; + uint ea = EA_AX_DI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, ix, d) +{ + uint res = MASK_OUT_ABOVE_16(DY); + uint ea = EA_AX_IX_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, ix, a) +{ + uint res = MASK_OUT_ABOVE_16(AY); + uint ea = EA_AX_IX_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, ix, .) +{ + uint res = M68KMAKE_GET_OPER_AY_16; + uint ea = EA_AX_IX_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, aw, d) +{ + uint res = MASK_OUT_ABOVE_16(DY); + uint ea = EA_AW_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, aw, a) +{ + uint res = MASK_OUT_ABOVE_16(AY); + uint ea = EA_AW_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, aw, .) +{ + uint res = M68KMAKE_GET_OPER_AY_16; + uint ea = EA_AW_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, al, d) +{ + uint res = MASK_OUT_ABOVE_16(DY); + uint ea = EA_AL_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, al, a) +{ + uint res = MASK_OUT_ABOVE_16(AY); + uint ea = EA_AL_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, al, .) +{ + uint res = M68KMAKE_GET_OPER_AY_16; + uint ea = EA_AL_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, d, d) +{ + uint res = DY; + uint* r_dst = &DX; + + *r_dst = res; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, d, a) +{ + uint res = AY; + uint* r_dst = &DX; + + *r_dst = res; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, d, .) +{ + uint res = M68KMAKE_GET_OPER_AY_32; + uint* r_dst = &DX; + + *r_dst = res; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, ai, d) +{ + uint res = DY; + uint ea = EA_AX_AI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, ai, a) +{ + uint res = AY; + uint ea = EA_AX_AI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, ai, .) +{ + uint res = M68KMAKE_GET_OPER_AY_32; + uint ea = EA_AX_AI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, pi, d) +{ + uint res = DY; + uint ea = EA_AX_PI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, pi, a) +{ + uint res = AY; + uint ea = EA_AX_PI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, pi, .) +{ + uint res = M68KMAKE_GET_OPER_AY_32; + uint ea = EA_AX_PI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, pd, d) +{ + uint res = DY; + uint ea = EA_AX_PD_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, pd, a) +{ + uint res = AY; + uint ea = EA_AX_PD_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, pd, .) +{ + uint res = M68KMAKE_GET_OPER_AY_32; + uint ea = EA_AX_PD_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, di, d) +{ + uint res = DY; + uint ea = EA_AX_DI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, di, a) +{ + uint res = AY; + uint ea = EA_AX_DI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, di, .) +{ + uint res = M68KMAKE_GET_OPER_AY_32; + uint ea = EA_AX_DI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, ix, d) +{ + uint res = DY; + uint ea = EA_AX_IX_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, ix, a) +{ + uint res = AY; + uint ea = EA_AX_IX_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, ix, .) +{ + uint res = M68KMAKE_GET_OPER_AY_32; + uint ea = EA_AX_IX_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, aw, d) +{ + uint res = DY; + uint ea = EA_AW_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, aw, a) +{ + uint res = AY; + uint ea = EA_AW_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, aw, .) +{ + uint res = M68KMAKE_GET_OPER_AY_32; + uint ea = EA_AW_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, al, d) +{ + uint res = DY; + uint ea = EA_AL_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, al, a) +{ + uint res = AY; + uint ea = EA_AL_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, al, .) +{ + uint res = M68KMAKE_GET_OPER_AY_32; + uint ea = EA_AL_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(movea, 16, ., d) +{ + AX = MAKE_INT_16(DY); +} + + +M68KMAKE_OP(movea, 16, ., a) +{ + AX = MAKE_INT_16(AY); +} + + +M68KMAKE_OP(movea, 16, ., .) +{ + AX = MAKE_INT_16(M68KMAKE_GET_OPER_AY_16); +} + + +M68KMAKE_OP(movea, 32, ., d) +{ + AX = DY; +} + + +M68KMAKE_OP(movea, 32, ., a) +{ + AX = AY; +} + + +M68KMAKE_OP(movea, 32, ., .) +{ + AX = M68KMAKE_GET_OPER_AY_32; +} + + +M68KMAKE_OP(move, 16, frc, d) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + DY = MASK_OUT_BELOW_16(DY) | m68ki_get_ccr(); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(move, 16, frc, .) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + m68ki_write_16(M68KMAKE_GET_EA_AY_16, m68ki_get_ccr()); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(move, 16, toc, d) +{ + m68ki_set_ccr(DY); +} + + +M68KMAKE_OP(move, 16, toc, .) +{ + m68ki_set_ccr(M68KMAKE_GET_OPER_AY_16); +} + + +M68KMAKE_OP(move, 16, frs, d) +{ + if(CPU_TYPE_IS_000(CPU_TYPE) || FLAG_S) /* NS990408 */ + { + DY = MASK_OUT_BELOW_16(DY) | m68ki_get_sr(); + return; + } + m68ki_exception_privilege_violation(); +} + + +M68KMAKE_OP(move, 16, frs, .) +{ + if(CPU_TYPE_IS_000(CPU_TYPE) || FLAG_S) /* NS990408 */ + { + uint ea = M68KMAKE_GET_EA_AY_16; + m68ki_write_16(ea, m68ki_get_sr()); + return; + } + m68ki_exception_privilege_violation(); +} + + +M68KMAKE_OP(move, 16, tos, d) +{ + if(FLAG_S) + { + m68ki_set_sr(DY); + return; + } + m68ki_exception_privilege_violation(); +} + + +M68KMAKE_OP(move, 16, tos, .) +{ + if(FLAG_S) + { + uint new_sr = M68KMAKE_GET_OPER_AY_16; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr(new_sr); + return; + } + m68ki_exception_privilege_violation(); +} + + +M68KMAKE_OP(move, 32, fru, .) +{ + if(FLAG_S) + { + AY = REG_USP; + return; + } + m68ki_exception_privilege_violation(); +} + + +M68KMAKE_OP(move, 32, tou, .) +{ + if(FLAG_S) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + REG_USP = AY; + return; + } + m68ki_exception_privilege_violation(); +} + + +M68KMAKE_OP(movec, 32, cr, .) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + switch (word2 & 0xfff) + { + case 0x000: /* SFC */ + REG_DA[(word2 >> 12) & 15] = REG_SFC; + return; + case 0x001: /* DFC */ + REG_DA[(word2 >> 12) & 15] = REG_DFC; + return; + case 0x002: /* CACR */ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + REG_DA[(word2 >> 12) & 15] = REG_CACR; + return; + } + return; + case 0x800: /* USP */ + REG_DA[(word2 >> 12) & 15] = REG_USP; + return; + case 0x801: /* VBR */ + REG_DA[(word2 >> 12) & 15] = REG_VBR; + return; + case 0x802: /* CAAR */ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + REG_DA[(word2 >> 12) & 15] = REG_CAAR; + return; + } + m68ki_exception_illegal(); + break; + case 0x803: /* MSP */ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + REG_DA[(word2 >> 12) & 15] = FLAG_M ? REG_SP : REG_MSP; + return; + } + m68ki_exception_illegal(); + return; + case 0x804: /* ISP */ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + REG_DA[(word2 >> 12) & 15] = FLAG_M ? REG_ISP : REG_SP; + return; + } + m68ki_exception_illegal(); + return; + case 0x003: /* TC */ + if(CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x004: /* ITT0 */ + if(CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x005: /* ITT1 */ + if(CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x006: /* DTT0 */ + if(CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x007: /* DTT1 */ + if(CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x805: /* MMUSR */ + if(CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x806: /* URP */ + if(CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x807: /* SRP */ + if(CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + default: + m68ki_exception_illegal(); + return; + } + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(movec, 32, rc, .) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + switch (word2 & 0xfff) + { + case 0x000: /* SFC */ + REG_SFC = REG_DA[(word2 >> 12) & 15] & 7; + return; + case 0x001: /* DFC */ + REG_DFC = REG_DA[(word2 >> 12) & 15] & 7; + return; + case 0x002: /* CACR */ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + REG_CACR = REG_DA[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(); + return; + case 0x800: /* USP */ + REG_USP = REG_DA[(word2 >> 12) & 15]; + return; + case 0x801: /* VBR */ + REG_VBR = REG_DA[(word2 >> 12) & 15]; + return; + case 0x802: /* CAAR */ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + REG_CAAR = REG_DA[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(); + return; + case 0x803: /* MSP */ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + /* we are in supervisor mode so just check for M flag */ + if(!FLAG_M) + { + REG_MSP = REG_DA[(word2 >> 12) & 15]; + return; + } + REG_SP = REG_DA[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(); + return; + case 0x804: /* ISP */ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(!FLAG_M) + { + REG_SP = REG_DA[(word2 >> 12) & 15]; + return; + } + REG_ISP = REG_DA[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(); + return; + case 0x003: /* TC */ + if (CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x004: /* ITT0 */ + if (CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x005: /* ITT1 */ + if (CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x006: /* DTT0 */ + if (CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x007: /* DTT1 */ + if (CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x805: /* MMUSR */ + if (CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x806: /* URP */ + if (CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x807: /* SRP */ + if (CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + default: + m68ki_exception_illegal(); + return; + } + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(movem, 16, re, pd) +{ + uint i = 0; + uint register_list = OPER_I_16(); + uint ea = AY; + uint count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + ea -= 2; + m68ki_write_16(ea, MASK_OUT_ABOVE_16(REG_DA[15-i])); + count++; + } + AY = ea; + + USE_CYCLES(count<> 8)); + m68ki_write_8(ea += 2, MASK_OUT_ABOVE_8(src)); +} + + +M68KMAKE_OP(movep, 32, re, .) +{ + uint ea = EA_AY_DI_32(); + uint src = DX; + + m68ki_write_8(ea, MASK_OUT_ABOVE_8(src >> 24)); + m68ki_write_8(ea += 2, MASK_OUT_ABOVE_8(src >> 16)); + m68ki_write_8(ea += 2, MASK_OUT_ABOVE_8(src >> 8)); + m68ki_write_8(ea += 2, MASK_OUT_ABOVE_8(src)); +} + + +M68KMAKE_OP(movep, 16, er, .) +{ + uint ea = EA_AY_DI_16(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | ((m68ki_read_8(ea) << 8) + m68ki_read_8(ea + 2)); +} + + +M68KMAKE_OP(movep, 32, er, .) +{ + uint ea = EA_AY_DI_32(); + + DX = (m68ki_read_8(ea) << 24) + (m68ki_read_8(ea + 2) << 16) + + (m68ki_read_8(ea + 4) << 8) + m68ki_read_8(ea + 6); +} + + +M68KMAKE_OP(moves, 8, ., .) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = M68KMAKE_GET_EA_AY_8; + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_8_fc(ea, REG_DFC, MASK_OUT_ABOVE_8(REG_DA[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A[(word2 >> 12) & 7] = MAKE_INT_8(m68ki_read_8_fc(ea, REG_SFC)); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to data register */ + REG_D[(word2 >> 12) & 7] = MASK_OUT_BELOW_8(REG_D[(word2 >> 12) & 7]) | m68ki_read_8_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(moves, 16, ., .) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = M68KMAKE_GET_EA_AY_16; + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_16_fc(ea, REG_DFC, MASK_OUT_ABOVE_16(REG_DA[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A[(word2 >> 12) & 7] = MAKE_INT_16(m68ki_read_16_fc(ea, REG_SFC)); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to data register */ + REG_D[(word2 >> 12) & 7] = MASK_OUT_BELOW_16(REG_D[(word2 >> 12) & 7]) | m68ki_read_16_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(moves, 32, ., .) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = M68KMAKE_GET_EA_AY_32; + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_32_fc(ea, REG_DFC, REG_DA[(word2 >> 12) & 15]); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to register */ + REG_DA[(word2 >> 12) & 15] = m68ki_read_32_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(moveq, 32, ., .) +{ + uint res = DX = MAKE_INT_8(MASK_OUT_ABOVE_8(REG_IR)); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move16, 32, ., .) +{ + UINT16 w2 = OPER_I_16(); + int ax = REG_IR & 7; + int ay = (w2 >> 12) & 7; + + m68ki_write_32(REG_A[ay], m68ki_read_32(REG_A[ax])); + m68ki_write_32(REG_A[ay]+4, m68ki_read_32(REG_A[ax]+4)); + m68ki_write_32(REG_A[ay]+8, m68ki_read_32(REG_A[ax]+8)); + m68ki_write_32(REG_A[ay]+12, m68ki_read_32(REG_A[ax]+12)); + + REG_A[ax] += 16; + REG_A[ay] += 16; +} + + +M68KMAKE_OP(muls, 16, ., d) +{ + uint* r_dst = &DX; + uint res = MASK_OUT_ABOVE_32(MAKE_INT_16(DY) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(muls, 16, ., .) +{ + uint* r_dst = &DX; + uint res = MASK_OUT_ABOVE_32(MAKE_INT_16(M68KMAKE_GET_OPER_AY_16) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(mulu, 16, ., d) +{ + uint* r_dst = &DX; + uint res = MASK_OUT_ABOVE_16(DY) * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(mulu, 16, ., .) +{ + uint* r_dst = &DX; + uint res = M68KMAKE_GET_OPER_AY_16 * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(mull, 32, ., d) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 src = DY; + uint64 dst = REG_D[(word2 >> 12) & 7]; + uint64 res; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (sint64)((sint32)src) * (sint64)((sint32)dst); + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = ((sint64)res != (sint32)res)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = (res > 0xffffffff)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint src = DY; + uint dst = REG_D[(word2 >> 12) & 7]; + uint neg = GET_MSB_32(src ^ dst); + uint src1; + uint src2; + uint dst1; + uint dst2; + uint r1; + uint r2; + uint r3; + uint r4; + uint lo; + uint hi; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + if(GET_MSB_32(src)) + src = (uint)MASK_OUT_ABOVE_32(-(sint)src); + if(GET_MSB_32(dst)) + dst = (uint)MASK_OUT_ABOVE_32(-(sint)dst); + } + + src1 = MASK_OUT_ABOVE_16(src); + src2 = src>>16; + dst1 = MASK_OUT_ABOVE_16(dst); + dst2 = dst>>16; + + + r1 = src1 * dst1; + r2 = src1 * dst2; + r3 = src2 * dst1; + r4 = src2 * dst2; + + lo = r1 + (MASK_OUT_ABOVE_16(r2)<<16) + (MASK_OUT_ABOVE_16(r3)<<16); + hi = r4 + (r2>>16) + (r3>>16) + (((r1>>16) + MASK_OUT_ABOVE_16(r2) + MASK_OUT_ABOVE_16(r3)) >> 16); + + if(BIT_B(word2) && neg) + { + hi = (uint)MASK_OUT_ABOVE_32((-(sint)hi) - (lo != 0)); + lo = (uint)MASK_OUT_ABOVE_32(-(sint)lo); + } + + if(BIT_A(word2)) + { + REG_D[word2 & 7] = hi; + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(hi); + FLAG_Z = hi | lo; + FLAG_V = VFLAG_CLEAR; + return; + } + + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(lo); + FLAG_Z = lo; + if(BIT_B(word2)) + FLAG_V = (!((GET_MSB_32(lo) && hi == 0xffffffff) || (!GET_MSB_32(lo) && !hi)))<<7; + else + FLAG_V = (hi != 0) << 7; + return; + } + m68ki_exception_illegal(); + +#endif +} + + +M68KMAKE_OP(mull, 32, ., .) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 src = M68KMAKE_GET_OPER_AY_32; + uint64 dst = REG_D[(word2 >> 12) & 7]; + uint64 res; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (sint64)((sint32)src) * (sint64)((sint32)dst); + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = ((sint64)res != (sint32)res)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = (res > 0xffffffff)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint src = M68KMAKE_GET_OPER_AY_32; + uint dst = REG_D[(word2 >> 12) & 7]; + uint neg = GET_MSB_32(src ^ dst); + uint src1; + uint src2; + uint dst1; + uint dst2; + uint r1; + uint r2; + uint r3; + uint r4; + uint lo; + uint hi; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + if(GET_MSB_32(src)) + src = (uint)MASK_OUT_ABOVE_32(-(sint)src); + if(GET_MSB_32(dst)) + dst = (uint)MASK_OUT_ABOVE_32(-(sint)dst); + } + + src1 = MASK_OUT_ABOVE_16(src); + src2 = src>>16; + dst1 = MASK_OUT_ABOVE_16(dst); + dst2 = dst>>16; + + + r1 = src1 * dst1; + r2 = src1 * dst2; + r3 = src2 * dst1; + r4 = src2 * dst2; + + lo = r1 + (MASK_OUT_ABOVE_16(r2)<<16) + (MASK_OUT_ABOVE_16(r3)<<16); + hi = r4 + (r2>>16) + (r3>>16) + (((r1>>16) + MASK_OUT_ABOVE_16(r2) + MASK_OUT_ABOVE_16(r3)) >> 16); + + if(BIT_B(word2) && neg) + { + hi = (uint)MASK_OUT_ABOVE_32((-(sint)hi) - (lo != 0)); + lo = (uint)MASK_OUT_ABOVE_32(-(sint)lo); + } + + if(BIT_A(word2)) + { + REG_D[word2 & 7] = hi; + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(hi); + FLAG_Z = hi | lo; + FLAG_V = VFLAG_CLEAR; + return; + } + + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(lo); + FLAG_Z = lo; + if(BIT_B(word2)) + FLAG_V = (!((GET_MSB_32(lo) && hi == 0xffffffff) || (!GET_MSB_32(lo) && !hi)))<<7; + else + FLAG_V = (hi != 0) << 7; + return; + } + m68ki_exception_illegal(); + +#endif +} + + +M68KMAKE_OP(nbcd, 8, ., d) +{ + uint* r_dst = &DY; + uint dst = *r_dst; + uint res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1()); + + if(res != 0x9a) + { + FLAG_V = ~res; /* Undefined V behavior */ + + if((res & 0x0f) == 0xa) + res = (res & 0xf0) + 0x10; + + res = MASK_OUT_ABOVE_8(res); + + FLAG_V &= res; /* Undefined V behavior part II */ + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + FLAG_Z |= res; + FLAG_C = CFLAG_SET; + FLAG_X = XFLAG_SET; + } + else + { + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_X = XFLAG_CLEAR; + } + FLAG_N = NFLAG_8(res); /* Undefined N behavior */ +} + + +M68KMAKE_OP(nbcd, 8, ., .) +{ + uint ea = M68KMAKE_GET_EA_AY_8; + uint dst = m68ki_read_8(ea); + uint res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1()); + + if(res != 0x9a) + { + FLAG_V = ~res; /* Undefined V behavior */ + + if((res & 0x0f) == 0xa) + res = (res & 0xf0) + 0x10; + + res = MASK_OUT_ABOVE_8(res); + + FLAG_V &= res; /* Undefined V behavior part II */ + + m68ki_write_8(ea, MASK_OUT_ABOVE_8(res)); + + FLAG_Z |= res; + FLAG_C = CFLAG_SET; + FLAG_X = XFLAG_SET; + } + else + { + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_X = XFLAG_CLEAR; + } + FLAG_N = NFLAG_8(res); /* Undefined N behavior */ +} + + +M68KMAKE_OP(neg, 8, ., d) +{ + uint* r_dst = &DY; + uint res = 0 - MASK_OUT_ABOVE_8(*r_dst); + + FLAG_N = NFLAG_8(res); + FLAG_C = FLAG_X = CFLAG_8(res); + FLAG_V = *r_dst & res; + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +M68KMAKE_OP(neg, 8, ., .) +{ + uint ea = M68KMAKE_GET_EA_AY_8; + uint src = m68ki_read_8(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_8(res); + FLAG_C = FLAG_X = CFLAG_8(res); + FLAG_V = src & res; + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +M68KMAKE_OP(neg, 16, ., d) +{ + uint* r_dst = &DY; + uint res = 0 - MASK_OUT_ABOVE_16(*r_dst); + + FLAG_N = NFLAG_16(res); + FLAG_C = FLAG_X = CFLAG_16(res); + FLAG_V = (*r_dst & res)>>8; + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +M68KMAKE_OP(neg, 16, ., .) +{ + uint ea = M68KMAKE_GET_EA_AY_16; + uint src = m68ki_read_16(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_16(res); + FLAG_C = FLAG_X = CFLAG_16(res); + FLAG_V = (src & res)>>8; + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +M68KMAKE_OP(neg, 32, ., d) +{ + uint* r_dst = &DY; + uint res = 0 - *r_dst; + + FLAG_N = NFLAG_32(res); + FLAG_C = FLAG_X = CFLAG_SUB_32(*r_dst, 0, res); + FLAG_V = (*r_dst & res)>>24; + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +M68KMAKE_OP(neg, 32, ., .) +{ + uint ea = M68KMAKE_GET_EA_AY_32; + uint src = m68ki_read_32(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_32(res); + FLAG_C = FLAG_X = CFLAG_SUB_32(src, 0, res); + FLAG_V = (src & res)>>24; + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +M68KMAKE_OP(negx, 8, ., d) +{ + uint* r_dst = &DY; + uint res = 0 - MASK_OUT_ABOVE_8(*r_dst) - XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = *r_dst & res; + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; +} + + +M68KMAKE_OP(negx, 8, ., .) +{ + uint ea = M68KMAKE_GET_EA_AY_8; + uint src = m68ki_read_8(ea); + uint res = 0 - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = src & res; + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +M68KMAKE_OP(negx, 16, ., d) +{ + uint* r_dst = &DY; + uint res = 0 - MASK_OUT_ABOVE_16(*r_dst) - XFLAG_AS_1(); + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = (*r_dst & res)>>8; + + res = MASK_OUT_ABOVE_16(res); + FLAG_Z |= res; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; +} + + +M68KMAKE_OP(negx, 16, ., .) +{ + uint ea = M68KMAKE_GET_EA_AY_16; + uint src = m68ki_read_16(ea); + uint res = 0 - MASK_OUT_ABOVE_16(src) - XFLAG_AS_1(); + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = (src & res)>>8; + + res = MASK_OUT_ABOVE_16(res); + FLAG_Z |= res; + + m68ki_write_16(ea, res); +} + + +M68KMAKE_OP(negx, 32, ., d) +{ + uint* r_dst = &DY; + uint res = 0 - MASK_OUT_ABOVE_32(*r_dst) - XFLAG_AS_1(); + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(*r_dst, 0, res); + FLAG_V = (*r_dst & res)>>24; + + res = MASK_OUT_ABOVE_32(res); + FLAG_Z |= res; + + *r_dst = res; +} + + +M68KMAKE_OP(negx, 32, ., .) +{ + uint ea = M68KMAKE_GET_EA_AY_32; + uint src = m68ki_read_32(ea); + uint res = 0 - MASK_OUT_ABOVE_32(src) - XFLAG_AS_1(); + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, 0, res); + FLAG_V = (src & res)>>24; + + res = MASK_OUT_ABOVE_32(res); + FLAG_Z |= res; + + m68ki_write_32(ea, res); +} + + +M68KMAKE_OP(nop, 0, ., .) +{ + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ +} + + +M68KMAKE_OP(not, 8, ., d) +{ + uint* r_dst = &DY; + uint res = MASK_OUT_ABOVE_8(~*r_dst); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(not, 8, ., .) +{ + uint ea = M68KMAKE_GET_EA_AY_8; + uint res = MASK_OUT_ABOVE_8(~m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(not, 16, ., d) +{ + uint* r_dst = &DY; + uint res = MASK_OUT_ABOVE_16(~*r_dst); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(not, 16, ., .) +{ + uint ea = M68KMAKE_GET_EA_AY_16; + uint res = MASK_OUT_ABOVE_16(~m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(not, 32, ., d) +{ + uint* r_dst = &DY; + uint res = *r_dst = MASK_OUT_ABOVE_32(~*r_dst); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(not, 32, ., .) +{ + uint ea = M68KMAKE_GET_EA_AY_32; + uint res = MASK_OUT_ABOVE_32(~m68ki_read_32(ea)); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(or, 8, er, d) +{ + uint res = MASK_OUT_ABOVE_8((DX |= MASK_OUT_ABOVE_8(DY))); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(or, 8, er, .) +{ + uint res = MASK_OUT_ABOVE_8((DX |= M68KMAKE_GET_OPER_AY_8)); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(or, 16, er, d) +{ + uint res = MASK_OUT_ABOVE_16((DX |= MASK_OUT_ABOVE_16(DY))); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(or, 16, er, .) +{ + uint res = MASK_OUT_ABOVE_16((DX |= M68KMAKE_GET_OPER_AY_16)); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(or, 32, er, d) +{ + uint res = DX |= DY; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(or, 32, er, .) +{ + uint res = DX |= M68KMAKE_GET_OPER_AY_32; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(or, 8, re, .) +{ + uint ea = M68KMAKE_GET_EA_AY_8; + uint res = MASK_OUT_ABOVE_8(DX | m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(or, 16, re, .) +{ + uint ea = M68KMAKE_GET_EA_AY_16; + uint res = MASK_OUT_ABOVE_16(DX | m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(or, 32, re, .) +{ + uint ea = M68KMAKE_GET_EA_AY_32; + uint res = DX | m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(ori, 8, ., d) +{ + uint res = MASK_OUT_ABOVE_8((DY |= OPER_I_8())); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(ori, 8, ., .) +{ + uint src = OPER_I_8(); + uint ea = M68KMAKE_GET_EA_AY_8; + uint res = MASK_OUT_ABOVE_8(src | m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(ori, 16, ., d) +{ + uint res = MASK_OUT_ABOVE_16(DY |= OPER_I_16()); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(ori, 16, ., .) +{ + uint src = OPER_I_16(); + uint ea = M68KMAKE_GET_EA_AY_16; + uint res = MASK_OUT_ABOVE_16(src | m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(ori, 32, ., d) +{ + uint res = DY |= OPER_I_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(ori, 32, ., .) +{ + uint src = OPER_I_32(); + uint ea = M68KMAKE_GET_EA_AY_32; + uint res = src | m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(ori, 16, toc, .) +{ + m68ki_set_ccr(m68ki_get_ccr() | OPER_I_16()); +} + + +M68KMAKE_OP(ori, 16, tos, .) +{ + if(FLAG_S) + { + uint src = OPER_I_16(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr(m68ki_get_sr() | src); + return; + } + m68ki_exception_privilege_violation(); +} + + +M68KMAKE_OP(pack, 16, rr, .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + /* Note: DX and DY are reversed in Motorola's docs */ + uint src = DY + OPER_I_16(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | ((src >> 4) & 0x00f0) | (src & 0x000f); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(pack, 16, mm, ax7) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + /* Note: AX and AY are reversed in Motorola's docs */ + uint ea_src = EA_AY_PD_8(); + uint src = m68ki_read_8(ea_src); + ea_src = EA_AY_PD_8(); + src = ((src << 8) | m68ki_read_8(ea_src)) + OPER_I_16(); + + m68ki_write_8(EA_A7_PD_8(), ((src >> 4) & 0x00f0) | (src & 0x000f)); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(pack, 16, mm, ay7) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + /* Note: AX and AY are reversed in Motorola's docs */ + uint ea_src = EA_A7_PD_8(); + uint src = m68ki_read_8(ea_src); + ea_src = EA_A7_PD_8(); + src = ((src << 8) | m68ki_read_8(ea_src)) + OPER_I_16(); + + m68ki_write_8(EA_AX_PD_8(), ((src >> 4) & 0x00f0) | (src & 0x000f)); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(pack, 16, mm, axy7) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint ea_src = EA_A7_PD_8(); + uint src = m68ki_read_8(ea_src); + ea_src = EA_A7_PD_8(); + src = ((src << 8) | m68ki_read_8(ea_src)) + OPER_I_16(); + + m68ki_write_8(EA_A7_PD_8(), ((src >> 4) & 0x00f0) | (src & 0x000f)); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(pack, 16, mm, .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + /* Note: AX and AY are reversed in Motorola's docs */ + uint ea_src = EA_AY_PD_8(); + uint src = m68ki_read_8(ea_src); + ea_src = EA_AY_PD_8(); + src = ((src << 8) | m68ki_read_8(ea_src)) + OPER_I_16(); + + m68ki_write_8(EA_AX_PD_8(), ((src >> 4) & 0x00f0) | (src & 0x000f)); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(pea, 32, ., .) +{ + uint ea = M68KMAKE_GET_EA_AY_32; + + m68ki_push_32(ea); +} + + +M68KMAKE_OP(pflush, 32, ., .) +{ + if(CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + // Nothing to do, unless address translation cache is emulated + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(reset, 0, ., .) +{ + if(FLAG_S) + { + m68ki_output_reset(); /* auto-disable (see m68kcpu.h) */ + USE_CYCLES(CYC_RESET); + return; + } + m68ki_exception_privilege_violation(); +} + + +M68KMAKE_OP(ror, 8, s, .) +{ + uint* r_dst = &DY; + uint orig_shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint shift = orig_shift & 7; + uint src = MASK_OUT_ABOVE_8(*r_dst); + uint res = ROR_8(src, shift); + + if(orig_shift != 0) + USE_CYCLES(orig_shift<> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_16(*r_dst); + uint res = ROR_16(src, shift); + + if(shift != 0) + USE_CYCLES(shift<> 9) - 1) & 7) + 1; + uint64 src = *r_dst; + uint res = ROR_32(src, shift); + + if(shift != 0) + USE_CYCLES(shift<> ((shift - 1) & 15)) << 8; + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_16(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(ror, 32, r, .) +{ + uint* r_dst = &DY; + uint orig_shift = DX & 0x3f; + uint shift = orig_shift & 31; + uint64 src = *r_dst; + uint res = ROR_32(src, shift); + + if(orig_shift != 0) + { + USE_CYCLES(orig_shift<> ((shift - 1) & 31)) << 8; + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_32(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(ror, 16, ., .) +{ + uint ea = M68KMAKE_GET_EA_AY_16; + uint src = m68ki_read_16(ea); + uint res = ROR_16(src, 1); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = src << 8; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(rol, 8, s, .) +{ + uint* r_dst = &DY; + uint orig_shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint shift = orig_shift & 7; + uint src = MASK_OUT_ABOVE_8(*r_dst); + uint res = ROL_8(src, shift); + + if(orig_shift != 0) + USE_CYCLES(orig_shift<> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_16(*r_dst); + uint res = ROL_16(src, shift); + + if(shift != 0) + USE_CYCLES(shift<> (8-shift); + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(rol, 32, s, .) +{ + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint64 src = *r_dst; + uint res = ROL_32(src, shift); + + if(shift != 0) + USE_CYCLES(shift<> (24-shift); + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(rol, 8, r, .) +{ + uint* r_dst = &DY; + uint orig_shift = DX & 0x3f; + uint shift = orig_shift & 7; + uint src = MASK_OUT_ABOVE_8(*r_dst); + uint res = ROL_8(src, shift); + + if(orig_shift != 0) + { + USE_CYCLES(orig_shift<> 8; + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + FLAG_C = (src & 1)<<8; + FLAG_N = NFLAG_16(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_16(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(rol, 32, r, .) +{ + uint* r_dst = &DY; + uint orig_shift = DX & 0x3f; + uint shift = orig_shift & 31; + uint64 src = *r_dst; + uint res = ROL_32(src, shift); + + if(orig_shift != 0) + { + USE_CYCLES(orig_shift<> (32 - shift)) << 8; + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_32(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(rol, 16, ., .) +{ + uint ea = M68KMAKE_GET_EA_AY_16; + uint src = m68ki_read_16(ea); + uint res = MASK_OUT_ABOVE_16(ROL_16(src, 1)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = src >> 7; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(roxr, 8, s, .) +{ + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_8(*r_dst); + uint res = ROR_9(src | (XFLAG_AS_1() << 8), shift); + + if(shift != 0) + USE_CYCLES(shift<> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_16(*r_dst); + uint res = ROR_17(src | (XFLAG_AS_1() << 16), shift); + + if(shift != 0) + USE_CYCLES(shift<> 8; + res = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(roxr, 32, s, .) +{ +#if M68K_USE_64_BIT + + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint64 src = *r_dst; + uint64 res = src | (((uint64)XFLAG_AS_1()) << 32); + + if(shift != 0) + USE_CYCLES(shift<> 24; + res = MASK_OUT_ABOVE_32(res); + + *r_dst = res; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + +#else + + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint src = *r_dst; + uint res = MASK_OUT_ABOVE_32((ROR_33(src, shift) & ~(1 << (32 - shift))) | (XFLAG_AS_1() << (32 - shift))); + uint new_x_flag = src & (1 << (shift - 1)); + + if(shift != 0) + USE_CYCLES(shift<> 8; + res = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = FLAG_X; + FLAG_N = NFLAG_16(*r_dst); + FLAG_Z = MASK_OUT_ABOVE_16(*r_dst); + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(roxr, 32, r, .) +{ +#if M68K_USE_64_BIT + + uint* r_dst = &DY; + uint orig_shift = DX & 0x3f; + + if(orig_shift != 0) + { + uint shift = orig_shift % 33; + uint64 src = *r_dst; + uint64 res = src | (((uint64)XFLAG_AS_1()) << 32); + + res = ROR_33_64(res, shift); + + USE_CYCLES(orig_shift<> 24; + res = MASK_OUT_ABOVE_32(res); + + *r_dst = res; + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = FLAG_X; + FLAG_N = NFLAG_32(*r_dst); + FLAG_Z = *r_dst; + FLAG_V = VFLAG_CLEAR; + +#else + + uint* r_dst = &DY; + uint orig_shift = DX & 0x3f; + uint shift = orig_shift % 33; + uint src = *r_dst; + uint res = MASK_OUT_ABOVE_32((ROR_33(src, shift) & ~(1 << (32 - shift))) | (XFLAG_AS_1() << (32 - shift))); + uint new_x_flag = src & (1 << (shift - 1)); + + if(orig_shift != 0) + USE_CYCLES(orig_shift<> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(roxl, 8, s, .) +{ + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_8(*r_dst); + uint res = ROL_9(src | (XFLAG_AS_1() << 8), shift); + + if(shift != 0) + USE_CYCLES(shift<> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_16(*r_dst); + uint res = ROL_17(src | (XFLAG_AS_1() << 16), shift); + + if(shift != 0) + USE_CYCLES(shift<> 8; + res = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(roxl, 32, s, .) +{ +#if M68K_USE_64_BIT + + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint64 src = *r_dst; + uint64 res = src | (((uint64)XFLAG_AS_1()) << 32); + + if(shift != 0) + USE_CYCLES(shift<> 24; + res = MASK_OUT_ABOVE_32(res); + + *r_dst = res; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + +#else + + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint src = *r_dst; + uint res = MASK_OUT_ABOVE_32((ROL_33(src, shift) & ~(1 << (shift - 1))) | (XFLAG_AS_1() << (shift - 1))); + uint new_x_flag = src & (1 << (32 - shift)); + + if(shift != 0) + USE_CYCLES(shift<> 8; + res = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = FLAG_X; + FLAG_N = NFLAG_16(*r_dst); + FLAG_Z = MASK_OUT_ABOVE_16(*r_dst); + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(roxl, 32, r, .) +{ +#if M68K_USE_64_BIT + + uint* r_dst = &DY; + uint orig_shift = DX & 0x3f; + + if(orig_shift != 0) + { + uint shift = orig_shift % 33; + uint64 src = *r_dst; + uint64 res = src | (((uint64)XFLAG_AS_1()) << 32); + + res = ROL_33_64(res, shift); + + USE_CYCLES(orig_shift<> 24; + res = MASK_OUT_ABOVE_32(res); + + *r_dst = res; + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = FLAG_X; + FLAG_N = NFLAG_32(*r_dst); + FLAG_Z = *r_dst; + FLAG_V = VFLAG_CLEAR; + +#else + + uint* r_dst = &DY; + uint orig_shift = DX & 0x3f; + uint shift = orig_shift % 33; + uint src = *r_dst; + uint res = MASK_OUT_ABOVE_32((ROL_33(src, shift) & ~(1 << (shift - 1))) | (XFLAG_AS_1() << (shift - 1))); + uint new_x_flag = src & (1 << (32 - shift)); + + if(orig_shift != 0) + USE_CYCLES(orig_shift<> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(rtd, 32, ., .) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + uint new_pc = m68ki_pull_32(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + REG_A[7] = MASK_OUT_ABOVE_32(REG_A[7] + MAKE_INT_16(OPER_I_16())); + m68ki_jump(new_pc); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(rte, 32, ., .) +{ + if(FLAG_S) + { + uint new_sr; + uint new_pc; + uint format_word; + + m68ki_rte_callback(); /* auto-disable (see m68kcpu.h) */ + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + + if(CPU_TYPE_IS_000(CPU_TYPE)) + { + new_sr = m68ki_pull_16(); + new_pc = m68ki_pull_32(); + m68ki_jump(new_pc); + m68ki_set_sr(new_sr); + + CPU_INSTR_MODE = INSTRUCTION_YES; + CPU_RUN_MODE = RUN_MODE_NORMAL; + + return; + } + + if(CPU_TYPE_IS_010(CPU_TYPE)) + { + format_word = m68ki_read_16(REG_A[7]+6) >> 12; + if(format_word == 0) + { + new_sr = m68ki_pull_16(); + new_pc = m68ki_pull_32(); + m68ki_fake_pull_16(); /* format word */ + m68ki_jump(new_pc); + m68ki_set_sr(new_sr); + CPU_INSTR_MODE = INSTRUCTION_YES; + CPU_RUN_MODE = RUN_MODE_NORMAL; + return; + } + CPU_INSTR_MODE = INSTRUCTION_YES; + CPU_RUN_MODE = RUN_MODE_NORMAL; + /* Not handling bus fault (9) */ + m68ki_exception_format_error(); + return; + } + + /* Otherwise it's 020 */ +rte_loop: + format_word = m68ki_read_16(REG_A[7]+6) >> 12; + switch(format_word) + { + case 0: /* Normal */ + new_sr = m68ki_pull_16(); + new_pc = m68ki_pull_32(); + m68ki_fake_pull_16(); /* format word */ + m68ki_jump(new_pc); + m68ki_set_sr(new_sr); + CPU_INSTR_MODE = INSTRUCTION_YES; + CPU_RUN_MODE = RUN_MODE_NORMAL; + return; + case 1: /* Throwaway */ + new_sr = m68ki_pull_16(); + m68ki_fake_pull_32(); /* program counter */ + m68ki_fake_pull_16(); /* format word */ + m68ki_set_sr_noint(new_sr); + goto rte_loop; + case 2: /* Trap */ + new_sr = m68ki_pull_16(); + new_pc = m68ki_pull_32(); + m68ki_fake_pull_16(); /* format word */ + m68ki_fake_pull_32(); /* address */ + m68ki_jump(new_pc); + m68ki_set_sr(new_sr); + CPU_INSTR_MODE = INSTRUCTION_YES; + CPU_RUN_MODE = RUN_MODE_NORMAL; + return; + } + /* Not handling long or short bus fault */ + CPU_INSTR_MODE = INSTRUCTION_YES; + CPU_RUN_MODE = RUN_MODE_NORMAL; + m68ki_exception_format_error(); + return; + } + m68ki_exception_privilege_violation(); +} + + +M68KMAKE_OP(rtm, 32, ., .) +{ + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", + m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, + m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(rtr, 32, ., .) +{ + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_set_ccr(m68ki_pull_16()); + m68ki_jump(m68ki_pull_32()); +} + + +M68KMAKE_OP(rts, 32, ., .) +{ + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_jump(m68ki_pull_32()); +} + + +M68KMAKE_OP(sbcd, 8, rr, .) +{ + uint* r_dst = &DX; + uint src = DY; + uint dst = *r_dst; + uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(); + +// FLAG_V = ~res; /* Undefined V behavior */ + FLAG_V = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to assume cleared. */ + + if(res > 9) + res -= 6; + res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); + if(res > 0x99) + { + res += 0xa0; + FLAG_X = FLAG_C = CFLAG_SET; + FLAG_N = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */ + } + else + FLAG_N = FLAG_X = FLAG_C = 0; + + res = MASK_OUT_ABOVE_8(res); + +// FLAG_V &= res; /* Undefined V behavior part II */ +// FLAG_N = NFLAG_8(res); /* Undefined N behavior */ + FLAG_Z |= res; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; +} + + +M68KMAKE_OP(sbcd, 8, mm, ax7) +{ + uint src = OPER_AY_PD_8(); + uint ea = EA_A7_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(); + +// FLAG_V = ~res; /* Undefined V behavior */ + FLAG_V = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to return zero. */ + + if(res > 9) + res -= 6; + res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); + if(res > 0x99) + { + res += 0xa0; + FLAG_X = FLAG_C = CFLAG_SET; + FLAG_N = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */ + } + else + FLAG_N = FLAG_X = FLAG_C = 0; + + res = MASK_OUT_ABOVE_8(res); + +// FLAG_V &= res; /* Undefined V behavior part II */ +// FLAG_N = NFLAG_8(res); /* Undefined N behavior */ + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +M68KMAKE_OP(sbcd, 8, mm, ay7) +{ + uint src = OPER_A7_PD_8(); + uint ea = EA_AX_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(); + +// FLAG_V = ~res; /* Undefined V behavior */ + FLAG_V = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to return zero. */ + + if(res > 9) + res -= 6; + res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); + if(res > 0x99) + { + res += 0xa0; + FLAG_X = FLAG_C = CFLAG_SET; + FLAG_N = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */ + } + else + FLAG_N = FLAG_X = FLAG_C = 0; + + res = MASK_OUT_ABOVE_8(res); + +// FLAG_V &= res; /* Undefined V behavior part II */ +// FLAG_N = NFLAG_8(res); /* Undefined N behavior */ + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +M68KMAKE_OP(sbcd, 8, mm, axy7) +{ + uint src = OPER_A7_PD_8(); + uint ea = EA_A7_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(); + +// FLAG_V = ~res; /* Undefined V behavior */ + FLAG_V = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to return zero. */ + + if(res > 9) + res -= 6; + res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); + if(res > 0x99) + { + res += 0xa0; + FLAG_X = FLAG_C = CFLAG_SET; + FLAG_N = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */ + } + else + FLAG_N = FLAG_X = FLAG_C = 0; + + res = MASK_OUT_ABOVE_8(res); + +// FLAG_V &= res; /* Undefined V behavior part II */ +// FLAG_N = NFLAG_8(res); /* Undefined N behavior */ + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +M68KMAKE_OP(sbcd, 8, mm, .) +{ + uint src = OPER_AY_PD_8(); + uint ea = EA_AX_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(); + +// FLAG_V = ~res; /* Undefined V behavior */ + FLAG_V = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to return zero. */ + + if(res > 9) + res -= 6; + res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); + if(res > 0x99) + { + res += 0xa0; + FLAG_X = FLAG_C = CFLAG_SET; + FLAG_N = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */ + } + else + FLAG_N = FLAG_X = FLAG_C = 0; + + res = MASK_OUT_ABOVE_8(res); + +// FLAG_V &= res; /* Undefined V behavior part II */ +// FLAG_N = NFLAG_8(res); /* Undefined N behavior */ + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +M68KMAKE_OP(st, 8, ., d) +{ + DY |= 0xff; +} + + +M68KMAKE_OP(st, 8, ., .) +{ + m68ki_write_8(M68KMAKE_GET_EA_AY_8, 0xff); +} + + +M68KMAKE_OP(sf, 8, ., d) +{ + DY &= 0xffffff00; +} + + +M68KMAKE_OP(sf, 8, ., .) +{ + m68ki_write_8(M68KMAKE_GET_EA_AY_8, 0); +} + + +M68KMAKE_OP(scc, 8, ., d) +{ + if(M68KMAKE_CC) + { + DY |= 0xff; + USE_CYCLES(CYC_SCC_R_TRUE); + return; + } + DY &= 0xffffff00; +} + + +M68KMAKE_OP(scc, 8, ., .) +{ + m68ki_write_8(M68KMAKE_GET_EA_AY_8, M68KMAKE_CC ? 0xff : 0); +} + + +M68KMAKE_OP(stop, 0, ., .) +{ + if(FLAG_S) + { + uint new_sr = OPER_I_16(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + CPU_STOPPED |= STOP_LEVEL_STOP; + m68ki_set_sr(new_sr); + m68ki_remaining_cycles = 0; + return; + } + m68ki_exception_privilege_violation(); +} + + +M68KMAKE_OP(sub, 8, er, d) +{ + uint* r_dst = &DX; + uint src = MASK_OUT_ABOVE_8(DY); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +M68KMAKE_OP(sub, 8, er, .) +{ + uint* r_dst = &DX; + uint src = M68KMAKE_GET_OPER_AY_8; + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +M68KMAKE_OP(sub, 16, er, d) +{ + uint* r_dst = &DX; + uint src = MASK_OUT_ABOVE_16(DY); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +M68KMAKE_OP(sub, 16, er, a) +{ + uint* r_dst = &DX; + uint src = MASK_OUT_ABOVE_16(AY); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +M68KMAKE_OP(sub, 16, er, .) +{ + uint* r_dst = &DX; + uint src = M68KMAKE_GET_OPER_AY_16; + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +M68KMAKE_OP(sub, 32, er, d) +{ + uint* r_dst = &DX; + uint src = DY; + uint dst = *r_dst; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +M68KMAKE_OP(sub, 32, er, a) +{ + uint* r_dst = &DX; + uint src = AY; + uint dst = *r_dst; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +M68KMAKE_OP(sub, 32, er, .) +{ + uint* r_dst = &DX; + uint src = M68KMAKE_GET_OPER_AY_32; + uint dst = *r_dst; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +M68KMAKE_OP(sub, 8, re, .) +{ + uint ea = M68KMAKE_GET_EA_AY_8; + uint src = MASK_OUT_ABOVE_8(DX); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +M68KMAKE_OP(sub, 16, re, .) +{ + uint ea = M68KMAKE_GET_EA_AY_16; + uint src = MASK_OUT_ABOVE_16(DX); + uint dst = m68ki_read_16(ea); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16(ea, FLAG_Z); +} + + +M68KMAKE_OP(sub, 32, re, .) +{ + uint ea = M68KMAKE_GET_EA_AY_32; + uint src = DX; + uint dst = m68ki_read_32(ea); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32(ea, FLAG_Z); +} + + +M68KMAKE_OP(suba, 16, ., d) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - MAKE_INT_16(DY)); +} + + +M68KMAKE_OP(suba, 16, ., a) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - MAKE_INT_16(AY)); +} + + +M68KMAKE_OP(suba, 16, ., .) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - MAKE_INT_16(M68KMAKE_GET_OPER_AY_16)); +} + + +M68KMAKE_OP(suba, 32, ., d) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - DY); +} + + +M68KMAKE_OP(suba, 32, ., a) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - AY); +} + + +M68KMAKE_OP(suba, 32, ., .) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - M68KMAKE_GET_OPER_AY_32); +} + + +M68KMAKE_OP(subi, 8, ., d) +{ + uint* r_dst = &DY; + uint src = OPER_I_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +M68KMAKE_OP(subi, 8, ., .) +{ + uint src = OPER_I_8(); + uint ea = M68KMAKE_GET_EA_AY_8; + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +M68KMAKE_OP(subi, 16, ., d) +{ + uint* r_dst = &DY; + uint src = OPER_I_16(); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +M68KMAKE_OP(subi, 16, ., .) +{ + uint src = OPER_I_16(); + uint ea = M68KMAKE_GET_EA_AY_16; + uint dst = m68ki_read_16(ea); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16(ea, FLAG_Z); +} + + +M68KMAKE_OP(subi, 32, ., d) +{ + uint* r_dst = &DY; + uint src = OPER_I_32(); + uint dst = *r_dst; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + *r_dst = FLAG_Z; +} + + +M68KMAKE_OP(subi, 32, ., .) +{ + uint src = OPER_I_32(); + uint ea = M68KMAKE_GET_EA_AY_32; + uint dst = m68ki_read_32(ea); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32(ea, FLAG_Z); +} + + +M68KMAKE_OP(subq, 8, ., d) +{ + uint* r_dst = &DY; + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +M68KMAKE_OP(subq, 8, ., .) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = M68KMAKE_GET_EA_AY_8; + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +M68KMAKE_OP(subq, 16, ., d) +{ + uint* r_dst = &DY; + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +M68KMAKE_OP(subq, 16, ., a) +{ + uint* r_dst = &AY; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - ((((REG_IR >> 9) - 1) & 7) + 1)); +} + + +M68KMAKE_OP(subq, 16, ., .) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = M68KMAKE_GET_EA_AY_16; + uint dst = m68ki_read_16(ea); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16(ea, FLAG_Z); +} + + +M68KMAKE_OP(subq, 32, ., d) +{ + uint* r_dst = &DY; + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint dst = *r_dst; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + *r_dst = FLAG_Z; +} + + +M68KMAKE_OP(subq, 32, ., a) +{ + uint* r_dst = &AY; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - ((((REG_IR >> 9) - 1) & 7) + 1)); +} + + +M68KMAKE_OP(subq, 32, ., .) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = M68KMAKE_GET_EA_AY_32; + uint dst = m68ki_read_32(ea); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32(ea, FLAG_Z); +} + + +M68KMAKE_OP(subx, 8, rr, .) +{ + uint* r_dst = &DX; + uint src = MASK_OUT_ABOVE_8(DY); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = dst - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; +} + + +M68KMAKE_OP(subx, 16, rr, .) +{ + uint* r_dst = &DX; + uint src = MASK_OUT_ABOVE_16(DY); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = dst - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + res = MASK_OUT_ABOVE_16(res); + FLAG_Z |= res; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; +} + + +M68KMAKE_OP(subx, 32, rr, .) +{ + uint* r_dst = &DX; + uint src = DY; + uint dst = *r_dst; + uint res = dst - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + res = MASK_OUT_ABOVE_32(res); + FLAG_Z |= res; + + *r_dst = res; +} + + +M68KMAKE_OP(subx, 8, mm, ax7) +{ + uint src = OPER_AY_PD_8(); + uint ea = EA_A7_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +M68KMAKE_OP(subx, 8, mm, ay7) +{ + uint src = OPER_A7_PD_8(); + uint ea = EA_AX_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +M68KMAKE_OP(subx, 8, mm, axy7) +{ + uint src = OPER_A7_PD_8(); + uint ea = EA_A7_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +M68KMAKE_OP(subx, 8, mm, .) +{ + uint src = OPER_AY_PD_8(); + uint ea = EA_AX_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +M68KMAKE_OP(subx, 16, mm, .) +{ + uint src = OPER_AY_PD_16(); + uint ea = EA_AX_PD_16(); + uint dst = m68ki_read_16(ea); + uint res = dst - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + res = MASK_OUT_ABOVE_16(res); + FLAG_Z |= res; + + m68ki_write_16(ea, res); +} + + +M68KMAKE_OP(subx, 32, mm, .) +{ + uint src = OPER_AY_PD_32(); + uint ea = EA_AX_PD_32(); + uint dst = m68ki_read_32(ea); + uint res = dst - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + res = MASK_OUT_ABOVE_32(res); + FLAG_Z |= res; + + m68ki_write_32(ea, res); +} + + +M68KMAKE_OP(swap, 32, ., .) +{ + uint* r_dst = &DY; + + FLAG_Z = MASK_OUT_ABOVE_32(*r_dst<<16); + *r_dst = (*r_dst>>16) | FLAG_Z; + + FLAG_Z = *r_dst; + FLAG_N = NFLAG_32(*r_dst); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +M68KMAKE_OP(tas, 8, ., d) +{ + uint* r_dst = &DY; + + FLAG_Z = MASK_OUT_ABOVE_8(*r_dst); + FLAG_N = NFLAG_8(*r_dst); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst |= 0x80; +} + + +M68KMAKE_OP(tas, 8, ., .) +{ + uint ea = M68KMAKE_GET_EA_AY_8; + uint dst = m68ki_read_8(ea); + + FLAG_Z = dst; + FLAG_N = NFLAG_8(dst); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +// m68ki_write_8(ea, dst | 0x80); // notaz: genesis, but only to mem +} + + +M68KMAKE_OP(trap, 0, ., .) +{ + /* Trap#n stacks exception frame type 0 */ + m68ki_exception_trapN(EXCEPTION_TRAP_BASE + (REG_IR & 0xf)); /* HJB 990403 */ +} + + +M68KMAKE_OP(trapt, 0, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(trapt, 16, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(trapt, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(trapf, 0, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(trapf, 16, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + REG_PC += 2; + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(trapf, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + REG_PC += 4; + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(trapcc, 0, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(M68KMAKE_CC) + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(trapcc, 16, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(M68KMAKE_CC) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 2; + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(trapcc, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(M68KMAKE_CC) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 4; + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(trapv, 0, ., .) +{ + if(COND_VC()) + { + return; + } + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ +} + + +M68KMAKE_OP(tst, 8, ., d) +{ + uint res = MASK_OUT_ABOVE_8(DY); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(tst, 8, ., .) +{ + uint res = M68KMAKE_GET_OPER_AY_8; + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(tst, 8, ., pcdi) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint res = OPER_PCDI_8(); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(tst, 8, ., pcix) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint res = OPER_PCIX_8(); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(tst, 8, ., i) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint res = OPER_I_8(); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(tst, 16, ., d) +{ + uint res = MASK_OUT_ABOVE_16(DY); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(tst, 16, ., a) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint res = MAKE_INT_16(AY); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(tst, 16, ., .) +{ + uint res = M68KMAKE_GET_OPER_AY_16; + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(tst, 16, ., pcdi) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint res = OPER_PCDI_16(); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(tst, 16, ., pcix) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint res = OPER_PCIX_16(); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(tst, 16, ., i) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint res = OPER_I_16(); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(tst, 32, ., d) +{ + uint res = DY; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(tst, 32, ., a) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint res = AY; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(tst, 32, ., .) +{ + uint res = M68KMAKE_GET_OPER_AY_32; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +M68KMAKE_OP(tst, 32, ., pcdi) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint res = OPER_PCDI_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(tst, 32, ., pcix) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint res = OPER_PCIX_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(tst, 32, ., i) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint res = OPER_I_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(unlk, 32, ., a7) +{ + REG_A[7] = m68ki_read_32(REG_A[7]); +} + + +M68KMAKE_OP(unlk, 32, ., .) +{ + uint* r_dst = &AY; + + REG_A[7] = *r_dst; + *r_dst = m68ki_pull_32(); +} + + +M68KMAKE_OP(unpk, 16, rr, .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + /* Note: DX and DY are reversed in Motorola's docs */ + uint src = DY; + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (((((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16()) & 0xffff); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(unpk, 16, mm, ax7) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + /* Note: AX and AY are reversed in Motorola's docs */ + uint src = OPER_AY_PD_8(); + uint ea_dst; + + src = (((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16(); + ea_dst = EA_A7_PD_8(); + m68ki_write_8(ea_dst, (src >> 8) & 0xff); + ea_dst = EA_A7_PD_8(); + m68ki_write_8(ea_dst, src & 0xff); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(unpk, 16, mm, ay7) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + /* Note: AX and AY are reversed in Motorola's docs */ + uint src = OPER_A7_PD_8(); + uint ea_dst; + + src = (((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16(); + ea_dst = EA_AX_PD_8(); + m68ki_write_8(ea_dst, (src >> 8) & 0xff); + ea_dst = EA_AX_PD_8(); + m68ki_write_8(ea_dst, src & 0xff); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(unpk, 16, mm, axy7) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint src = OPER_A7_PD_8(); + uint ea_dst; + + src = (((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16(); + ea_dst = EA_A7_PD_8(); + m68ki_write_8(ea_dst, (src >> 8) & 0xff); + ea_dst = EA_A7_PD_8(); + m68ki_write_8(ea_dst, src & 0xff); + return; + } + m68ki_exception_illegal(); +} + + +M68KMAKE_OP(unpk, 16, mm, .) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + /* Note: AX and AY are reversed in Motorola's docs */ + uint src = OPER_AY_PD_8(); + uint ea_dst; + + src = (((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16(); + ea_dst = EA_AX_PD_8(); + m68ki_write_8(ea_dst, (src >> 8) & 0xff); + ea_dst = EA_AX_PD_8(); + m68ki_write_8(ea_dst, src & 0xff); + return; + } + m68ki_exception_illegal(); +} + + + +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +M68KMAKE_END diff --git a/cpu/musashi/m68kconf.h b/cpu/musashi/m68kconf.h new file mode 100644 index 00000000..ced542df --- /dev/null +++ b/cpu/musashi/m68kconf.h @@ -0,0 +1,203 @@ +/* ======================================================================== */ +/* ========================= LICENSING & COPYRIGHT ======================== */ +/* ======================================================================== */ +/* + * MUSASHI + * Version 3.3 + * + * A portable Motorola M680x0 processor emulation engine. + * Copyright 1998-2001 Karl Stenerud. All rights reserved. + * + * This code may be freely used for non-commercial purposes as long as this + * copyright notice remains unaltered in the source code and any binary files + * containing this code in compiled form. + * + * All other lisencing terms must be negotiated with the author + * (Karl Stenerud). + * + * The latest version of this code can be obtained at: + * http://kstenerud.cjb.net + */ + + +// notaz: kill some stupid VC warnings +#ifndef __GNUC__ +#pragma warning (disable:4100) // unreferenced formal parameter +#pragma warning (disable:4127) // conditional expression is constant +#pragma warning (disable:4245) // type conversion +#pragma warning (disable:4514) // unreferenced inline function has been removed +#endif + + +#ifndef M68KCONF__HEADER +#define M68KCONF__HEADER + + +/* Configuration switches. + * Use OPT_SPECIFY_HANDLER for configuration options that allow callbacks. + * OPT_SPECIFY_HANDLER causes the core to link directly to the function + * or macro you specify, rather than using callback functions whose pointer + * must be passed in using m68k_set_xxx_callback(). + */ +#define OPT_OFF 0 +#define OPT_ON 1 +#define OPT_SPECIFY_HANDLER 2 + + +/* ======================================================================== */ +/* ============================== MAME STUFF ============================== */ +/* ======================================================================== */ + +/* If you're compiling this for MAME, only change M68K_COMPILE_FOR_MAME + * to OPT_ON and use m68kmame.h to configure the 68k core. + */ +#ifndef M68K_COMPILE_FOR_MAME +#define M68K_COMPILE_FOR_MAME OPT_OFF +#endif /* M68K_COMPILE_FOR_MAME */ + + +#if M68K_COMPILE_FOR_MAME == OPT_OFF + + +/* ======================================================================== */ +/* ============================= CONFIGURATION ============================ */ +/* ======================================================================== */ + +/* Turn ON if you want to use the following M68K variants */ +#define M68K_EMULATE_008 OPT_OFF +#define M68K_EMULATE_010 OPT_OFF +#define M68K_EMULATE_EC020 OPT_OFF +#define M68K_EMULATE_020 OPT_OFF +#define M68K_EMULATE_040 OPT_OFF + + +/* If ON, the CPU will call m68k_read_immediate_xx() for immediate addressing + * and m68k_read_pcrelative_xx() for PC-relative addressing. + * If off, all read requests from the CPU will be redirected to m68k_read_xx() + */ +#define M68K_SEPARATE_READS OPT_ON + +/* If ON, the CPU will call m68k_write_32_pd() when it executes move.l with a + * predecrement destination EA mode instead of m68k_write_32(). + * To simulate real 68k behavior, m68k_write_32_pd() must first write the high + * word to [address+2], and then write the low word to [address]. + */ +#define M68K_SIMULATE_PD_WRITES OPT_OFF + +/* If ON, CPU will call the interrupt acknowledge callback when it services an + * interrupt. + * If off, all interrupts will be autovectored and all interrupt requests will + * auto-clear when the interrupt is serviced. + */ +#define M68K_EMULATE_INT_ACK OPT_ON +#define M68K_INT_ACK_CALLBACK(A) your_int_ack_handler_function(A) + + +/* If ON, CPU will call the breakpoint acknowledge callback when it encounters + * a breakpoint instruction and it is running a 68010+. + */ +#define M68K_EMULATE_BKPT_ACK OPT_OFF +#define M68K_BKPT_ACK_CALLBACK() your_bkpt_ack_handler_function() + + +/* If ON, the CPU will monitor the trace flags and take trace exceptions + */ +#define M68K_EMULATE_TRACE OPT_OFF + + +/* If ON, CPU will call the output reset callback when it encounters a reset + * instruction. + */ +#define M68K_EMULATE_RESET OPT_OFF +#define M68K_RESET_CALLBACK() your_reset_handler_function() + + +/* If ON, CPU will call the callback when it encounters a cmpi.l #v, dn + * instruction. + */ +#define M68K_CMPILD_HAS_CALLBACK OPT_OFF +#define M68K_CMPILD_CALLBACK(v,r) your_cmpild_handler_function(v,r) + + +/* If ON, CPU will call the callback when it encounters a rte + * instruction. + */ +#define M68K_RTE_HAS_CALLBACK OPT_OFF +#define M68K_RTE_CALLBACK() your_rte_handler_function() + + +/* If ON, CPU will call the set fc callback on every memory access to + * differentiate between user/supervisor, program/data access like a real + * 68000 would. This should be enabled and the callback should be set if you + * want to properly emulate the m68010 or higher. (moves uses function codes + * to read/write data from different address spaces) + */ +#define M68K_EMULATE_FC OPT_OFF +#define M68K_SET_FC_CALLBACK(A) your_set_fc_handler_function(A) + + +/* If ON, CPU will call the pc changed callback when it changes the PC by a + * large value. This allows host programs to be nicer when it comes to + * fetching immediate data and instructions on a banked memory system. + */ +#define M68K_MONITOR_PC OPT_OFF +#define M68K_SET_PC_CALLBACK(A) your_pc_changed_handler_function(A) + + +/* If ON, CPU will call the instruction hook callback before every + * instruction. + */ +#define M68K_INSTRUCTION_HOOK OPT_OFF +#define M68K_INSTRUCTION_CALLBACK() your_instruction_hook_function() + + +/* If ON, the CPU will emulate the 4-byte prefetch queue of a real 68000 */ +#define M68K_EMULATE_PREFETCH OPT_OFF + + +/* If ON, the CPU will generate address error exceptions if it tries to + * access a word or longword at an odd address. + * NOTE: This is only emulated properly for 68000 mode. + */ +#define M68K_EMULATE_ADDRESS_ERROR OPT_OFF + + +/* Turn ON to enable logging of illegal instruction calls. + * M68K_LOG_FILEHANDLE must be #defined to a stdio file stream. + * Turn on M68K_LOG_1010_1111 to log all 1010 and 1111 calls. + */ +#define M68K_LOG_ENABLE OPT_OFF +#define M68K_LOG_1010_1111 OPT_OFF +#define M68K_LOG_FILEHANDLE some_file_handle + + +/* ----------------------------- COMPATIBILITY ---------------------------- */ + +/* The following options set optimizations that violate the current ANSI + * standard, but will be compliant under the forthcoming C9X standard. + */ + + +/* If ON, the enulation core will use 64-bit integers to speed up some + * operations. +*/ +#define M68K_USE_64_BIT OPT_OFF + + +/* Set to your compiler's static inline keyword to enable it, or + * set it to blank to disable it. + * If you define INLINE in the makefile, it will override this value. + * NOTE: not enabling inline functions will SEVERELY slow down emulation. + */ +#ifndef INLINE +#define INLINE static __inline +#endif /* INLINE */ + +#endif /* M68K_COMPILE_FOR_MAME */ + + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ + +#endif /* M68KCONF__HEADER */ diff --git a/cpu/musashi/m68kcpu.c b/cpu/musashi/m68kcpu.c new file mode 100644 index 00000000..b3cd36db --- /dev/null +++ b/cpu/musashi/m68kcpu.c @@ -0,0 +1,1015 @@ +/* ======================================================================== */ +/* ========================= LICENSING & COPYRIGHT ======================== */ +/* ======================================================================== */ + +#if 0 +static const char* copyright_notice = +"MUSASHI\n" +"Version 3.3 (2001-01-29)\n" +"A portable Motorola M680x0 processor emulation engine.\n" +"Copyright 1998-2001 Karl Stenerud. All rights reserved.\n" +"\n" +"This code may be freely used for non-commercial purpooses as long as this\n" +"copyright notice remains unaltered in the source code and any binary files\n" +"containing this code in compiled form.\n" +"\n" +"All other lisencing terms must be negotiated with the author\n" +"(Karl Stenerud).\n" +"\n" +"The latest version of this code can be obtained at:\n" +"http://kstenerud.cjb.net\n" +; +#endif + + +/* ======================================================================== */ +/* ================================= NOTES ================================ */ +/* ======================================================================== */ + + + +/* ======================================================================== */ +/* ================================ INCLUDES ============================== */ +/* ======================================================================== */ + +#include "m68kops.h" +#include "m68kcpu.h" + +/* ======================================================================== */ +/* ================================= DATA ================================= */ +/* ======================================================================== */ + +int m68ki_initial_cycles; +int m68ki_remaining_cycles = 0; /* Number of clocks remaining */ +uint m68ki_tracing = 0; +uint m68ki_address_space; + +#ifdef M68K_LOG_ENABLE +const char* m68ki_cpu_names[] = +{ + "Invalid CPU", + "M68000", + "M68008", + "Invalid CPU", + "M68010", + "Invalid CPU", + "Invalid CPU", + "Invalid CPU", + "M68EC020", + "Invalid CPU", + "Invalid CPU", + "Invalid CPU", + "Invalid CPU", + "Invalid CPU", + "Invalid CPU", + "Invalid CPU", + "M68020" +}; +#endif /* M68K_LOG_ENABLE */ + +/* The CPU core */ +// m68ki_cpu_core m68ki_cpu = {0}; +m68ki_cpu_core *m68ki_cpu_p = NULL; + + +#if M68K_EMULATE_ADDRESS_ERROR +jmp_buf m68ki_aerr_trap; +#endif /* M68K_EMULATE_ADDRESS_ERROR */ + +uint m68ki_aerr_address; +uint m68ki_aerr_write_mode; +uint m68ki_aerr_fc; + +/* Used by shift & rotate instructions */ +uint8 m68ki_shift_8_table[65] = +{ + 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff +}; +uint16 m68ki_shift_16_table[65] = +{ + 0x0000, 0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, + 0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff +}; +uint m68ki_shift_32_table[65] = +{ + 0x00000000, 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 0xf8000000, + 0xfc000000, 0xfe000000, 0xff000000, 0xff800000, 0xffc00000, 0xffe00000, + 0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000, 0xffff8000, + 0xffffc000, 0xffffe000, 0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00, + 0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 0xfffffff8, + 0xfffffffc, 0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff +}; + + +/* Number of clock cycles to use for exception processing. + * I used 4 for any vectors that are undocumented for processing times. + */ +uint8 m68ki_exception_cycle_table[4][256] = +{ + { /* 000 */ + 4, /* 0: Reset - Initial Stack Pointer */ + 4, /* 1: Reset - Initial Program Counter */ + 50, /* 2: Bus Error (unemulated) */ + 50, /* 3: Address Error (unemulated) */ + 34, /* 4: Illegal Instruction */ + 38, /* 5: Divide by Zero -- ASG: changed from 42 */ + 40, /* 6: CHK -- ASG: chanaged from 44 */ + 34, /* 7: TRAPV */ + 34, /* 8: Privilege Violation */ + 34, /* 9: Trace */ + 4, /* 10: 1010 */ + 4, /* 11: 1111 */ + 4, /* 12: RESERVED */ + 4, /* 13: Coprocessor Protocol Violation (unemulated) */ + 4, /* 14: Format Error */ + 44, /* 15: Uninitialized Interrupt */ + 4, /* 16: RESERVED */ + 4, /* 17: RESERVED */ + 4, /* 18: RESERVED */ + 4, /* 19: RESERVED */ + 4, /* 20: RESERVED */ + 4, /* 21: RESERVED */ + 4, /* 22: RESERVED */ + 4, /* 23: RESERVED */ + 44, /* 24: Spurious Interrupt */ + 44, /* 25: Level 1 Interrupt Autovector */ + 44, /* 26: Level 2 Interrupt Autovector */ + 44, /* 27: Level 3 Interrupt Autovector */ + 44, /* 28: Level 4 Interrupt Autovector */ + 44, /* 29: Level 5 Interrupt Autovector */ + 44, /* 30: Level 6 Interrupt Autovector */ + 44, /* 31: Level 7 Interrupt Autovector */ + 34, /* 32: TRAP #0 -- ASG: chanaged from 38 */ + 34, /* 33: TRAP #1 */ + 34, /* 34: TRAP #2 */ + 34, /* 35: TRAP #3 */ + 34, /* 36: TRAP #4 */ + 34, /* 37: TRAP #5 */ + 34, /* 38: TRAP #6 */ + 34, /* 39: TRAP #7 */ + 34, /* 40: TRAP #8 */ + 34, /* 41: TRAP #9 */ + 34, /* 42: TRAP #10 */ + 34, /* 43: TRAP #11 */ + 34, /* 44: TRAP #12 */ + 34, /* 45: TRAP #13 */ + 34, /* 46: TRAP #14 */ + 34, /* 47: TRAP #15 */ + 4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */ + 4, /* 49: FP Inexact Result (unemulated) */ + 4, /* 50: FP Divide by Zero (unemulated) */ + 4, /* 51: FP Underflow (unemulated) */ + 4, /* 52: FP Operand Error (unemulated) */ + 4, /* 53: FP Overflow (unemulated) */ + 4, /* 54: FP Signaling NAN (unemulated) */ + 4, /* 55: FP Unimplemented Data Type (unemulated) */ + 4, /* 56: MMU Configuration Error (unemulated) */ + 4, /* 57: MMU Illegal Operation Error (unemulated) */ + 4, /* 58: MMU Access Level Violation Error (unemulated) */ + 4, /* 59: RESERVED */ + 4, /* 60: RESERVED */ + 4, /* 61: RESERVED */ + 4, /* 62: RESERVED */ + 4, /* 63: RESERVED */ + /* 64-255: User Defined */ + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 + }, + { /* 010 */ + 4, /* 0: Reset - Initial Stack Pointer */ + 4, /* 1: Reset - Initial Program Counter */ + 126, /* 2: Bus Error (unemulated) */ + 126, /* 3: Address Error (unemulated) */ + 38, /* 4: Illegal Instruction */ + 44, /* 5: Divide by Zero */ + 44, /* 6: CHK */ + 34, /* 7: TRAPV */ + 38, /* 8: Privilege Violation */ + 38, /* 9: Trace */ + 4, /* 10: 1010 */ + 4, /* 11: 1111 */ + 4, /* 12: RESERVED */ + 4, /* 13: Coprocessor Protocol Violation (unemulated) */ + 4, /* 14: Format Error */ + 44, /* 15: Uninitialized Interrupt */ + 4, /* 16: RESERVED */ + 4, /* 17: RESERVED */ + 4, /* 18: RESERVED */ + 4, /* 19: RESERVED */ + 4, /* 20: RESERVED */ + 4, /* 21: RESERVED */ + 4, /* 22: RESERVED */ + 4, /* 23: RESERVED */ + 46, /* 24: Spurious Interrupt */ + 46, /* 25: Level 1 Interrupt Autovector */ + 46, /* 26: Level 2 Interrupt Autovector */ + 46, /* 27: Level 3 Interrupt Autovector */ + 46, /* 28: Level 4 Interrupt Autovector */ + 46, /* 29: Level 5 Interrupt Autovector */ + 46, /* 30: Level 6 Interrupt Autovector */ + 46, /* 31: Level 7 Interrupt Autovector */ + 38, /* 32: TRAP #0 */ + 38, /* 33: TRAP #1 */ + 38, /* 34: TRAP #2 */ + 38, /* 35: TRAP #3 */ + 38, /* 36: TRAP #4 */ + 38, /* 37: TRAP #5 */ + 38, /* 38: TRAP #6 */ + 38, /* 39: TRAP #7 */ + 38, /* 40: TRAP #8 */ + 38, /* 41: TRAP #9 */ + 38, /* 42: TRAP #10 */ + 38, /* 43: TRAP #11 */ + 38, /* 44: TRAP #12 */ + 38, /* 45: TRAP #13 */ + 38, /* 46: TRAP #14 */ + 38, /* 47: TRAP #15 */ + 4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */ + 4, /* 49: FP Inexact Result (unemulated) */ + 4, /* 50: FP Divide by Zero (unemulated) */ + 4, /* 51: FP Underflow (unemulated) */ + 4, /* 52: FP Operand Error (unemulated) */ + 4, /* 53: FP Overflow (unemulated) */ + 4, /* 54: FP Signaling NAN (unemulated) */ + 4, /* 55: FP Unimplemented Data Type (unemulated) */ + 4, /* 56: MMU Configuration Error (unemulated) */ + 4, /* 57: MMU Illegal Operation Error (unemulated) */ + 4, /* 58: MMU Access Level Violation Error (unemulated) */ + 4, /* 59: RESERVED */ + 4, /* 60: RESERVED */ + 4, /* 61: RESERVED */ + 4, /* 62: RESERVED */ + 4, /* 63: RESERVED */ + /* 64-255: User Defined */ + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 + }, + { /* 020 */ + 4, /* 0: Reset - Initial Stack Pointer */ + 4, /* 1: Reset - Initial Program Counter */ + 50, /* 2: Bus Error (unemulated) */ + 50, /* 3: Address Error (unemulated) */ + 20, /* 4: Illegal Instruction */ + 38, /* 5: Divide by Zero */ + 40, /* 6: CHK */ + 20, /* 7: TRAPV */ + 34, /* 8: Privilege Violation */ + 25, /* 9: Trace */ + 20, /* 10: 1010 */ + 20, /* 11: 1111 */ + 4, /* 12: RESERVED */ + 4, /* 13: Coprocessor Protocol Violation (unemulated) */ + 4, /* 14: Format Error */ + 30, /* 15: Uninitialized Interrupt */ + 4, /* 16: RESERVED */ + 4, /* 17: RESERVED */ + 4, /* 18: RESERVED */ + 4, /* 19: RESERVED */ + 4, /* 20: RESERVED */ + 4, /* 21: RESERVED */ + 4, /* 22: RESERVED */ + 4, /* 23: RESERVED */ + 30, /* 24: Spurious Interrupt */ + 30, /* 25: Level 1 Interrupt Autovector */ + 30, /* 26: Level 2 Interrupt Autovector */ + 30, /* 27: Level 3 Interrupt Autovector */ + 30, /* 28: Level 4 Interrupt Autovector */ + 30, /* 29: Level 5 Interrupt Autovector */ + 30, /* 30: Level 6 Interrupt Autovector */ + 30, /* 31: Level 7 Interrupt Autovector */ + 20, /* 32: TRAP #0 */ + 20, /* 33: TRAP #1 */ + 20, /* 34: TRAP #2 */ + 20, /* 35: TRAP #3 */ + 20, /* 36: TRAP #4 */ + 20, /* 37: TRAP #5 */ + 20, /* 38: TRAP #6 */ + 20, /* 39: TRAP #7 */ + 20, /* 40: TRAP #8 */ + 20, /* 41: TRAP #9 */ + 20, /* 42: TRAP #10 */ + 20, /* 43: TRAP #11 */ + 20, /* 44: TRAP #12 */ + 20, /* 45: TRAP #13 */ + 20, /* 46: TRAP #14 */ + 20, /* 47: TRAP #15 */ + 4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */ + 4, /* 49: FP Inexact Result (unemulated) */ + 4, /* 50: FP Divide by Zero (unemulated) */ + 4, /* 51: FP Underflow (unemulated) */ + 4, /* 52: FP Operand Error (unemulated) */ + 4, /* 53: FP Overflow (unemulated) */ + 4, /* 54: FP Signaling NAN (unemulated) */ + 4, /* 55: FP Unimplemented Data Type (unemulated) */ + 4, /* 56: MMU Configuration Error (unemulated) */ + 4, /* 57: MMU Illegal Operation Error (unemulated) */ + 4, /* 58: MMU Access Level Violation Error (unemulated) */ + 4, /* 59: RESERVED */ + 4, /* 60: RESERVED */ + 4, /* 61: RESERVED */ + 4, /* 62: RESERVED */ + 4, /* 63: RESERVED */ + /* 64-255: User Defined */ + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 + }, + { /* 040 */ // TODO: these values are not correct + 4, /* 0: Reset - Initial Stack Pointer */ + 4, /* 1: Reset - Initial Program Counter */ + 50, /* 2: Bus Error (unemulated) */ + 50, /* 3: Address Error (unemulated) */ + 20, /* 4: Illegal Instruction */ + 38, /* 5: Divide by Zero */ + 40, /* 6: CHK */ + 20, /* 7: TRAPV */ + 34, /* 8: Privilege Violation */ + 25, /* 9: Trace */ + 20, /* 10: 1010 */ + 20, /* 11: 1111 */ + 4, /* 12: RESERVED */ + 4, /* 13: Coprocessor Protocol Violation (unemulated) */ + 4, /* 14: Format Error */ + 30, /* 15: Uninitialized Interrupt */ + 4, /* 16: RESERVED */ + 4, /* 17: RESERVED */ + 4, /* 18: RESERVED */ + 4, /* 19: RESERVED */ + 4, /* 20: RESERVED */ + 4, /* 21: RESERVED */ + 4, /* 22: RESERVED */ + 4, /* 23: RESERVED */ + 30, /* 24: Spurious Interrupt */ + 30, /* 25: Level 1 Interrupt Autovector */ + 30, /* 26: Level 2 Interrupt Autovector */ + 30, /* 27: Level 3 Interrupt Autovector */ + 30, /* 28: Level 4 Interrupt Autovector */ + 30, /* 29: Level 5 Interrupt Autovector */ + 30, /* 30: Level 6 Interrupt Autovector */ + 30, /* 31: Level 7 Interrupt Autovector */ + 20, /* 32: TRAP #0 */ + 20, /* 33: TRAP #1 */ + 20, /* 34: TRAP #2 */ + 20, /* 35: TRAP #3 */ + 20, /* 36: TRAP #4 */ + 20, /* 37: TRAP #5 */ + 20, /* 38: TRAP #6 */ + 20, /* 39: TRAP #7 */ + 20, /* 40: TRAP #8 */ + 20, /* 41: TRAP #9 */ + 20, /* 42: TRAP #10 */ + 20, /* 43: TRAP #11 */ + 20, /* 44: TRAP #12 */ + 20, /* 45: TRAP #13 */ + 20, /* 46: TRAP #14 */ + 20, /* 47: TRAP #15 */ + 4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */ + 4, /* 49: FP Inexact Result (unemulated) */ + 4, /* 50: FP Divide by Zero (unemulated) */ + 4, /* 51: FP Underflow (unemulated) */ + 4, /* 52: FP Operand Error (unemulated) */ + 4, /* 53: FP Overflow (unemulated) */ + 4, /* 54: FP Signaling NAN (unemulated) */ + 4, /* 55: FP Unimplemented Data Type (unemulated) */ + 4, /* 56: MMU Configuration Error (unemulated) */ + 4, /* 57: MMU Illegal Operation Error (unemulated) */ + 4, /* 58: MMU Access Level Violation Error (unemulated) */ + 4, /* 59: RESERVED */ + 4, /* 60: RESERVED */ + 4, /* 61: RESERVED */ + 4, /* 62: RESERVED */ + 4, /* 63: RESERVED */ + /* 64-255: User Defined */ + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 + } +}; + +uint8 m68ki_ea_idx_cycle_table[64] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, /* ..01.000 no memory indirect, base NULL */ + 5, /* ..01..01 memory indirect, base NULL, outer NULL */ + 7, /* ..01..10 memory indirect, base NULL, outer 16 */ + 7, /* ..01..11 memory indirect, base NULL, outer 32 */ + 0, 5, 7, 7, 0, 5, 7, 7, 0, 5, 7, 7, + 2, /* ..10.000 no memory indirect, base 16 */ + 7, /* ..10..01 memory indirect, base 16, outer NULL */ + 9, /* ..10..10 memory indirect, base 16, outer 16 */ + 9, /* ..10..11 memory indirect, base 16, outer 32 */ + 0, 7, 9, 9, 0, 7, 9, 9, 0, 7, 9, 9, + 6, /* ..11.000 no memory indirect, base 32 */ + 11, /* ..11..01 memory indirect, base 32, outer NULL */ + 13, /* ..11..10 memory indirect, base 32, outer 16 */ + 13, /* ..11..11 memory indirect, base 32, outer 32 */ + 0, 11, 13, 13, 0, 11, 13, 13, 0, 11, 13, 13 +}; + + + +/* ======================================================================== */ +/* =============================== CALLBACKS ============================== */ +/* ======================================================================== */ + +/* Default callbacks used if the callback hasn't been set yet, or if the + * callback is set to NULL + */ + +/* Interrupt acknowledge */ +static int default_int_ack_callback_data; +static int default_int_ack_callback(int int_level) +{ + default_int_ack_callback_data = int_level; + CPU_INT_LEVEL = 0; + return M68K_INT_ACK_AUTOVECTOR; +} + +/* Breakpoint acknowledge */ +static unsigned int default_bkpt_ack_callback_data; +static void default_bkpt_ack_callback(unsigned int data) +{ + default_bkpt_ack_callback_data = data; +} + +/* Called when a reset instruction is executed */ +static void default_reset_instr_callback(void) +{ +} + +/* Called when a cmpi.l #v, dn instruction is executed */ +static void default_cmpild_instr_callback(unsigned int val, int reg) +{ +} + +/* Called when a rte instruction is executed */ +static void default_rte_instr_callback(void) +{ +} + +/* Called when the program counter changed by a large value */ +static unsigned int default_pc_changed_callback_data; +static void default_pc_changed_callback(unsigned int new_pc) +{ + default_pc_changed_callback_data = new_pc; +} + +/* Called every time there's bus activity (read/write to/from memory */ +static unsigned int default_set_fc_callback_data; +static void default_set_fc_callback(unsigned int new_fc) +{ + default_set_fc_callback_data = new_fc; +} + +/* Called every instruction cycle prior to execution */ +static void default_instr_hook_callback(void) +{ +} + + +#if M68K_EMULATE_ADDRESS_ERROR + #include + jmp_buf m68ki_aerr_trap; +#endif /* M68K_EMULATE_ADDRESS_ERROR */ + + +/* ======================================================================== */ +/* ================================= API ================================== */ +/* ======================================================================== */ + +/* Access the internals of the CPU */ +unsigned int m68k_get_reg(void* context, m68k_register_t regnum) +{ + m68ki_cpu_core* cpu = context != NULL ?(m68ki_cpu_core*)context : &m68ki_cpu; + + switch(regnum) + { + case M68K_REG_D0: return cpu->dar[0]; + case M68K_REG_D1: return cpu->dar[1]; + case M68K_REG_D2: return cpu->dar[2]; + case M68K_REG_D3: return cpu->dar[3]; + case M68K_REG_D4: return cpu->dar[4]; + case M68K_REG_D5: return cpu->dar[5]; + case M68K_REG_D6: return cpu->dar[6]; + case M68K_REG_D7: return cpu->dar[7]; + case M68K_REG_A0: return cpu->dar[8]; + case M68K_REG_A1: return cpu->dar[9]; + case M68K_REG_A2: return cpu->dar[10]; + case M68K_REG_A3: return cpu->dar[11]; + case M68K_REG_A4: return cpu->dar[12]; + case M68K_REG_A5: return cpu->dar[13]; + case M68K_REG_A6: return cpu->dar[14]; + case M68K_REG_A7: return cpu->dar[15]; + case M68K_REG_PC: return MASK_OUT_ABOVE_32(cpu->pc); + case M68K_REG_SR: return cpu->t1_flag | + cpu->t0_flag | + (cpu->s_flag << 11) | + (cpu->m_flag << 11) | + cpu->int_mask | + ((cpu->x_flag & XFLAG_SET) >> 4) | + ((cpu->n_flag & NFLAG_SET) >> 4) | + ((!cpu->not_z_flag) << 2) | + ((cpu->v_flag & VFLAG_SET) >> 6) | + ((cpu->c_flag & CFLAG_SET) >> 8); + case M68K_REG_SP: return cpu->dar[15]; + case M68K_REG_USP: return cpu->s_flag ? cpu->sp[0] : cpu->dar[15]; + case M68K_REG_ISP: return cpu->s_flag && !cpu->m_flag ? cpu->dar[15] : cpu->sp[4]; + case M68K_REG_MSP: return cpu->s_flag && cpu->m_flag ? cpu->dar[15] : cpu->sp[6]; + case M68K_REG_SFC: return cpu->sfc; + case M68K_REG_DFC: return cpu->dfc; + case M68K_REG_VBR: return cpu->vbr; + case M68K_REG_CACR: return cpu->cacr; + case M68K_REG_CAAR: return cpu->caar; + case M68K_REG_PREF_ADDR: return cpu->pref_addr; + case M68K_REG_PREF_DATA: return cpu->pref_data; + case M68K_REG_PPC: return MASK_OUT_ABOVE_32(cpu->ppc); + case M68K_REG_IR: return cpu->ir; + case M68K_REG_CPU_TYPE: + switch(cpu->cpu_type) + { + case CPU_TYPE_000: return (unsigned int)M68K_CPU_TYPE_68000; + case CPU_TYPE_008: return (unsigned int)M68K_CPU_TYPE_68008; + case CPU_TYPE_010: return (unsigned int)M68K_CPU_TYPE_68010; + case CPU_TYPE_EC020: return (unsigned int)M68K_CPU_TYPE_68EC020; + case CPU_TYPE_020: return (unsigned int)M68K_CPU_TYPE_68020; + case CPU_TYPE_040: return (unsigned int)M68K_CPU_TYPE_68040; + } + return M68K_CPU_TYPE_INVALID; + default: return 0; + } + return 0; +} + +void m68k_set_reg(m68k_register_t regnum, unsigned int value) +{ + switch(regnum) + { + case M68K_REG_D0: REG_D[0] = MASK_OUT_ABOVE_32(value); return; + case M68K_REG_D1: REG_D[1] = MASK_OUT_ABOVE_32(value); return; + case M68K_REG_D2: REG_D[2] = MASK_OUT_ABOVE_32(value); return; + case M68K_REG_D3: REG_D[3] = MASK_OUT_ABOVE_32(value); return; + case M68K_REG_D4: REG_D[4] = MASK_OUT_ABOVE_32(value); return; + case M68K_REG_D5: REG_D[5] = MASK_OUT_ABOVE_32(value); return; + case M68K_REG_D6: REG_D[6] = MASK_OUT_ABOVE_32(value); return; + case M68K_REG_D7: REG_D[7] = MASK_OUT_ABOVE_32(value); return; + case M68K_REG_A0: REG_A[0] = MASK_OUT_ABOVE_32(value); return; + case M68K_REG_A1: REG_A[1] = MASK_OUT_ABOVE_32(value); return; + case M68K_REG_A2: REG_A[2] = MASK_OUT_ABOVE_32(value); return; + case M68K_REG_A3: REG_A[3] = MASK_OUT_ABOVE_32(value); return; + case M68K_REG_A4: REG_A[4] = MASK_OUT_ABOVE_32(value); return; + case M68K_REG_A5: REG_A[5] = MASK_OUT_ABOVE_32(value); return; + case M68K_REG_A6: REG_A[6] = MASK_OUT_ABOVE_32(value); return; + case M68K_REG_A7: REG_A[7] = MASK_OUT_ABOVE_32(value); return; + case M68K_REG_PC: m68ki_jump(MASK_OUT_ABOVE_32(value)); return; + case M68K_REG_SR: m68ki_set_sr(value); return; + case M68K_REG_SP: REG_SP = MASK_OUT_ABOVE_32(value); return; + case M68K_REG_USP: if(FLAG_S) + REG_USP = MASK_OUT_ABOVE_32(value); + else + REG_SP = MASK_OUT_ABOVE_32(value); + return; + case M68K_REG_ISP: if(FLAG_S && !FLAG_M) + REG_SP = MASK_OUT_ABOVE_32(value); + else + REG_ISP = MASK_OUT_ABOVE_32(value); + return; + case M68K_REG_MSP: if(FLAG_S && FLAG_M) + REG_SP = MASK_OUT_ABOVE_32(value); + else + REG_MSP = MASK_OUT_ABOVE_32(value); + return; + case M68K_REG_VBR: REG_VBR = MASK_OUT_ABOVE_32(value); return; + case M68K_REG_SFC: REG_SFC = value & 7; return; + case M68K_REG_DFC: REG_DFC = value & 7; return; + case M68K_REG_CACR: REG_CACR = MASK_OUT_ABOVE_32(value); return; + case M68K_REG_CAAR: REG_CAAR = MASK_OUT_ABOVE_32(value); return; + case M68K_REG_PPC: REG_PPC = MASK_OUT_ABOVE_32(value); return; + case M68K_REG_IR: REG_IR = MASK_OUT_ABOVE_16(value); return; + case M68K_REG_PREF_ADDR: CPU_PREF_ADDR = MASK_OUT_ABOVE_32(value); return; + case M68K_REG_CPU_TYPE: m68k_set_cpu_type(value); return; + default: return; + } +} + +/* Set the callbacks */ +void m68k_set_int_ack_callback(int (*callback)(int int_level)) +{ + CALLBACK_INT_ACK = callback ? callback : default_int_ack_callback; +} + +void m68k_set_bkpt_ack_callback(void (*callback)(unsigned int data)) +{ + CALLBACK_BKPT_ACK = callback ? callback : default_bkpt_ack_callback; +} + +void m68k_set_reset_instr_callback(void (*callback)(void)) +{ + CALLBACK_RESET_INSTR = callback ? callback : default_reset_instr_callback; +} + +void m68k_set_cmpild_instr_callback(void (*callback)(unsigned int, int)) +{ + CALLBACK_CMPILD_INSTR = callback ? callback : default_cmpild_instr_callback; +} + +void m68k_set_rte_instr_callback(void (*callback)(void)) +{ + CALLBACK_RTE_INSTR = callback ? callback : default_rte_instr_callback; +} + +void m68k_set_pc_changed_callback(void (*callback)(unsigned int new_pc)) +{ + CALLBACK_PC_CHANGED = callback ? callback : default_pc_changed_callback; +} + +void m68k_set_fc_callback(void (*callback)(unsigned int new_fc)) +{ + CALLBACK_SET_FC = callback ? callback : default_set_fc_callback; +} + +void m68k_set_instr_hook_callback(void (*callback)(void)) +{ + CALLBACK_INSTR_HOOK = callback ? callback : default_instr_hook_callback; +} + +#include +/* Set the CPU type. */ +void m68k_set_cpu_type(unsigned int cpu_type) +{ + switch(cpu_type) + { + case M68K_CPU_TYPE_68000: + CPU_TYPE = CPU_TYPE_000; + CPU_ADDRESS_MASK = 0x00ffffff; + CPU_SR_MASK = 0xa71f; /* T1 -- S -- -- I2 I1 I0 -- -- -- X N Z V C */ + CYC_INSTRUCTION = m68ki_cycles[0]; + CYC_EXCEPTION = m68ki_exception_cycle_table[0]; + CYC_BCC_NOTAKE_B = -2; + CYC_BCC_NOTAKE_W = 2; + CYC_DBCC_F_NOEXP = -2; + CYC_DBCC_F_EXP = 2; + CYC_SCC_R_TRUE = 2; + CYC_MOVEM_W = 2; + CYC_MOVEM_L = 3; + CYC_SHIFT = 1; + CYC_RESET = 132; + return; + case M68K_CPU_TYPE_68008: + CPU_TYPE = CPU_TYPE_008; + CPU_ADDRESS_MASK = 0x003fffff; + CPU_SR_MASK = 0xa71f; /* T1 -- S -- -- I2 I1 I0 -- -- -- X N Z V C */ + CYC_INSTRUCTION = m68ki_cycles[0]; + CYC_EXCEPTION = m68ki_exception_cycle_table[0]; + CYC_BCC_NOTAKE_B = -2; + CYC_BCC_NOTAKE_W = 2; + CYC_DBCC_F_NOEXP = -2; + CYC_DBCC_F_EXP = 2; + CYC_SCC_R_TRUE = 2; + CYC_MOVEM_W = 2; + CYC_MOVEM_L = 3; + CYC_SHIFT = 1; + CYC_RESET = 132; + return; + case M68K_CPU_TYPE_68010: + CPU_TYPE = CPU_TYPE_010; + CPU_ADDRESS_MASK = 0x00ffffff; + CPU_SR_MASK = 0xa71f; /* T1 -- S -- -- I2 I1 I0 -- -- -- X N Z V C */ + CYC_INSTRUCTION = m68ki_cycles[1]; + CYC_EXCEPTION = m68ki_exception_cycle_table[1]; + CYC_BCC_NOTAKE_B = -4; + CYC_BCC_NOTAKE_W = 0; + CYC_DBCC_F_NOEXP = 0; + CYC_DBCC_F_EXP = 6; + CYC_SCC_R_TRUE = 0; + CYC_MOVEM_W = 2; + CYC_MOVEM_L = 3; + CYC_SHIFT = 1; + CYC_RESET = 130; + return; + case M68K_CPU_TYPE_68EC020: + CPU_TYPE = CPU_TYPE_EC020; + CPU_ADDRESS_MASK = 0x00ffffff; + CPU_SR_MASK = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */ + CYC_INSTRUCTION = m68ki_cycles[2]; + CYC_EXCEPTION = m68ki_exception_cycle_table[2]; + CYC_BCC_NOTAKE_B = -2; + CYC_BCC_NOTAKE_W = 0; + CYC_DBCC_F_NOEXP = 0; + CYC_DBCC_F_EXP = 4; + CYC_SCC_R_TRUE = 0; + CYC_MOVEM_W = 2; + CYC_MOVEM_L = 2; + CYC_SHIFT = 0; + CYC_RESET = 518; + return; + case M68K_CPU_TYPE_68020: + CPU_TYPE = CPU_TYPE_020; + CPU_ADDRESS_MASK = 0xffffffff; + CPU_SR_MASK = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */ + CYC_INSTRUCTION = m68ki_cycles[2]; + CYC_EXCEPTION = m68ki_exception_cycle_table[2]; + CYC_BCC_NOTAKE_B = -2; + CYC_BCC_NOTAKE_W = 0; + CYC_DBCC_F_NOEXP = 0; + CYC_DBCC_F_EXP = 4; + CYC_SCC_R_TRUE = 0; + CYC_MOVEM_W = 2; + CYC_MOVEM_L = 2; + CYC_SHIFT = 0; + CYC_RESET = 518; + return; + case M68K_CPU_TYPE_68040: // TODO: these values are not correct + CPU_TYPE = CPU_TYPE_040; + CPU_ADDRESS_MASK = 0xffffffff; + CPU_SR_MASK = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */ + CYC_INSTRUCTION = m68ki_cycles[2]; + CYC_EXCEPTION = m68ki_exception_cycle_table[2]; + CYC_BCC_NOTAKE_B = -2; + CYC_BCC_NOTAKE_W = 0; + CYC_DBCC_F_NOEXP = 0; + CYC_DBCC_F_EXP = 4; + CYC_SCC_R_TRUE = 0; + CYC_MOVEM_W = 2; + CYC_MOVEM_L = 2; + CYC_SHIFT = 0; + CYC_RESET = 518; + return; + } +} + +/* Execute some instructions until we use up num_cycles clock cycles */ +/* ASG: removed per-instruction interrupt checks */ +int m68k_execute(int num_cycles) +{ + /* Make sure we're not stopped */ + if(!CPU_STOPPED) + { + /* Set our pool of clock cycles available */ + SET_CYCLES(num_cycles); + m68ki_initial_cycles = num_cycles; + + /* ASG: update cycles */ + USE_CYCLES(CPU_INT_CYCLES); + CPU_INT_CYCLES = 0; + + /* Return point if we had an address error */ + m68ki_set_address_error_trap(); /* auto-disable (see m68kcpu.h) */ + + /* Main loop. Keep going until we run out of clock cycles */ + while(GET_CYCLES() > 0) + { + /* Set tracing accodring to T1. (T0 is done inside instruction) */ + m68ki_trace_t1(); /* auto-disable (see m68kcpu.h) */ + + /* Set the address space for reads */ + m68ki_use_data_space(); /* auto-disable (see m68kcpu.h) */ + + /* Call external hook to peek at CPU */ + m68ki_instr_hook(); /* auto-disable (see m68kcpu.h) */ + + /* Record previous program counter */ + REG_PPC = REG_PC; + + /* Read an instruction and call its handler */ + REG_IR = m68ki_read_imm_16(); + m68ki_instruction_jump_table[REG_IR](); + USE_CYCLES(CYC_INSTRUCTION[REG_IR]); + + /* Trace m68k_exception, if necessary */ + m68ki_exception_if_trace(); /* auto-disable (see m68kcpu.h) */ + } + + /* set previous PC to current PC for the next entry into the loop */ + REG_PPC = REG_PC; + + /* ASG: update cycles */ + USE_CYCLES(CPU_INT_CYCLES); + CPU_INT_CYCLES = 0; + + /* return how many clocks we used */ + return m68ki_initial_cycles - GET_CYCLES(); + } + + /* We get here if the CPU is stopped or halted */ + SET_CYCLES(0); + CPU_INT_CYCLES = 0; + + return num_cycles; +} + + +int m68k_cycles_run(void) +{ + return m68ki_initial_cycles - GET_CYCLES(); +} + +int m68k_cycles_remaining(void) +{ + return GET_CYCLES(); +} + +/* Change the timeslice */ +void m68k_modify_timeslice(int cycles) +{ + m68ki_initial_cycles += cycles; + ADD_CYCLES(cycles); +} + + +void m68k_end_timeslice(void) +{ + m68ki_initial_cycles = GET_CYCLES(); + SET_CYCLES(0); +} + + +/* ASG: rewrote so that the int_level is a mask of the IPL0/IPL1/IPL2 bits */ +/* KS: Modified so that IPL* bits match with mask positions in the SR + * and cleaned out remenants of the interrupt controller. + */ +void m68k_set_irq(unsigned int int_level) +{ + uint old_level = CPU_INT_LEVEL; + CPU_INT_LEVEL = int_level << 8; + + /* A transition from < 7 to 7 always interrupts (NMI) */ + /* Note: Level 7 can also level trigger like a normal IRQ */ + if(old_level != 0x0700 && CPU_INT_LEVEL == 0x0700) + m68ki_exception_interrupt(7); /* Edge triggered level 7 (NMI) */ + else + m68ki_check_interrupts(); /* Level triggered (IRQ) */ +} + +void m68k_init(void) +{ + static uint emulation_initialized = 0; + + /* The first call to this function initializes the opcode handler jump table */ + if(!emulation_initialized) + { + m68ki_build_opcode_table(); + emulation_initialized = 1; + } + + m68k_set_int_ack_callback(NULL); + m68k_set_bkpt_ack_callback(NULL); + m68k_set_reset_instr_callback(NULL); + m68k_set_cmpild_instr_callback(NULL); + m68k_set_rte_instr_callback(NULL); + m68k_set_pc_changed_callback(NULL); + m68k_set_fc_callback(NULL); + m68k_set_instr_hook_callback(NULL); +} + +/* Pulse the RESET line on the CPU */ +void m68k_pulse_reset(void) +{ + /* Clear all stop levels and eat up all remaining cycles */ + CPU_STOPPED = 0; + SET_CYCLES(0); + + CPU_RUN_MODE = RUN_MODE_BERR_AERR_RESET; + + /* Turn off tracing */ + FLAG_T1 = FLAG_T0 = 0; + m68ki_clear_trace(); + /* Interrupt mask to level 7 */ + FLAG_INT_MASK = 0x0700; + /* Reset VBR */ + REG_VBR = 0; + /* Go to supervisor mode */ + m68ki_set_sm_flag(SFLAG_SET | MFLAG_CLEAR); + + /* Invalidate the prefetch queue */ +#if M68K_EMULATE_PREFETCH + /* Set to arbitrary number since our first fetch is from 0 */ + CPU_PREF_ADDR = 0x1000; +#endif /* M68K_EMULATE_PREFETCH */ + + /* Read the initial stack pointer and program counter */ + m68ki_jump(0); + REG_SP = m68ki_read_imm_32(); + REG_PC = m68ki_read_imm_32(); + m68ki_jump(REG_PC); + + CPU_RUN_MODE = RUN_MODE_NORMAL; +} + +/* Pulse the HALT line on the CPU */ +void m68k_pulse_halt(void) +{ + CPU_STOPPED |= STOP_LEVEL_HALT; +} + + +/* Get and set the current CPU context */ +/* This is to allow for multiple CPUs */ +unsigned int m68k_context_size() +{ + return sizeof(m68ki_cpu_core); +} + +/* +unsigned int m68k_get_context(void* dst) +{ + if(dst) *(m68ki_cpu_core*)dst = m68ki_cpu; + return sizeof(m68ki_cpu_core); +} +*/ + +void m68k_set_context(void* src) +{ + if(src) m68ki_cpu_p = src; +} + + + +/* ======================================================================== */ +/* ============================== MAME STUFF ============================== */ +/* ======================================================================== */ + +#if M68K_COMPILE_FOR_MAME == OPT_ON + +#include "state.h" + +static struct { + UINT16 sr; + UINT8 stopped; + UINT8 halted; +} m68k_substate; + +static void m68k_prepare_substate(void) +{ + m68k_substate.sr = m68ki_get_sr(); + m68k_substate.stopped = (CPU_STOPPED & STOP_LEVEL_STOP) != 0; + m68k_substate.halted = (CPU_STOPPED & STOP_LEVEL_HALT) != 0; +} + +static void m68k_post_load(void) +{ + m68ki_set_sr_noint_nosp(m68k_substate.sr); + CPU_STOPPED = m68k_substate.stopped ? STOP_LEVEL_STOP : 0 + | m68k_substate.halted ? STOP_LEVEL_HALT : 0; + m68ki_jump(REG_PC); +} + +void m68k_state_register(const char *type, int index) +{ + state_save_register_item_array(type, index, REG_D); + state_save_register_item_array(type, index, REG_A); + state_save_register_item(type, index, REG_PPC); + state_save_register_item(type, index, REG_PC); + state_save_register_item(type, index, REG_USP); + state_save_register_item(type, index, REG_ISP); + state_save_register_item(type, index, REG_MSP); + state_save_register_item(type, index, REG_VBR); + state_save_register_item(type, index, REG_SFC); + state_save_register_item(type, index, REG_DFC); + state_save_register_item(type, index, REG_CACR); + state_save_register_item(type, index, REG_CAAR); + state_save_register_item(type, index, m68k_substate.sr); + state_save_register_item(type, index, CPU_INT_LEVEL); + state_save_register_item(type, index, CPU_INT_CYCLES); + state_save_register_item(type, index, m68k_substate.stopped); + state_save_register_item(type, index, m68k_substate.halted); + state_save_register_item(type, index, CPU_PREF_ADDR); + state_save_register_item(type, index, CPU_PREF_DATA); + state_save_register_func_presave(m68k_prepare_substate); + state_save_register_func_postload(m68k_post_load); +} + +#endif /* M68K_COMPILE_FOR_MAME */ + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ diff --git a/cpu/musashi/m68kcpu.h b/cpu/musashi/m68kcpu.h new file mode 100644 index 00000000..88855956 --- /dev/null +++ b/cpu/musashi/m68kcpu.h @@ -0,0 +1,2022 @@ +#include +/* ======================================================================== */ +/* ========================= LICENSING & COPYRIGHT ======================== */ +/* ======================================================================== */ +/* + * MUSASHI + * Version 3.3 + * + * A portable Motorola M680x0 processor emulation engine. + * Copyright 1998-2001 Karl Stenerud. All rights reserved. + * + * This code may be freely used for non-commercial purposes as long as this + * copyright notice remains unaltered in the source code and any binary files + * containing this code in compiled form. + * + * All other lisencing terms must be negotiated with the author + * (Karl Stenerud). + * + * The latest version of this code can be obtained at: + * http://kstenerud.cjb.net + */ + + + + +#ifndef M68KCPU__HEADER +#define M68KCPU__HEADER + +// notaz: something's missing this +#ifndef UINT16 +#define UINT32 unsigned int +#define UINT16 unsigned short +#define UINT8 unsigned char +#endif + +#include "m68k.h" +#include + +#if M68K_EMULATE_ADDRESS_ERROR +#include +#endif /* M68K_EMULATE_ADDRESS_ERROR */ + +/* ======================================================================== */ +/* ==================== ARCHITECTURE-DEPENDANT DEFINES ==================== */ +/* ======================================================================== */ + +/* Check for > 32bit sizes */ +#if UINT_MAX > 0xffffffff + #define M68K_INT_GT_32_BIT 1 +#else + #define M68K_INT_GT_32_BIT 0 +#endif + +/* Data types used in this emulation core */ +#undef sint8 +#undef sint16 +#undef sint32 +#undef sint64 +#undef uint8 +#undef uint16 +#undef uint32 +#undef uint64 +#undef sint +#undef uint + +#define sint8 signed char /* ASG: changed from char to signed char */ +#define sint16 signed short +#define sint32 signed long +#define uint8 unsigned char +#define uint16 unsigned short +#define uint32 unsigned long + +/* signed and unsigned int must be at least 32 bits wide */ +#define sint signed int +#define uint unsigned int + + +#if M68K_USE_64_BIT +#define sint64 signed long long +#define uint64 unsigned long long +#else +#define sint64 sint32 +#define uint64 uint32 +#endif /* M68K_USE_64_BIT */ + + + +/* Allow for architectures that don't have 8-bit sizes */ +#if UCHAR_MAX == 0xff + #define MAKE_INT_8(A) (sint8)(A) +#else + #undef sint8 + #define sint8 signed int + #undef uint8 + #define uint8 unsigned int + INLINE sint MAKE_INT_8(uint value) + { + return (value & 0x80) ? value | ~0xff : value & 0xff; + } +#endif /* UCHAR_MAX == 0xff */ + + +/* Allow for architectures that don't have 16-bit sizes */ +#if USHRT_MAX == 0xffff + #define MAKE_INT_16(A) (sint16)(A) +#else + #undef sint16 + #define sint16 signed int + #undef uint16 + #define uint16 unsigned int + INLINE sint MAKE_INT_16(uint value) + { + return (value & 0x8000) ? value | ~0xffff : value & 0xffff; + } +#endif /* USHRT_MAX == 0xffff */ + + +/* Allow for architectures that don't have 32-bit sizes */ +#if ULONG_MAX == 0xffffffff + #define MAKE_INT_32(A) (sint32)(A) +#else + #undef sint32 + #define sint32 signed int + #undef uint32 + #define uint32 unsigned int + INLINE sint MAKE_INT_32(uint value) + { + return (value & 0x80000000) ? value | ~0xffffffff : value & 0xffffffff; + } +#endif /* ULONG_MAX == 0xffffffff */ + +// notaz +INLINE sint32 MAKE_INT_24(uint value) +{ + return (value & 0x800000) ? value | ~0xffffff : value & 0xffffff; +} + + + +/* ======================================================================== */ +/* ============================ GENERAL DEFINES =========================== */ +/* ======================================================================== */ + +/* Exception Vectors handled by emulation */ +#define EXCEPTION_BUS_ERROR 2 /* This one is not emulated! */ +#define EXCEPTION_ADDRESS_ERROR 3 /* This one is partially emulated (doesn't stack a proper frame yet) */ +#define EXCEPTION_ILLEGAL_INSTRUCTION 4 +#define EXCEPTION_ZERO_DIVIDE 5 +#define EXCEPTION_CHK 6 +#define EXCEPTION_TRAPV 7 +#define EXCEPTION_PRIVILEGE_VIOLATION 8 +#define EXCEPTION_TRACE 9 +#define EXCEPTION_1010 10 +#define EXCEPTION_1111 11 +#define EXCEPTION_FORMAT_ERROR 14 +#define EXCEPTION_UNINITIALIZED_INTERRUPT 15 +#define EXCEPTION_SPURIOUS_INTERRUPT 24 +#define EXCEPTION_INTERRUPT_AUTOVECTOR 24 +#define EXCEPTION_TRAP_BASE 32 + +/* Function codes set by CPU during data/address bus activity */ +#define FUNCTION_CODE_USER_DATA 1 +#define FUNCTION_CODE_USER_PROGRAM 2 +#define FUNCTION_CODE_SUPERVISOR_DATA 5 +#define FUNCTION_CODE_SUPERVISOR_PROGRAM 6 +#define FUNCTION_CODE_CPU_SPACE 7 + +/* CPU types for deciding what to emulate */ +#define CPU_TYPE_000 1 +#define CPU_TYPE_008 2 +#define CPU_TYPE_010 4 +#define CPU_TYPE_EC020 8 +#define CPU_TYPE_020 16 +#define CPU_TYPE_040 32 + +/* Different ways to stop the CPU */ +#define STOP_LEVEL_STOP 1 +#define STOP_LEVEL_HALT 2 + +/* Used for 68000 address error processing */ +#define INSTRUCTION_YES 0 +#define INSTRUCTION_NO 0x08 +#define MODE_READ 0x10 +#define MODE_WRITE 0 + +#define RUN_MODE_NORMAL 0 +#define RUN_MODE_BERR_AERR_RESET 1 + +#ifndef NULL +#define NULL ((void*)0) +#endif + +/* ======================================================================== */ +/* ================================ MACROS ================================ */ +/* ======================================================================== */ + + +/* ---------------------------- General Macros ---------------------------- */ + +/* Bit Isolation Macros */ +#define BIT_0(A) ((A) & 0x00000001) +#define BIT_1(A) ((A) & 0x00000002) +#define BIT_2(A) ((A) & 0x00000004) +#define BIT_3(A) ((A) & 0x00000008) +#define BIT_4(A) ((A) & 0x00000010) +#define BIT_5(A) ((A) & 0x00000020) +#define BIT_6(A) ((A) & 0x00000040) +#define BIT_7(A) ((A) & 0x00000080) +#define BIT_8(A) ((A) & 0x00000100) +#define BIT_9(A) ((A) & 0x00000200) +#define BIT_A(A) ((A) & 0x00000400) +#define BIT_B(A) ((A) & 0x00000800) +#define BIT_C(A) ((A) & 0x00001000) +#define BIT_D(A) ((A) & 0x00002000) +#define BIT_E(A) ((A) & 0x00004000) +#define BIT_F(A) ((A) & 0x00008000) +#define BIT_10(A) ((A) & 0x00010000) +#define BIT_11(A) ((A) & 0x00020000) +#define BIT_12(A) ((A) & 0x00040000) +#define BIT_13(A) ((A) & 0x00080000) +#define BIT_14(A) ((A) & 0x00100000) +#define BIT_15(A) ((A) & 0x00200000) +#define BIT_16(A) ((A) & 0x00400000) +#define BIT_17(A) ((A) & 0x00800000) +#define BIT_18(A) ((A) & 0x01000000) +#define BIT_19(A) ((A) & 0x02000000) +#define BIT_1A(A) ((A) & 0x04000000) +#define BIT_1B(A) ((A) & 0x08000000) +#define BIT_1C(A) ((A) & 0x10000000) +#define BIT_1D(A) ((A) & 0x20000000) +#define BIT_1E(A) ((A) & 0x40000000) +#define BIT_1F(A) ((A) & 0x80000000) + +/* Get the most significant bit for specific sizes */ +#define GET_MSB_8(A) ((A) & 0x80) +#define GET_MSB_9(A) ((A) & 0x100) +#define GET_MSB_16(A) ((A) & 0x8000) +#define GET_MSB_17(A) ((A) & 0x10000) +#define GET_MSB_32(A) ((A) & 0x80000000) +#if M68K_USE_64_BIT +#define GET_MSB_33(A) ((A) & 0x100000000) +#endif /* M68K_USE_64_BIT */ + +/* Isolate nibbles */ +#define LOW_NIBBLE(A) ((A) & 0x0f) +#define HIGH_NIBBLE(A) ((A) & 0xf0) + +/* These are used to isolate 8, 16, and 32 bit sizes */ +#define MASK_OUT_ABOVE_2(A) ((A) & 3) +#define MASK_OUT_ABOVE_8(A) ((A) & 0xff) +#define MASK_OUT_ABOVE_16(A) ((A) & 0xffff) +#define MASK_OUT_BELOW_2(A) ((A) & ~3) +#define MASK_OUT_BELOW_8(A) ((A) & ~0xff) +#define MASK_OUT_BELOW_16(A) ((A) & ~0xffff) + +/* No need to mask if we are 32 bit */ +#if M68K_INT_GT_32_BIT || M68K_USE_64_BIT + #define MASK_OUT_ABOVE_32(A) ((A) & 0xffffffff) + #define MASK_OUT_BELOW_32(A) ((A) & ~0xffffffff) +#else + #define MASK_OUT_ABOVE_32(A) (A) + #define MASK_OUT_BELOW_32(A) 0 +#endif /* M68K_INT_GT_32_BIT || M68K_USE_64_BIT */ + +/* Simulate address lines of 68k family */ +#define ADDRESS_68K(A) ((A)&CPU_ADDRESS_MASK) + + +/* Shift & Rotate Macros. */ +#define LSL(A, C) ((A) << (C)) +#define LSR(A, C) ((A) >> (C)) + +/* Some > 32-bit optimizations */ +#if M68K_INT_GT_32_BIT + /* Shift left and right */ + #define LSR_32(A, C) ((A) >> (C)) + #define LSL_32(A, C) ((A) << (C)) +#else + /* We have to do this because the morons at ANSI decided that shifts + * by >= data size are undefined. + */ + #define LSR_32(A, C) ((C) < 32 ? (A) >> (C) : 0) + #define LSL_32(A, C) ((C) < 32 ? (A) << (C) : 0) +#endif /* M68K_INT_GT_32_BIT */ + +#if M68K_USE_64_BIT + #define LSL_32_64(A, C) ((A) << (C)) + #define LSR_32_64(A, C) ((A) >> (C)) + #define ROL_33_64(A, C) (LSL_32_64(A, C) | LSR_32_64(A, 33-(C))) + #define ROR_33_64(A, C) (LSR_32_64(A, C) | LSL_32_64(A, 33-(C))) +#endif /* M68K_USE_64_BIT */ + +#define ROL_8(A, C) MASK_OUT_ABOVE_8(LSL(A, C) | LSR(A, 8-(C))) +#define ROL_9(A, C) (LSL(A, C) | LSR(A, 9-(C))) +#define ROL_16(A, C) MASK_OUT_ABOVE_16(LSL(A, C) | LSR(A, 16-(C))) +#define ROL_17(A, C) (LSL(A, C) | LSR(A, 17-(C))) +#define ROL_32(A, C) MASK_OUT_ABOVE_32(LSL_32(A, C) | LSR_32(A, 32-(C))) +#define ROL_33(A, C) (LSL_32(A, C) | LSR_32(A, 33-(C))) + +#define ROR_8(A, C) MASK_OUT_ABOVE_8(LSR(A, C) | LSL(A, 8-(C))) +#define ROR_9(A, C) (LSR(A, C) | LSL(A, 9-(C))) +#define ROR_16(A, C) MASK_OUT_ABOVE_16(LSR(A, C) | LSL(A, 16-(C))) +#define ROR_17(A, C) (LSR(A, C) | LSL(A, 17-(C))) +#define ROR_32(A, C) MASK_OUT_ABOVE_32(LSR_32(A, C) | LSL_32(A, 32-(C))) +#define ROR_33(A, C) (LSR_32(A, C) | LSL_32(A, 33-(C))) + + + +/* ------------------------------ CPU Access ------------------------------ */ + +/* Access the CPU registers */ +#define CPU_TYPE m68ki_cpu.cpu_type + +#define REG_DA m68ki_cpu.dar /* easy access to data and address regs */ +#define REG_D m68ki_cpu.dar +#define REG_A (m68ki_cpu.dar+8) +#define REG_PPC m68ki_cpu.ppc +#define REG_PC m68ki_cpu.pc +#define REG_SP_BASE m68ki_cpu.sp +#define REG_USP m68ki_cpu.sp[0] +#define REG_ISP m68ki_cpu.sp[4] +#define REG_MSP m68ki_cpu.sp[6] +#define REG_SP m68ki_cpu.dar[15] +#define REG_VBR m68ki_cpu.vbr +#define REG_SFC m68ki_cpu.sfc +#define REG_DFC m68ki_cpu.dfc +#define REG_CACR m68ki_cpu.cacr +#define REG_CAAR m68ki_cpu.caar +#define REG_IR m68ki_cpu.ir + +#define FLAG_T1 m68ki_cpu.t1_flag +#define FLAG_T0 m68ki_cpu.t0_flag +#define FLAG_S m68ki_cpu.s_flag +#define FLAG_M m68ki_cpu.m_flag +#define FLAG_X m68ki_cpu.x_flag +#define FLAG_N m68ki_cpu.n_flag +#define FLAG_Z m68ki_cpu.not_z_flag +#define FLAG_V m68ki_cpu.v_flag +#define FLAG_C m68ki_cpu.c_flag +#define FLAG_INT_MASK m68ki_cpu.int_mask + +#define CPU_INT_LEVEL m68ki_cpu.int_level /* ASG: changed from CPU_INTS_PENDING */ +#define CPU_INT_CYCLES m68ki_cpu.int_cycles /* ASG */ +#define CPU_STOPPED m68ki_cpu.stopped +#define CPU_PREF_ADDR m68ki_cpu.pref_addr +#define CPU_PREF_DATA m68ki_cpu.pref_data +#define CPU_ADDRESS_MASK m68ki_cpu.address_mask +#define CPU_SR_MASK m68ki_cpu.sr_mask +#define CPU_INSTR_MODE m68ki_cpu.instr_mode +#define CPU_RUN_MODE m68ki_cpu.run_mode + +#define CYC_INSTRUCTION m68ki_cpu.cyc_instruction +#define CYC_EXCEPTION m68ki_cpu.cyc_exception +#define CYC_BCC_NOTAKE_B m68ki_cpu.cyc_bcc_notake_b +#define CYC_BCC_NOTAKE_W m68ki_cpu.cyc_bcc_notake_w +#define CYC_DBCC_F_NOEXP m68ki_cpu.cyc_dbcc_f_noexp +#define CYC_DBCC_F_EXP m68ki_cpu.cyc_dbcc_f_exp +#define CYC_SCC_R_TRUE m68ki_cpu.cyc_scc_r_true +#define CYC_MOVEM_W m68ki_cpu.cyc_movem_w +#define CYC_MOVEM_L m68ki_cpu.cyc_movem_l +#define CYC_SHIFT m68ki_cpu.cyc_shift +#define CYC_RESET m68ki_cpu.cyc_reset + + +#define CALLBACK_INT_ACK m68ki_cpu.int_ack_callback +#define CALLBACK_BKPT_ACK m68ki_cpu.bkpt_ack_callback +#define CALLBACK_RESET_INSTR m68ki_cpu.reset_instr_callback +#define CALLBACK_CMPILD_INSTR m68ki_cpu.cmpild_instr_callback +#define CALLBACK_RTE_INSTR m68ki_cpu.rte_instr_callback +#define CALLBACK_PC_CHANGED m68ki_cpu.pc_changed_callback +#define CALLBACK_SET_FC m68ki_cpu.set_fc_callback +#define CALLBACK_INSTR_HOOK m68ki_cpu.instr_hook_callback + + + +/* ----------------------------- Configuration ---------------------------- */ + +/* These defines are dependant on the configuration defines in m68kconf.h */ + +/* Disable certain comparisons if we're not using all CPU types */ +#if M68K_EMULATE_040 + #define CPU_TYPE_IS_040_PLUS(A) ((A) & CPU_TYPE_040) + #define CPU_TYPE_IS_040_LESS(A) 1 +#else + #define CPU_TYPE_IS_040_PLUS(A) 0 + #define CPU_TYPE_IS_040_LESS(A) 1 +#endif + +#if M68K_EMULATE_020 + #define CPU_TYPE_IS_020_PLUS(A) ((A) & (CPU_TYPE_020 | CPU_TYPE_040)) + #define CPU_TYPE_IS_020_LESS(A) 1 +#else + #define CPU_TYPE_IS_020_PLUS(A) 0 + #define CPU_TYPE_IS_020_LESS(A) 1 +#endif + +#if M68K_EMULATE_EC020 + #define CPU_TYPE_IS_EC020_PLUS(A) ((A) & (CPU_TYPE_EC020 | CPU_TYPE_020 | CPU_TYPE_040)) + #define CPU_TYPE_IS_EC020_LESS(A) ((A) & (CPU_TYPE_000 | CPU_TYPE_008 | CPU_TYPE_010 | CPU_TYPE_EC020)) +#else + #define CPU_TYPE_IS_EC020_PLUS(A) CPU_TYPE_IS_020_PLUS(A) + #define CPU_TYPE_IS_EC020_LESS(A) CPU_TYPE_IS_020_LESS(A) +#endif + +#if M68K_EMULATE_010 + #define CPU_TYPE_IS_010(A) ((A) == CPU_TYPE_010) + #define CPU_TYPE_IS_010_PLUS(A) ((A) & (CPU_TYPE_010 | CPU_TYPE_EC020 | CPU_TYPE_020 | CPU_TYPE_040)) + #define CPU_TYPE_IS_010_LESS(A) ((A) & (CPU_TYPE_000 | CPU_TYPE_008 | CPU_TYPE_010)) +#else + #define CPU_TYPE_IS_010(A) 0 + #define CPU_TYPE_IS_010_PLUS(A) CPU_TYPE_IS_EC020_PLUS(A) + #define CPU_TYPE_IS_010_LESS(A) CPU_TYPE_IS_EC020_LESS(A) +#endif + +#if M68K_EMULATE_020 || M68K_EMULATE_EC020 + #define CPU_TYPE_IS_020_VARIANT(A) ((A) & (CPU_TYPE_EC020 | CPU_TYPE_020)) +#else + #define CPU_TYPE_IS_020_VARIANT(A) 0 +#endif + +#if M68K_EMULATE_040 || M68K_EMULATE_020 || M68K_EMULATE_EC020 || M68K_EMULATE_010 + #define CPU_TYPE_IS_000(A) ((A) == CPU_TYPE_000 || (A) == CPU_TYPE_008) +#else + #define CPU_TYPE_IS_000(A) 1 +#endif + + +#if !M68K_SEPARATE_READS +#define m68k_read_immediate_16(A) m68ki_read_program_16(A) +#define m68k_read_immediate_32(A) m68ki_read_program_32(A) + +#define m68k_read_pcrelative_8(A) m68ki_read_program_8(A) +#define m68k_read_pcrelative_16(A) m68ki_read_program_16(A) +#define m68k_read_pcrelative_32(A) m68ki_read_program_32(A) +#endif /* M68K_SEPARATE_READS */ + + +/* Enable or disable callback functions */ +#if M68K_EMULATE_INT_ACK + #if M68K_EMULATE_INT_ACK == OPT_SPECIFY_HANDLER + #define m68ki_int_ack(A) M68K_INT_ACK_CALLBACK(A) + #else + #define m68ki_int_ack(A) CALLBACK_INT_ACK(A) + #endif +#else + /* Default action is to used autovector mode, which is most common */ + #define m68ki_int_ack(A) M68K_INT_ACK_AUTOVECTOR +#endif /* M68K_EMULATE_INT_ACK */ + +#if M68K_EMULATE_BKPT_ACK + #if M68K_EMULATE_BKPT_ACK == OPT_SPECIFY_HANDLER + #define m68ki_bkpt_ack(A) M68K_BKPT_ACK_CALLBACK(A) + #else + #define m68ki_bkpt_ack(A) CALLBACK_BKPT_ACK(A) + #endif +#else + #define m68ki_bkpt_ack(A) +#endif /* M68K_EMULATE_BKPT_ACK */ + +#if M68K_EMULATE_RESET + #if M68K_EMULATE_RESET == OPT_SPECIFY_HANDLER + #define m68ki_output_reset() M68K_RESET_CALLBACK() + #else + #define m68ki_output_reset() CALLBACK_RESET_INSTR() + #endif +#else + #define m68ki_output_reset() +#endif /* M68K_EMULATE_RESET */ + +#if M68K_CMPILD_HAS_CALLBACK + #if M68K_CMPILD_HAS_CALLBACK == OPT_SPECIFY_HANDLER + #define m68ki_cmpild_callback(v,r) M68K_CMPILD_CALLBACK(v,r) + #else + #define m68ki_cmpild_callback(v,r) CALLBACK_CMPILD_INSTR(v,r) + #endif +#else + #define m68ki_cmpild_callback(v,r) +#endif /* M68K_CMPILD_HAS_CALLBACK */ + +#if M68K_RTE_HAS_CALLBACK + #if M68K_RTE_HAS_CALLBACK == OPT_SPECIFY_HANDLER + #define m68ki_rte_callback() M68K_RTE_CALLBACK() + #else + #define m68ki_rte_callback() CALLBACK_RTE_INSTR() + #endif +#else + #define m68ki_rte_callback() +#endif /* M68K_RTE_HAS_CALLBACK */ + +#if M68K_INSTRUCTION_HOOK + #if M68K_INSTRUCTION_HOOK == OPT_SPECIFY_HANDLER + #define m68ki_instr_hook() M68K_INSTRUCTION_CALLBACK() + #else + #define m68ki_instr_hook() CALLBACK_INSTR_HOOK() + #endif +#else + #define m68ki_instr_hook() +#endif /* M68K_INSTRUCTION_HOOK */ + +#if M68K_MONITOR_PC + #if M68K_MONITOR_PC == OPT_SPECIFY_HANDLER + #define m68ki_pc_changed(A) M68K_SET_PC_CALLBACK(ADDRESS_68K(A)) + #else + #define m68ki_pc_changed(A) CALLBACK_PC_CHANGED(ADDRESS_68K(A)) + #endif +#else + #define m68ki_pc_changed(A) +#endif /* M68K_MONITOR_PC */ + + +/* Enable or disable function code emulation */ +#if M68K_EMULATE_FC + #if M68K_EMULATE_FC == OPT_SPECIFY_HANDLER + #define m68ki_set_fc(A) M68K_SET_FC_CALLBACK(A) + #else + #define m68ki_set_fc(A) CALLBACK_SET_FC(A) + #endif + #define m68ki_use_data_space() m68ki_address_space = FUNCTION_CODE_USER_DATA + #define m68ki_use_program_space() m68ki_address_space = FUNCTION_CODE_USER_PROGRAM + #define m68ki_get_address_space() m68ki_address_space +#else + #define m68ki_set_fc(A) + #define m68ki_use_data_space() + #define m68ki_use_program_space() + #define m68ki_get_address_space() FUNCTION_CODE_USER_DATA +#endif /* M68K_EMULATE_FC */ + + +/* Enable or disable trace emulation */ +#if M68K_EMULATE_TRACE + /* Initiates trace checking before each instruction (t1) */ + #define m68ki_trace_t1() m68ki_tracing = FLAG_T1 + /* adds t0 to trace checking if we encounter change of flow */ + #define m68ki_trace_t0() m68ki_tracing |= FLAG_T0 + /* Clear all tracing */ + #define m68ki_clear_trace() m68ki_tracing = 0 + /* Cause a trace exception if we are tracing */ + #define m68ki_exception_if_trace() if(m68ki_tracing) m68ki_exception_trace() +#else + #define m68ki_trace_t1() + #define m68ki_trace_t0() + #define m68ki_clear_trace() + #define m68ki_exception_if_trace() +#endif /* M68K_EMULATE_TRACE */ + + + +/* Address error */ +#if M68K_EMULATE_ADDRESS_ERROR + #include + extern jmp_buf m68ki_aerr_trap; + + #define m68ki_set_address_error_trap() \ + if(setjmp(m68ki_aerr_trap) != 0) \ + { \ + m68ki_exception_address_error(); \ + if(CPU_STOPPED) \ + { \ + SET_CYCLES(0); \ + CPU_INT_CYCLES = 0; \ + return m68ki_initial_cycles; \ + } \ + } + + #define m68ki_check_address_error(ADDR, WRITE_MODE, FC) \ + if((ADDR)&1) \ + { \ + m68ki_aerr_address = ADDR; \ + m68ki_aerr_write_mode = WRITE_MODE; \ + m68ki_aerr_fc = FC; \ + longjmp(m68ki_aerr_trap, 1); \ + } + + #define m68ki_check_address_error_010_less(ADDR, WRITE_MODE, FC) \ + if (CPU_TYPE_IS_010_LESS(CPU_TYPE)) \ + { \ + m68ki_check_address_error(ADDR, WRITE_MODE, FC) \ + } +#else + #define m68ki_set_address_error_trap() + #define m68ki_check_address_error(ADDR, WRITE_MODE, FC) + #define m68ki_check_address_error_010_less(ADDR, WRITE_MODE, FC) +#endif /* M68K_ADDRESS_ERROR */ + +/* Logging */ +#if M68K_LOG_ENABLE + #include + extern FILE* M68K_LOG_FILEHANDLE + extern char* m68ki_cpu_names[]; + + #define M68K_DO_LOG(A) if(M68K_LOG_FILEHANDLE) fprintf A + #if M68K_LOG_1010_1111 + #define M68K_DO_LOG_EMU(A) if(M68K_LOG_FILEHANDLE) fprintf A + #else + #define M68K_DO_LOG_EMU(A) + #endif +#else + #define M68K_DO_LOG(A) + #define M68K_DO_LOG_EMU(A) +#endif + + + +/* -------------------------- EA / Operand Access ------------------------- */ + +/* + * The general instruction format follows this pattern: + * .... XXX. .... .YYY + * where XXX is register X and YYY is register Y + */ +/* Data Register Isolation */ +#define DX (REG_D[(REG_IR >> 9) & 7]) +#define DY (REG_D[REG_IR & 7]) +/* Address Register Isolation */ +#define AX (REG_A[(REG_IR >> 9) & 7]) +#define AY (REG_A[REG_IR & 7]) + + +/* Effective Address Calculations */ +#define EA_AY_AI_8() AY /* address register indirect */ +#define EA_AY_AI_16() EA_AY_AI_8() +#define EA_AY_AI_32() EA_AY_AI_8() +#define EA_AY_PI_8() (AY++) /* postincrement (size = byte) */ +#define EA_AY_PI_16() ((AY+=2)-2) /* postincrement (size = word) */ +#define EA_AY_PI_32() ((AY+=4)-4) /* postincrement (size = long) */ +#define EA_AY_PD_8() (--AY) /* predecrement (size = byte) */ +#define EA_AY_PD_16() (AY-=2) /* predecrement (size = word) */ +#define EA_AY_PD_32() (AY-=4) /* predecrement (size = long) */ +#define EA_AY_DI_8() (AY+MAKE_INT_16(m68ki_read_imm_16())) /* displacement */ +#define EA_AY_DI_16() EA_AY_DI_8() +#define EA_AY_DI_32() EA_AY_DI_8() +#define EA_AY_IX_8() m68ki_get_ea_ix(AY) /* indirect + index */ +#define EA_AY_IX_16() EA_AY_IX_8() +#define EA_AY_IX_32() EA_AY_IX_8() + +#define EA_AX_AI_8() AX +#define EA_AX_AI_16() EA_AX_AI_8() +#define EA_AX_AI_32() EA_AX_AI_8() +#define EA_AX_PI_8() (AX++) +#define EA_AX_PI_16() ((AX+=2)-2) +#define EA_AX_PI_32() ((AX+=4)-4) +#define EA_AX_PD_8() (--AX) +#define EA_AX_PD_16() (AX-=2) +#define EA_AX_PD_32() (AX-=4) +#define EA_AX_DI_8() (AX+MAKE_INT_16(m68ki_read_imm_16())) +#define EA_AX_DI_16() EA_AX_DI_8() +#define EA_AX_DI_32() EA_AX_DI_8() +#define EA_AX_IX_8() m68ki_get_ea_ix(AX) +#define EA_AX_IX_16() EA_AX_IX_8() +#define EA_AX_IX_32() EA_AX_IX_8() + +#define EA_A7_PI_8() ((REG_A[7]+=2)-2) +#define EA_A7_PD_8() (REG_A[7]-=2) + +#define EA_AW_8() MAKE_INT_16(m68ki_read_imm_16()) /* absolute word */ +#define EA_AW_16() EA_AW_8() +#define EA_AW_32() EA_AW_8() +#define EA_AL_8() m68ki_read_imm_32() /* absolute long */ +#define EA_AL_16() EA_AL_8() +#define EA_AL_32() EA_AL_8() +#define EA_PCDI_8() m68ki_get_ea_pcdi() /* pc indirect + displacement */ +#define EA_PCDI_16() EA_PCDI_8() +#define EA_PCDI_32() EA_PCDI_8() +#define EA_PCIX_8() m68ki_get_ea_pcix() /* pc indirect + index */ +#define EA_PCIX_16() EA_PCIX_8() +#define EA_PCIX_32() EA_PCIX_8() + + +#define OPER_I_8() m68ki_read_imm_8() +#define OPER_I_16() m68ki_read_imm_16() +#define OPER_I_32() m68ki_read_imm_32() + + + +/* --------------------------- Status Register ---------------------------- */ + +/* Flag Calculation Macros */ +#define CFLAG_8(A) (A) +#define CFLAG_16(A) ((A)>>8) + +#if M68K_INT_GT_32_BIT + #define CFLAG_ADD_32(S, D, R) ((R)>>24) + #define CFLAG_SUB_32(S, D, R) ((R)>>24) +#else + #define CFLAG_ADD_32(S, D, R) (((S & D) | (~R & (S | D)))>>23) + #define CFLAG_SUB_32(S, D, R) (((S & R) | (~D & (S | R)))>>23) +#endif /* M68K_INT_GT_32_BIT */ + +#define VFLAG_ADD_8(S, D, R) ((S^R) & (D^R)) +#define VFLAG_ADD_16(S, D, R) (((S^R) & (D^R))>>8) +#define VFLAG_ADD_32(S, D, R) (((S^R) & (D^R))>>24) + +#define VFLAG_SUB_8(S, D, R) ((S^D) & (R^D)) +#define VFLAG_SUB_16(S, D, R) (((S^D) & (R^D))>>8) +#define VFLAG_SUB_32(S, D, R) (((S^D) & (R^D))>>24) + +#define NFLAG_8(A) (A) +#define NFLAG_16(A) ((A)>>8) +#define NFLAG_32(A) ((A)>>24) +#define NFLAG_64(A) ((A)>>56) + +#define ZFLAG_8(A) MASK_OUT_ABOVE_8(A) +#define ZFLAG_16(A) MASK_OUT_ABOVE_16(A) +#define ZFLAG_32(A) MASK_OUT_ABOVE_32(A) + + +/* Flag values */ +#define NFLAG_SET 0x80 +#define NFLAG_CLEAR 0 +#define CFLAG_SET 0x100 +#define CFLAG_CLEAR 0 +#define XFLAG_SET 0x100 +#define XFLAG_CLEAR 0 +#define VFLAG_SET 0x80 +#define VFLAG_CLEAR 0 +#define ZFLAG_SET 0 +#define ZFLAG_CLEAR 0xffffffff + +#define SFLAG_SET 4 +#define SFLAG_CLEAR 0 +#define MFLAG_SET 2 +#define MFLAG_CLEAR 0 + +/* Turn flag values into 1 or 0 */ +#define XFLAG_AS_1() ((FLAG_X>>8)&1) +#define NFLAG_AS_1() ((FLAG_N>>7)&1) +#define VFLAG_AS_1() ((FLAG_V>>7)&1) +#define ZFLAG_AS_1() (!FLAG_Z) +#define CFLAG_AS_1() ((FLAG_C>>8)&1) + + +/* Conditions */ +#define COND_CS() (FLAG_C&0x100) +#define COND_CC() (!COND_CS()) +#define COND_VS() (FLAG_V&0x80) +#define COND_VC() (!COND_VS()) +#define COND_NE() FLAG_Z +#define COND_EQ() (!COND_NE()) +#define COND_MI() (FLAG_N&0x80) +#define COND_PL() (!COND_MI()) +#define COND_LT() ((FLAG_N^FLAG_V)&0x80) +#define COND_GE() (!COND_LT()) +#define COND_HI() (COND_CC() && COND_NE()) +#define COND_LS() (COND_CS() || COND_EQ()) +#define COND_GT() (COND_GE() && COND_NE()) +#define COND_LE() (COND_LT() || COND_EQ()) + +/* Reversed conditions */ +#define COND_NOT_CS() COND_CC() +#define COND_NOT_CC() COND_CS() +#define COND_NOT_VS() COND_VC() +#define COND_NOT_VC() COND_VS() +#define COND_NOT_NE() COND_EQ() +#define COND_NOT_EQ() COND_NE() +#define COND_NOT_MI() COND_PL() +#define COND_NOT_PL() COND_MI() +#define COND_NOT_LT() COND_GE() +#define COND_NOT_GE() COND_LT() +#define COND_NOT_HI() COND_LS() +#define COND_NOT_LS() COND_HI() +#define COND_NOT_GT() COND_LE() +#define COND_NOT_LE() COND_GT() + +/* Not real conditions, but here for convenience */ +#define COND_XS() (FLAG_X&0x100) +#define COND_XC() (!COND_XS) + + +/* Get the condition code register */ +#define m68ki_get_ccr() ((COND_XS() >> 4) | \ + (COND_MI() >> 4) | \ + (COND_EQ() << 2) | \ + (COND_VS() >> 6) | \ + (COND_CS() >> 8)) + +/* Get the status register */ +#define m68ki_get_sr() ( FLAG_T1 | \ + FLAG_T0 | \ + (FLAG_S << 11) | \ + (FLAG_M << 11) | \ + FLAG_INT_MASK | \ + m68ki_get_ccr()) + + + +/* ---------------------------- Cycle Counting ---------------------------- */ + +#define ADD_CYCLES(A) m68ki_remaining_cycles += (A) +#define USE_CYCLES(A) m68ki_remaining_cycles -= (A) +#define SET_CYCLES(A) m68ki_remaining_cycles = A +#define GET_CYCLES() m68ki_remaining_cycles +#define USE_ALL_CYCLES() m68ki_remaining_cycles = 0 + + + +/* ----------------------------- Read / Write ----------------------------- */ + +/* Read from the current address space */ +#define m68ki_read_8(A) m68ki_read_8_fc (A, FLAG_S | m68ki_get_address_space()) +#define m68ki_read_16(A) m68ki_read_16_fc(A, FLAG_S | m68ki_get_address_space()) +#define m68ki_read_32(A) m68ki_read_32_fc(A, FLAG_S | m68ki_get_address_space()) + +/* Write to the current data space */ +#define m68ki_write_8(A, V) m68ki_write_8_fc (A, FLAG_S | FUNCTION_CODE_USER_DATA, V) +#define m68ki_write_16(A, V) m68ki_write_16_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA, V) +#define m68ki_write_32(A, V) m68ki_write_32_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA, V) + +#if M68K_SIMULATE_PD_WRITES +#define m68ki_write_32_pd(A, V) m68ki_write_32_pd_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA, V) +#else +#define m68ki_write_32_pd(A, V) m68ki_write_32_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA, V) +#endif + +/* map read immediate 8 to read immediate 16 */ +#define m68ki_read_imm_8() MASK_OUT_ABOVE_8(m68ki_read_imm_16()) + +/* Map PC-relative reads */ +#define m68ki_read_pcrel_8(A) m68k_read_pcrelative_8(A) +#define m68ki_read_pcrel_16(A) m68k_read_pcrelative_16(A) +#define m68ki_read_pcrel_32(A) m68k_read_pcrelative_32(A) + +/* Read from the program space */ +#define m68ki_read_program_8(A) m68ki_read_8_fc(A, FLAG_S | FUNCTION_CODE_USER_PROGRAM) +#define m68ki_read_program_16(A) m68ki_read_16_fc(A, FLAG_S | FUNCTION_CODE_USER_PROGRAM) +#define m68ki_read_program_32(A) m68ki_read_32_fc(A, FLAG_S | FUNCTION_CODE_USER_PROGRAM) + +/* Read from the data space */ +#define m68ki_read_data_8(A) m68ki_read_8_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA) +#define m68ki_read_data_16(A) m68ki_read_16_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA) +#define m68ki_read_data_32(A) m68ki_read_32_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA) + + + +/* ======================================================================== */ +/* =============================== PROTOTYPES ============================= */ +/* ======================================================================== */ + +typedef struct +{ + uint cpu_type; /* CPU Type: 68000, 68008, 68010, 68EC020, or 68020 */ + uint dar[16]; /* Data and Address Registers */ + uint ppc; /* Previous program counter */ + uint pc; /* Program Counter */ + uint sp[7]; /* User, Interrupt, and Master Stack Pointers */ + uint vbr; /* Vector Base Register (m68010+) */ + uint sfc; /* Source Function Code Register (m68010+) */ + uint dfc; /* Destination Function Code Register (m68010+) */ + uint cacr; /* Cache Control Register (m68020, unemulated) */ + uint caar; /* Cache Address Register (m68020, unemulated) */ + uint ir; /* Instruction Register */ + uint t1_flag; /* Trace 1 */ + uint t0_flag; /* Trace 0 */ + uint s_flag; /* Supervisor */ + uint m_flag; /* Master/Interrupt state */ + uint x_flag; /* Extend */ + uint n_flag; /* Negative */ + uint not_z_flag; /* Zero, inverted for speedups */ + uint v_flag; /* Overflow */ + uint c_flag; /* Carry */ + uint int_mask; /* I0-I2 */ + uint int_level; /* State of interrupt pins IPL0-IPL2 -- ASG: changed from ints_pending */ + uint int_cycles; /* ASG: extra cycles from generated interrupts */ + uint stopped; /* Stopped state */ + uint pref_addr; /* Last prefetch address */ + uint pref_data; /* Data in the prefetch queue */ + uint address_mask; /* Available address pins */ + uint sr_mask; /* Implemented status register bits */ + uint instr_mode; /* Stores whether we are in instruction mode or group 0/1 exception mode */ + uint run_mode; /* Stores whether we are processing a reset, bus error, address error, or something else */ + + /* Clocks required for instructions / exceptions */ + uint cyc_bcc_notake_b; + uint cyc_bcc_notake_w; + uint cyc_dbcc_f_noexp; + uint cyc_dbcc_f_exp; + uint cyc_scc_r_true; + uint cyc_movem_w; + uint cyc_movem_l; + uint cyc_shift; + uint cyc_reset; + uint8* cyc_instruction; + uint8* cyc_exception; + + /* Callbacks to host */ + int (*int_ack_callback)(int int_line); /* Interrupt Acknowledge */ + void (*bkpt_ack_callback)(unsigned int data); /* Breakpoint Acknowledge */ + void (*reset_instr_callback)(void); /* Called when a RESET instruction is encountered */ + void (*cmpild_instr_callback)(unsigned int, int); /* Called when a CMPI.L #v, Dn instruction is encountered */ + void (*rte_instr_callback)(void); /* Called when a RTE instruction is encountered */ + void (*pc_changed_callback)(unsigned int new_pc); /* Called when the PC changes by a large amount */ + void (*set_fc_callback)(unsigned int new_fc); /* Called when the CPU function code changes */ + void (*instr_hook_callback)(void); /* Called every instruction cycle prior to execution */ + +} m68ki_cpu_core; + + +extern m68ki_cpu_core *m68ki_cpu_p; +#define m68ki_cpu (*m68ki_cpu_p) // test + +extern sint m68ki_remaining_cycles; +extern uint m68ki_tracing; +extern uint8 m68ki_shift_8_table[]; +extern uint16 m68ki_shift_16_table[]; +extern uint m68ki_shift_32_table[]; +extern uint8 m68ki_exception_cycle_table[][256]; +extern uint m68ki_address_space; +extern uint8 m68ki_ea_idx_cycle_table[]; + +extern uint m68ki_aerr_address; +extern uint m68ki_aerr_write_mode; +extern uint m68ki_aerr_fc; + +/* Read data immediately after the program counter */ +INLINE uint m68ki_read_imm_16(void); +INLINE uint m68ki_read_imm_32(void); + +/* Read data with specific function code */ +INLINE uint m68ki_read_8_fc (uint address, uint fc); +INLINE uint m68ki_read_16_fc (uint address, uint fc); +INLINE uint m68ki_read_32_fc (uint address, uint fc); + +/* Write data with specific function code */ +INLINE void m68ki_write_8_fc (uint address, uint fc, uint value); +INLINE void m68ki_write_16_fc(uint address, uint fc, uint value); +INLINE void m68ki_write_32_fc(uint address, uint fc, uint value); +#if M68K_SIMULATE_PD_WRITES +INLINE void m68ki_write_32_pd_fc(uint address, uint fc, uint value); +#endif /* M68K_SIMULATE_PD_WRITES */ + +/* Indexed and PC-relative ea fetching */ +INLINE uint m68ki_get_ea_pcdi(void); +INLINE uint m68ki_get_ea_pcix(void); +INLINE uint m68ki_get_ea_ix(uint An); + +/* Operand fetching */ +INLINE uint OPER_AY_AI_8(void); +INLINE uint OPER_AY_AI_16(void); +INLINE uint OPER_AY_AI_32(void); +INLINE uint OPER_AY_PI_8(void); +INLINE uint OPER_AY_PI_16(void); +INLINE uint OPER_AY_PI_32(void); +INLINE uint OPER_AY_PD_8(void); +INLINE uint OPER_AY_PD_16(void); +INLINE uint OPER_AY_PD_32(void); +INLINE uint OPER_AY_DI_8(void); +INLINE uint OPER_AY_DI_16(void); +INLINE uint OPER_AY_DI_32(void); +INLINE uint OPER_AY_IX_8(void); +INLINE uint OPER_AY_IX_16(void); +INLINE uint OPER_AY_IX_32(void); + +INLINE uint OPER_AX_AI_8(void); +INLINE uint OPER_AX_AI_16(void); +INLINE uint OPER_AX_AI_32(void); +INLINE uint OPER_AX_PI_8(void); +INLINE uint OPER_AX_PI_16(void); +INLINE uint OPER_AX_PI_32(void); +INLINE uint OPER_AX_PD_8(void); +INLINE uint OPER_AX_PD_16(void); +INLINE uint OPER_AX_PD_32(void); +INLINE uint OPER_AX_DI_8(void); +INLINE uint OPER_AX_DI_16(void); +INLINE uint OPER_AX_DI_32(void); +INLINE uint OPER_AX_IX_8(void); +INLINE uint OPER_AX_IX_16(void); +INLINE uint OPER_AX_IX_32(void); + +INLINE uint OPER_A7_PI_8(void); +INLINE uint OPER_A7_PD_8(void); + +INLINE uint OPER_AW_8(void); +INLINE uint OPER_AW_16(void); +INLINE uint OPER_AW_32(void); +INLINE uint OPER_AL_8(void); +INLINE uint OPER_AL_16(void); +INLINE uint OPER_AL_32(void); +INLINE uint OPER_PCDI_8(void); +INLINE uint OPER_PCDI_16(void); +INLINE uint OPER_PCDI_32(void); +INLINE uint OPER_PCIX_8(void); +INLINE uint OPER_PCIX_16(void); +INLINE uint OPER_PCIX_32(void); + +/* Stack operations */ +INLINE void m68ki_push_16(uint value); +INLINE void m68ki_push_32(uint value); +INLINE uint m68ki_pull_16(void); +INLINE uint m68ki_pull_32(void); + +/* Program flow operations */ +INLINE void m68ki_jump(uint new_pc); +INLINE void m68ki_jump_vector(uint vector); +INLINE void m68ki_branch_8(uint offset); +INLINE void m68ki_branch_16(uint offset); +INLINE void m68ki_branch_32(uint offset); + +/* Status register operations. */ +INLINE void m68ki_set_s_flag(uint value); /* Only bit 2 of value should be set (i.e. 4 or 0) */ +INLINE void m68ki_set_sm_flag(uint value); /* only bits 1 and 2 of value should be set */ +INLINE void m68ki_set_ccr(uint value); /* set the condition code register */ +INLINE void m68ki_set_sr(uint value); /* set the status register */ +INLINE void m68ki_set_sr_noint(uint value); /* set the status register */ + +/* Exception processing */ +INLINE uint m68ki_init_exception(void); /* Initial exception processing */ + +INLINE void m68ki_stack_frame_3word(uint pc, uint sr); /* Stack various frame types */ +INLINE void m68ki_stack_frame_buserr(uint sr); + +INLINE void m68ki_stack_frame_0000(uint pc, uint sr, uint vector); +INLINE void m68ki_stack_frame_0001(uint pc, uint sr, uint vector); +INLINE void m68ki_stack_frame_0010(uint sr, uint vector); +INLINE void m68ki_stack_frame_1000(uint pc, uint sr, uint vector); +INLINE void m68ki_stack_frame_1010(uint sr, uint vector, uint pc); +INLINE void m68ki_stack_frame_1011(uint sr, uint vector, uint pc); + +INLINE void m68ki_exception_trap(uint vector); +INLINE void m68ki_exception_trapN(uint vector); +INLINE void m68ki_exception_trace(void); +INLINE void m68ki_exception_privilege_violation(void); +INLINE void m68ki_exception_1010(void); +INLINE void m68ki_exception_1111(void); +INLINE void m68ki_exception_illegal(void); +INLINE void m68ki_exception_format_error(void); +INLINE void m68ki_exception_address_error(void); +INLINE void m68ki_exception_interrupt(uint int_level); +INLINE void m68ki_check_interrupts(void); /* ASG: check for interrupts */ + +/* quick disassembly (used for logging) */ +char* m68ki_disassemble_quick(unsigned int pc, unsigned int cpu_type); + + +/* ======================================================================== */ +/* =========================== UTILITY FUNCTIONS ========================== */ +/* ======================================================================== */ + + +/* ---------------------------- Read Immediate ---------------------------- */ + +/* Handles all immediate reads, does address error check, function code setting, + * and prefetching if they are enabled in m68kconf.h + */ +INLINE uint m68ki_read_imm_16(void) +{ + m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */ + m68ki_check_address_error(REG_PC, MODE_READ, FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */ +#if M68K_EMULATE_PREFETCH + if(MASK_OUT_BELOW_2(REG_PC) != CPU_PREF_ADDR) + { + CPU_PREF_ADDR = MASK_OUT_BELOW_2(REG_PC); + CPU_PREF_DATA = m68k_read_immediate_32(ADDRESS_68K(CPU_PREF_ADDR)); + } + REG_PC += 2; + return MASK_OUT_ABOVE_16(CPU_PREF_DATA >> ((2-((REG_PC-2)&2))<<3)); +#else + REG_PC += 2; + return m68k_read_immediate_16(ADDRESS_68K(REG_PC-2)); +#endif /* M68K_EMULATE_PREFETCH */ +} +INLINE uint m68ki_read_imm_32(void) +{ +#if M68K_EMULATE_PREFETCH + uint temp_val; + + m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */ + m68ki_check_address_error(REG_PC, MODE_READ, FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */ + if(MASK_OUT_BELOW_2(REG_PC) != CPU_PREF_ADDR) + { + CPU_PREF_ADDR = MASK_OUT_BELOW_2(REG_PC); + CPU_PREF_DATA = m68k_read_immediate_32(ADDRESS_68K(CPU_PREF_ADDR)); + } + temp_val = CPU_PREF_DATA; + REG_PC += 2; + if(MASK_OUT_BELOW_2(REG_PC) != CPU_PREF_ADDR) + { + CPU_PREF_ADDR = MASK_OUT_BELOW_2(REG_PC); + CPU_PREF_DATA = m68k_read_immediate_32(ADDRESS_68K(CPU_PREF_ADDR)); + temp_val = MASK_OUT_ABOVE_32((temp_val << 16) | (CPU_PREF_DATA >> 16)); + } + REG_PC += 2; + + return temp_val; +#else + m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */ + m68ki_check_address_error(REG_PC, MODE_READ, FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */ + REG_PC += 4; + return m68k_read_immediate_32(ADDRESS_68K(REG_PC-4)); +#endif /* M68K_EMULATE_PREFETCH */ +} + + + +/* ------------------------- Top level read/write ------------------------- */ + +/* Handles all memory accesses (except for immediate reads if they are + * configured to use separate functions in m68kconf.h). + * All memory accesses must go through these top level functions. + * These functions will also check for address error and set the function + * code if they are enabled in m68kconf.h. + */ +INLINE uint m68ki_read_8_fc(uint address, uint fc) +{ + m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */ + return m68k_read_memory_8(ADDRESS_68K(address)); +} +INLINE uint m68ki_read_16_fc(uint address, uint fc) +{ + m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */ + m68ki_check_address_error_010_less(address, MODE_READ, fc); /* auto-disable (see m68kcpu.h) */ + return m68k_read_memory_16(ADDRESS_68K(address)); +} +INLINE uint m68ki_read_32_fc(uint address, uint fc) +{ + m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */ + m68ki_check_address_error_010_less(address, MODE_READ, fc); /* auto-disable (see m68kcpu.h) */ + return m68k_read_memory_32(ADDRESS_68K(address)); +} + +INLINE void m68ki_write_8_fc(uint address, uint fc, uint value) +{ + m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */ + m68k_write_memory_8(ADDRESS_68K(address), value); +} +INLINE void m68ki_write_16_fc(uint address, uint fc, uint value) +{ + m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */ + m68ki_check_address_error_010_less(address, MODE_WRITE, fc); /* auto-disable (see m68kcpu.h) */ + m68k_write_memory_16(ADDRESS_68K(address), value); +} +INLINE void m68ki_write_32_fc(uint address, uint fc, uint value) +{ + m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */ + m68ki_check_address_error_010_less(address, MODE_WRITE, fc); /* auto-disable (see m68kcpu.h) */ + m68k_write_memory_32(ADDRESS_68K(address), value); +} + +#if M68K_SIMULATE_PD_WRITES +INLINE void m68ki_write_32_pd_fc(uint address, uint fc, uint value) +{ + m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */ + m68ki_check_address_error_010_less(address, MODE_WRITE, fc); /* auto-disable (see m68kcpu.h) */ + m68k_write_memory_32_pd(ADDRESS_68K(address), value); +} +#endif + + +/* --------------------- Effective Address Calculation -------------------- */ + +/* The program counter relative addressing modes cause operands to be + * retrieved from program space, not data space. + */ +INLINE uint m68ki_get_ea_pcdi(void) +{ + uint old_pc = REG_PC; + m68ki_use_program_space(); /* auto-disable */ + return old_pc + MAKE_INT_16(m68ki_read_imm_16()); +} + + +INLINE uint m68ki_get_ea_pcix(void) +{ + m68ki_use_program_space(); /* auto-disable */ + return m68ki_get_ea_ix(REG_PC); +} + +/* Indexed addressing modes are encoded as follows: + * + * Base instruction format: + * F E D C B A 9 8 7 6 | 5 4 3 | 2 1 0 + * x x x x x x x x x x | 1 1 0 | BASE REGISTER (An) + * + * Base instruction format for destination EA in move instructions: + * F E D C | B A 9 | 8 7 6 | 5 4 3 2 1 0 + * x x x x | BASE REG | 1 1 0 | X X X X X X (An) + * + * Brief extension format: + * F | E D C | B | A 9 | 8 | 7 6 5 4 3 2 1 0 + * D/A | REGISTER | W/L | SCALE | 0 | DISPLACEMENT + * + * Full extension format: + * F E D C B A 9 8 7 6 5 4 3 2 1 0 + * D/A | REGISTER | W/L | SCALE | 1 | BS | IS | BD SIZE | 0 | I/IS + * BASE DISPLACEMENT (0, 16, 32 bit) (bd) + * OUTER DISPLACEMENT (0, 16, 32 bit) (od) + * + * D/A: 0 = Dn, 1 = An (Xn) + * W/L: 0 = W (sign extend), 1 = L (.SIZE) + * SCALE: 00=1, 01=2, 10=4, 11=8 (*SCALE) + * BS: 0=add base reg, 1=suppress base reg (An suppressed) + * IS: 0=add index, 1=suppress index (Xn suppressed) + * BD SIZE: 00=reserved, 01=NULL, 10=Word, 11=Long (size of bd) + * + * IS I/IS Operation + * 0 000 No Memory Indirect + * 0 001 indir prex with null outer + * 0 010 indir prex with word outer + * 0 011 indir prex with long outer + * 0 100 reserved + * 0 101 indir postx with null outer + * 0 110 indir postx with word outer + * 0 111 indir postx with long outer + * 1 000 no memory indirect + * 1 001 mem indir with null outer + * 1 010 mem indir with word outer + * 1 011 mem indir with long outer + * 1 100-111 reserved + */ +INLINE uint m68ki_get_ea_ix(uint An) +{ + /* An = base register */ + uint extension = m68ki_read_imm_16(); + uint Xn = 0; /* Index register */ + uint bd = 0; /* Base Displacement */ + uint od = 0; /* Outer Displacement */ + + if(CPU_TYPE_IS_010_LESS(CPU_TYPE)) + { + /* Calculate index */ + Xn = REG_DA[extension>>12]; /* Xn */ + if(!BIT_B(extension)) /* W/L */ + Xn = MAKE_INT_16(Xn); + + /* Add base register and displacement and return */ + return An + Xn + MAKE_INT_8(extension); + } + + /* Brief extension format */ + if(!BIT_8(extension)) + { + /* Calculate index */ + Xn = REG_DA[extension>>12]; /* Xn */ + if(!BIT_B(extension)) /* W/L */ + Xn = MAKE_INT_16(Xn); + /* Add scale if proper CPU type */ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + Xn <<= (extension>>9) & 3; /* SCALE */ + + /* Add base register and displacement and return */ + return An + Xn + MAKE_INT_8(extension); + } + + /* Full extension format */ + + USE_CYCLES(m68ki_ea_idx_cycle_table[extension&0x3f]); + + /* Check if base register is present */ + if(BIT_7(extension)) /* BS */ + An = 0; /* An */ + + /* Check if index is present */ + if(!BIT_6(extension)) /* IS */ + { + Xn = REG_DA[extension>>12]; /* Xn */ + if(!BIT_B(extension)) /* W/L */ + Xn = MAKE_INT_16(Xn); + Xn <<= (extension>>9) & 3; /* SCALE */ + } + + /* Check if base displacement is present */ + if(BIT_5(extension)) /* BD SIZE */ + bd = BIT_4(extension) ? m68ki_read_imm_32() : MAKE_INT_16(m68ki_read_imm_16()); + + /* If no indirect action, we are done */ + if(!(extension&7)) /* No Memory Indirect */ + return An + bd + Xn; + + /* Check if outer displacement is present */ + if(BIT_1(extension)) /* I/IS: od */ + od = BIT_0(extension) ? m68ki_read_imm_32() : MAKE_INT_16(m68ki_read_imm_16()); + + /* Postindex */ + if(BIT_2(extension)) /* I/IS: 0 = preindex, 1 = postindex */ + return m68ki_read_32(An + bd) + Xn + od; + + /* Preindex */ + return m68ki_read_32(An + bd + Xn) + od; +} + + +/* Fetch operands */ +INLINE uint OPER_AY_AI_8(void) {uint ea = EA_AY_AI_8(); return m68ki_read_8(ea); } +INLINE uint OPER_AY_AI_16(void) {uint ea = EA_AY_AI_16(); return m68ki_read_16(ea);} +INLINE uint OPER_AY_AI_32(void) {uint ea = EA_AY_AI_32(); return m68ki_read_32(ea);} +INLINE uint OPER_AY_PI_8(void) {uint ea = EA_AY_PI_8(); return m68ki_read_8(ea); } +INLINE uint OPER_AY_PI_16(void) {uint ea = EA_AY_PI_16(); return m68ki_read_16(ea);} +INLINE uint OPER_AY_PI_32(void) {uint ea = EA_AY_PI_32(); return m68ki_read_32(ea);} +INLINE uint OPER_AY_PD_8(void) {uint ea = EA_AY_PD_8(); return m68ki_read_8(ea); } +INLINE uint OPER_AY_PD_16(void) {uint ea = EA_AY_PD_16(); return m68ki_read_16(ea);} +INLINE uint OPER_AY_PD_32(void) {uint ea = EA_AY_PD_32(); return m68ki_read_32(ea);} +INLINE uint OPER_AY_DI_8(void) {uint ea = EA_AY_DI_8(); return m68ki_read_8(ea); } +INLINE uint OPER_AY_DI_16(void) {uint ea = EA_AY_DI_16(); return m68ki_read_16(ea);} +INLINE uint OPER_AY_DI_32(void) {uint ea = EA_AY_DI_32(); return m68ki_read_32(ea);} +INLINE uint OPER_AY_IX_8(void) {uint ea = EA_AY_IX_8(); return m68ki_read_8(ea); } +INLINE uint OPER_AY_IX_16(void) {uint ea = EA_AY_IX_16(); return m68ki_read_16(ea);} +INLINE uint OPER_AY_IX_32(void) {uint ea = EA_AY_IX_32(); return m68ki_read_32(ea);} + +INLINE uint OPER_AX_AI_8(void) {uint ea = EA_AX_AI_8(); return m68ki_read_8(ea); } +INLINE uint OPER_AX_AI_16(void) {uint ea = EA_AX_AI_16(); return m68ki_read_16(ea);} +INLINE uint OPER_AX_AI_32(void) {uint ea = EA_AX_AI_32(); return m68ki_read_32(ea);} +INLINE uint OPER_AX_PI_8(void) {uint ea = EA_AX_PI_8(); return m68ki_read_8(ea); } +INLINE uint OPER_AX_PI_16(void) {uint ea = EA_AX_PI_16(); return m68ki_read_16(ea);} +INLINE uint OPER_AX_PI_32(void) {uint ea = EA_AX_PI_32(); return m68ki_read_32(ea);} +INLINE uint OPER_AX_PD_8(void) {uint ea = EA_AX_PD_8(); return m68ki_read_8(ea); } +INLINE uint OPER_AX_PD_16(void) {uint ea = EA_AX_PD_16(); return m68ki_read_16(ea);} +INLINE uint OPER_AX_PD_32(void) {uint ea = EA_AX_PD_32(); return m68ki_read_32(ea);} +INLINE uint OPER_AX_DI_8(void) {uint ea = EA_AX_DI_8(); return m68ki_read_8(ea); } +INLINE uint OPER_AX_DI_16(void) {uint ea = EA_AX_DI_16(); return m68ki_read_16(ea);} +INLINE uint OPER_AX_DI_32(void) {uint ea = EA_AX_DI_32(); return m68ki_read_32(ea);} +INLINE uint OPER_AX_IX_8(void) {uint ea = EA_AX_IX_8(); return m68ki_read_8(ea); } +INLINE uint OPER_AX_IX_16(void) {uint ea = EA_AX_IX_16(); return m68ki_read_16(ea);} +INLINE uint OPER_AX_IX_32(void) {uint ea = EA_AX_IX_32(); return m68ki_read_32(ea);} + +INLINE uint OPER_A7_PI_8(void) {uint ea = EA_A7_PI_8(); return m68ki_read_8(ea); } +INLINE uint OPER_A7_PD_8(void) {uint ea = EA_A7_PD_8(); return m68ki_read_8(ea); } + +INLINE uint OPER_AW_8(void) {uint ea = EA_AW_8(); return m68ki_read_8(ea); } +INLINE uint OPER_AW_16(void) {uint ea = EA_AW_16(); return m68ki_read_16(ea);} +INLINE uint OPER_AW_32(void) {uint ea = EA_AW_32(); return m68ki_read_32(ea);} +INLINE uint OPER_AL_8(void) {uint ea = EA_AL_8(); return m68ki_read_8(ea); } +INLINE uint OPER_AL_16(void) {uint ea = EA_AL_16(); return m68ki_read_16(ea);} +INLINE uint OPER_AL_32(void) {uint ea = EA_AL_32(); return m68ki_read_32(ea);} +INLINE uint OPER_PCDI_8(void) {uint ea = EA_PCDI_8(); return m68ki_read_pcrel_8(ea); } +INLINE uint OPER_PCDI_16(void) {uint ea = EA_PCDI_16(); return m68ki_read_pcrel_16(ea);} +INLINE uint OPER_PCDI_32(void) {uint ea = EA_PCDI_32(); return m68ki_read_pcrel_32(ea);} +INLINE uint OPER_PCIX_8(void) {uint ea = EA_PCIX_8(); return m68ki_read_pcrel_8(ea); } +INLINE uint OPER_PCIX_16(void) {uint ea = EA_PCIX_16(); return m68ki_read_pcrel_16(ea);} +INLINE uint OPER_PCIX_32(void) {uint ea = EA_PCIX_32(); return m68ki_read_pcrel_32(ea);} + + + +/* ---------------------------- Stack Functions --------------------------- */ + +/* Push/pull data from the stack */ +INLINE void m68ki_push_16(uint value) +{ + REG_SP = MASK_OUT_ABOVE_32(REG_SP - 2); + m68ki_write_16(REG_SP, value); +} + +INLINE void m68ki_push_32(uint value) +{ + REG_SP = MASK_OUT_ABOVE_32(REG_SP - 4); + m68ki_write_32(REG_SP, value); +} + +INLINE uint m68ki_pull_16(void) +{ + REG_SP = MASK_OUT_ABOVE_32(REG_SP + 2); + return m68ki_read_16(REG_SP-2); +} + +INLINE uint m68ki_pull_32(void) +{ + REG_SP = MASK_OUT_ABOVE_32(REG_SP + 4); + return m68ki_read_32(REG_SP-4); +} + + +/* Increment/decrement the stack as if doing a push/pull but + * don't do any memory access. + */ +INLINE void m68ki_fake_push_16(void) +{ + REG_SP = MASK_OUT_ABOVE_32(REG_SP - 2); +} + +INLINE void m68ki_fake_push_32(void) +{ + REG_SP = MASK_OUT_ABOVE_32(REG_SP - 4); +} + +INLINE void m68ki_fake_pull_16(void) +{ + REG_SP = MASK_OUT_ABOVE_32(REG_SP + 2); +} + +INLINE void m68ki_fake_pull_32(void) +{ + REG_SP = MASK_OUT_ABOVE_32(REG_SP + 4); +} + + +/* ----------------------------- Program Flow ----------------------------- */ + +/* Jump to a new program location or vector. + * These functions will also call the pc_changed callback if it was enabled + * in m68kconf.h. + */ +INLINE void m68ki_jump(uint new_pc) +{ + REG_PC = new_pc; + m68ki_pc_changed(REG_PC); +} + +INLINE void m68ki_jump_vector(uint vector) +{ + REG_PC = (vector<<2) + REG_VBR; + REG_PC = m68ki_read_data_32(REG_PC); + m68ki_pc_changed(REG_PC); +} + + +/* Branch to a new memory location. + * The 32-bit branch will call pc_changed if it was enabled in m68kconf.h. + * So far I've found no problems with not calling pc_changed for 8 or 16 + * bit branches. + */ +INLINE void m68ki_branch_8(uint offset) +{ + REG_PC += MAKE_INT_8(offset); +} + +INLINE void m68ki_branch_16(uint offset) +{ + REG_PC += MAKE_INT_16(offset); +} + +INLINE void m68ki_branch_32(uint offset) +{ + REG_PC += offset; + m68ki_pc_changed(REG_PC); +} + + + +/* ---------------------------- Status Register --------------------------- */ + +/* Set the S flag and change the active stack pointer. + * Note that value MUST be 4 or 0. + */ +INLINE void m68ki_set_s_flag(uint value) +{ + /* Backup the old stack pointer */ + REG_SP_BASE[FLAG_S | ((FLAG_S>>1) & FLAG_M)] = REG_SP; + /* Set the S flag */ + FLAG_S = value; + /* Set the new stack pointer */ + REG_SP = REG_SP_BASE[FLAG_S | ((FLAG_S>>1) & FLAG_M)]; +} + +/* Set the S and M flags and change the active stack pointer. + * Note that value MUST be 0, 2, 4, or 6 (bit2 = S, bit1 = M). + */ +INLINE void m68ki_set_sm_flag(uint value) +{ + /* Backup the old stack pointer */ + REG_SP_BASE[FLAG_S | ((FLAG_S>>1) & FLAG_M)] = REG_SP; + /* Set the S and M flags */ + FLAG_S = value & SFLAG_SET; + FLAG_M = value & MFLAG_SET; + /* Set the new stack pointer */ + REG_SP = REG_SP_BASE[FLAG_S | ((FLAG_S>>1) & FLAG_M)]; +} + +/* Set the S and M flags. Don't touch the stack pointer. */ +INLINE void m68ki_set_sm_flag_nosp(uint value) +{ + /* Set the S and M flags */ + FLAG_S = value & SFLAG_SET; + FLAG_M = value & MFLAG_SET; +} + + +/* Set the condition code register */ +INLINE void m68ki_set_ccr(uint value) +{ + FLAG_X = BIT_4(value) << 4; + FLAG_N = BIT_3(value) << 4; + FLAG_Z = !BIT_2(value); + FLAG_V = BIT_1(value) << 6; + FLAG_C = BIT_0(value) << 8; +} + +/* Set the status register but don't check for interrupts */ +INLINE void m68ki_set_sr_noint(uint value) +{ + /* Mask out the "unimplemented" bits */ + value &= CPU_SR_MASK; + + /* Now set the status register */ + FLAG_T1 = BIT_F(value); + FLAG_T0 = BIT_E(value); + FLAG_INT_MASK = value & 0x0700; + m68ki_set_ccr(value); + m68ki_set_sm_flag((value >> 11) & 6); +} + +/* Set the status register but don't check for interrupts nor + * change the stack pointer + */ +INLINE void m68ki_set_sr_noint_nosp(uint value) +{ + /* Mask out the "unimplemented" bits */ + value &= CPU_SR_MASK; + + /* Now set the status register */ + FLAG_T1 = BIT_F(value); + FLAG_T0 = BIT_E(value); + FLAG_INT_MASK = value & 0x0700; + m68ki_set_ccr(value); + m68ki_set_sm_flag_nosp((value >> 11) & 6); +} + +/* Set the status register and check for interrupts */ +INLINE void m68ki_set_sr(uint value) +{ + m68ki_set_sr_noint(value); + m68ki_check_interrupts(); +} + + +/* ------------------------- Exception Processing ------------------------- */ + +/* Initiate exception processing */ +INLINE uint m68ki_init_exception(void) +{ + /* Save the old status register */ + uint sr = m68ki_get_sr(); + + /* Turn off trace flag, clear pending traces */ + FLAG_T1 = FLAG_T0 = 0; + m68ki_clear_trace(); + /* Enter supervisor mode */ + m68ki_set_s_flag(SFLAG_SET); + + return sr; +} + +/* 3 word stack frame (68000 only) */ +INLINE void m68ki_stack_frame_3word(uint pc, uint sr) +{ + m68ki_push_32(pc); + m68ki_push_16(sr); +} + +/* Format 0 stack frame. + * This is the standard stack frame for 68010+. + */ +INLINE void m68ki_stack_frame_0000(uint pc, uint sr, uint vector) +{ + /* Stack a 3-word frame if we are 68000 */ + if(CPU_TYPE == CPU_TYPE_000 || CPU_TYPE == CPU_TYPE_008) + { + m68ki_stack_frame_3word(pc, sr); + return; + } + m68ki_push_16(vector<<2); + m68ki_push_32(pc); + m68ki_push_16(sr); +} + +/* Format 1 stack frame (68020). + * For 68020, this is the 4 word throwaway frame. + */ +INLINE void m68ki_stack_frame_0001(uint pc, uint sr, uint vector) +{ + m68ki_push_16(0x1000 | (vector<<2)); + m68ki_push_32(pc); + m68ki_push_16(sr); +} + +/* Format 2 stack frame. + * This is used only by 68020 for trap exceptions. + */ +INLINE void m68ki_stack_frame_0010(uint sr, uint vector) +{ + m68ki_push_32(REG_PPC); + m68ki_push_16(0x2000 | (vector<<2)); + m68ki_push_32(REG_PC); + m68ki_push_16(sr); +} + + +/* Bus error stack frame (68000 only). + */ +INLINE void m68ki_stack_frame_buserr(uint sr) +{ + m68ki_push_32(REG_PC); + m68ki_push_16(sr); + m68ki_push_16(REG_IR); + m68ki_push_32(m68ki_aerr_address); /* access address */ + /* 0 0 0 0 0 0 0 0 0 0 0 R/W I/N FC + * R/W 0 = write, 1 = read + * I/N 0 = instruction, 1 = not + * FC 3-bit function code + */ + m68ki_push_16(m68ki_aerr_write_mode | CPU_INSTR_MODE | m68ki_aerr_fc); +} + +/* Format 8 stack frame (68010). + * 68010 only. This is the 29 word bus/address error frame. + */ +void m68ki_stack_frame_1000(uint pc, uint sr, uint vector) +{ + /* VERSION + * NUMBER + * INTERNAL INFORMATION, 16 WORDS + */ + m68ki_fake_push_32(); + m68ki_fake_push_32(); + m68ki_fake_push_32(); + m68ki_fake_push_32(); + m68ki_fake_push_32(); + m68ki_fake_push_32(); + m68ki_fake_push_32(); + m68ki_fake_push_32(); + + /* INSTRUCTION INPUT BUFFER */ + m68ki_push_16(0); + + /* UNUSED, RESERVED (not written) */ + m68ki_fake_push_16(); + + /* DATA INPUT BUFFER */ + m68ki_push_16(0); + + /* UNUSED, RESERVED (not written) */ + m68ki_fake_push_16(); + + /* DATA OUTPUT BUFFER */ + m68ki_push_16(0); + + /* UNUSED, RESERVED (not written) */ + m68ki_fake_push_16(); + + /* FAULT ADDRESS */ + m68ki_push_32(0); + + /* SPECIAL STATUS WORD */ + m68ki_push_16(0); + + /* 1000, VECTOR OFFSET */ + m68ki_push_16(0x8000 | (vector<<2)); + + /* PROGRAM COUNTER */ + m68ki_push_32(pc); + + /* STATUS REGISTER */ + m68ki_push_16(sr); +} + +/* Format A stack frame (short bus fault). + * This is used only by 68020 for bus fault and address error + * if the error happens at an instruction boundary. + * PC stacked is address of next instruction. + */ +void m68ki_stack_frame_1010(uint sr, uint vector, uint pc) +{ + /* INTERNAL REGISTER */ + m68ki_push_16(0); + + /* INTERNAL REGISTER */ + m68ki_push_16(0); + + /* DATA OUTPUT BUFFER (2 words) */ + m68ki_push_32(0); + + /* INTERNAL REGISTER */ + m68ki_push_16(0); + + /* INTERNAL REGISTER */ + m68ki_push_16(0); + + /* DATA CYCLE FAULT ADDRESS (2 words) */ + m68ki_push_32(0); + + /* INSTRUCTION PIPE STAGE B */ + m68ki_push_16(0); + + /* INSTRUCTION PIPE STAGE C */ + m68ki_push_16(0); + + /* SPECIAL STATUS REGISTER */ + m68ki_push_16(0); + + /* INTERNAL REGISTER */ + m68ki_push_16(0); + + /* 1010, VECTOR OFFSET */ + m68ki_push_16(0xa000 | (vector<<2)); + + /* PROGRAM COUNTER */ + m68ki_push_32(pc); + + /* STATUS REGISTER */ + m68ki_push_16(sr); +} + +/* Format B stack frame (long bus fault). + * This is used only by 68020 for bus fault and address error + * if the error happens during instruction execution. + * PC stacked is address of instruction in progress. + */ +void m68ki_stack_frame_1011(uint sr, uint vector, uint pc) +{ + /* INTERNAL REGISTERS (18 words) */ + m68ki_push_32(0); + m68ki_push_32(0); + m68ki_push_32(0); + m68ki_push_32(0); + m68ki_push_32(0); + m68ki_push_32(0); + m68ki_push_32(0); + m68ki_push_32(0); + m68ki_push_32(0); + + /* VERSION# (4 bits), INTERNAL INFORMATION */ + m68ki_push_16(0); + + /* INTERNAL REGISTERS (3 words) */ + m68ki_push_32(0); + m68ki_push_16(0); + + /* DATA INTPUT BUFFER (2 words) */ + m68ki_push_32(0); + + /* INTERNAL REGISTERS (2 words) */ + m68ki_push_32(0); + + /* STAGE B ADDRESS (2 words) */ + m68ki_push_32(0); + + /* INTERNAL REGISTER (4 words) */ + m68ki_push_32(0); + m68ki_push_32(0); + + /* DATA OUTPUT BUFFER (2 words) */ + m68ki_push_32(0); + + /* INTERNAL REGISTER */ + m68ki_push_16(0); + + /* INTERNAL REGISTER */ + m68ki_push_16(0); + + /* DATA CYCLE FAULT ADDRESS (2 words) */ + m68ki_push_32(0); + + /* INSTRUCTION PIPE STAGE B */ + m68ki_push_16(0); + + /* INSTRUCTION PIPE STAGE C */ + m68ki_push_16(0); + + /* SPECIAL STATUS REGISTER */ + m68ki_push_16(0); + + /* INTERNAL REGISTER */ + m68ki_push_16(0); + + /* 1011, VECTOR OFFSET */ + m68ki_push_16(0xb000 | (vector<<2)); + + /* PROGRAM COUNTER */ + m68ki_push_32(pc); + + /* STATUS REGISTER */ + m68ki_push_16(sr); +} + + +/* Used for Group 2 exceptions. + * These stack a type 2 frame on the 020. + */ +INLINE void m68ki_exception_trap(uint vector) +{ + uint sr = m68ki_init_exception(); + + if(CPU_TYPE_IS_010_LESS(CPU_TYPE)) + m68ki_stack_frame_0000(REG_PC, sr, vector); + else + m68ki_stack_frame_0010(sr, vector); + + m68ki_jump_vector(vector); + + /* Use up some clock cycles */ + USE_CYCLES(CYC_EXCEPTION[vector]); +} + +/* Trap#n stacks a 0 frame but behaves like group2 otherwise */ +INLINE void m68ki_exception_trapN(uint vector) +{ + uint sr = m68ki_init_exception(); + m68ki_stack_frame_0000(REG_PC, sr, vector); + m68ki_jump_vector(vector); + + /* Use up some clock cycles */ + USE_CYCLES(CYC_EXCEPTION[vector]); +} + +/* Exception for trace mode */ +INLINE void m68ki_exception_trace(void) +{ + uint sr = m68ki_init_exception(); + + if(CPU_TYPE_IS_010_LESS(CPU_TYPE)) + { + #if M68K_EMULATE_ADDRESS_ERROR == OPT_ON + if(CPU_TYPE_IS_000(CPU_TYPE)) + { + CPU_INSTR_MODE = INSTRUCTION_NO; + } + #endif /* M68K_EMULATE_ADDRESS_ERROR */ + m68ki_stack_frame_0000(REG_PC, sr, EXCEPTION_TRACE); + } + else + m68ki_stack_frame_0010(sr, EXCEPTION_TRACE); + + m68ki_jump_vector(EXCEPTION_TRACE); + + /* Trace nullifies a STOP instruction */ + CPU_STOPPED &= ~STOP_LEVEL_STOP; + + /* Use up some clock cycles */ + USE_CYCLES(CYC_EXCEPTION[EXCEPTION_TRACE]); +} + +/* Exception for privilege violation */ +INLINE void m68ki_exception_privilege_violation(void) +{ + uint sr = m68ki_init_exception(); + + #if M68K_EMULATE_ADDRESS_ERROR == OPT_ON + if(CPU_TYPE_IS_000(CPU_TYPE)) + { + CPU_INSTR_MODE = INSTRUCTION_NO; + } + #endif /* M68K_EMULATE_ADDRESS_ERROR */ + + m68ki_stack_frame_0000(REG_PPC, sr, EXCEPTION_PRIVILEGE_VIOLATION); + m68ki_jump_vector(EXCEPTION_PRIVILEGE_VIOLATION); + + /* Use up some clock cycles and undo the instruction's cycles */ + USE_CYCLES(CYC_EXCEPTION[EXCEPTION_PRIVILEGE_VIOLATION] - CYC_INSTRUCTION[REG_IR]); +} + +/* Exception for A-Line instructions */ +INLINE void m68ki_exception_1010(void) +{ + uint sr; +#if M68K_LOG_1010_1111 == OPT_ON + M68K_DO_LOG_EMU((M68K_LOG_FILEHANDLE "%s at %08x: called 1010 instruction %04x (%s)\n", + m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PPC), REG_IR, + m68ki_disassemble_quick(ADDRESS_68K(REG_PPC)))); +#endif + + sr = m68ki_init_exception(); + m68ki_stack_frame_0000(REG_PPC, sr, EXCEPTION_1010); + m68ki_jump_vector(EXCEPTION_1010); + + /* Use up some clock cycles and undo the instruction's cycles */ + USE_CYCLES(CYC_EXCEPTION[EXCEPTION_1010] - CYC_INSTRUCTION[REG_IR]); +} + +/* Exception for F-Line instructions */ +INLINE void m68ki_exception_1111(void) +{ + uint sr; + +#if M68K_LOG_1010_1111 == OPT_ON + M68K_DO_LOG_EMU((M68K_LOG_FILEHANDLE "%s at %08x: called 1111 instruction %04x (%s)\n", + m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PPC), REG_IR, + m68ki_disassemble_quick(ADDRESS_68K(REG_PPC)))); +#endif + + sr = m68ki_init_exception(); + m68ki_stack_frame_0000(REG_PPC, sr, EXCEPTION_1111); + m68ki_jump_vector(EXCEPTION_1111); + + /* Use up some clock cycles and undo the instruction's cycles */ + USE_CYCLES(CYC_EXCEPTION[EXCEPTION_1111] - CYC_INSTRUCTION[REG_IR]); +} + +/* Exception for illegal instructions */ +INLINE void m68ki_exception_illegal(void) +{ + uint sr; + + M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: illegal instruction %04x (%s)\n", + m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PPC), REG_IR, + m68ki_disassemble_quick(ADDRESS_68K(REG_PPC)))); + + sr = m68ki_init_exception(); + + #if M68K_EMULATE_ADDRESS_ERROR == OPT_ON + if(CPU_TYPE_IS_000(CPU_TYPE)) + { + CPU_INSTR_MODE = INSTRUCTION_NO; + } + #endif /* M68K_EMULATE_ADDRESS_ERROR */ + + m68ki_stack_frame_0000(REG_PPC, sr, EXCEPTION_ILLEGAL_INSTRUCTION); + m68ki_jump_vector(EXCEPTION_ILLEGAL_INSTRUCTION); + + /* Use up some clock cycles and undo the instruction's cycles */ + USE_CYCLES(CYC_EXCEPTION[EXCEPTION_ILLEGAL_INSTRUCTION] - CYC_INSTRUCTION[REG_IR]); +} + +/* Exception for format errror in RTE */ +INLINE void m68ki_exception_format_error(void) +{ + uint sr = m68ki_init_exception(); + m68ki_stack_frame_0000(REG_PC, sr, EXCEPTION_FORMAT_ERROR); + m68ki_jump_vector(EXCEPTION_FORMAT_ERROR); + + /* Use up some clock cycles and undo the instruction's cycles */ + USE_CYCLES(CYC_EXCEPTION[EXCEPTION_FORMAT_ERROR] - CYC_INSTRUCTION[REG_IR]); +} + +/* Exception for address error */ +INLINE void m68ki_exception_address_error(void) +{ + uint sr = m68ki_init_exception(); + + /* If we were processing a bus error, address error, or reset, + * this is a catastrophic failure. + * Halt the CPU + */ + if(CPU_RUN_MODE == RUN_MODE_BERR_AERR_RESET) + { +m68k_read_memory_8(0x00ffff01); + CPU_STOPPED = STOP_LEVEL_HALT; + return; + } + CPU_RUN_MODE = RUN_MODE_BERR_AERR_RESET; + + /* Note: This is implemented for 68000 only! */ + m68ki_stack_frame_buserr(sr); + + m68ki_jump_vector(EXCEPTION_ADDRESS_ERROR); + + /* Use up some clock cycles and undo the instruction's cycles */ + USE_CYCLES(CYC_EXCEPTION[EXCEPTION_ADDRESS_ERROR] - CYC_INSTRUCTION[REG_IR]); +} + +/* Service an interrupt request and start exception processing */ +void m68ki_exception_interrupt(uint int_level) +{ + uint vector; + uint sr; + uint new_pc; + + #if M68K_EMULATE_ADDRESS_ERROR == OPT_ON + if(CPU_TYPE_IS_000(CPU_TYPE)) + { + CPU_INSTR_MODE = INSTRUCTION_NO; + } + #endif /* M68K_EMULATE_ADDRESS_ERROR */ + + /* Turn off the stopped state */ + CPU_STOPPED &= ~STOP_LEVEL_STOP; + + /* If we are halted, don't do anything */ + if(CPU_STOPPED) + return; + + /* Acknowledge the interrupt */ + vector = m68ki_int_ack(int_level); + + /* Get the interrupt vector */ + if(vector == M68K_INT_ACK_AUTOVECTOR) + /* Use the autovectors. This is the most commonly used implementation */ + vector = EXCEPTION_INTERRUPT_AUTOVECTOR+int_level; + else if(vector == M68K_INT_ACK_SPURIOUS) + /* Called if no devices respond to the interrupt acknowledge */ + vector = EXCEPTION_SPURIOUS_INTERRUPT; + else if(vector > 255) + { + M68K_DO_LOG_EMU((M68K_LOG_FILEHANDLE "%s at %08x: Interrupt acknowledge returned invalid vector $%x\n", + m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC), vector)); + return; + } + + /* Start exception processing */ + sr = m68ki_init_exception(); + + /* Set the interrupt mask to the level of the one being serviced */ + FLAG_INT_MASK = int_level<<8; + + /* Get the new PC */ + new_pc = m68ki_read_data_32((vector<<2) + REG_VBR); + + /* If vector is uninitialized, call the uninitialized interrupt vector */ + if(new_pc == 0) + new_pc = m68ki_read_data_32((EXCEPTION_UNINITIALIZED_INTERRUPT<<2) + REG_VBR); + + /* Generate a stack frame */ + m68ki_stack_frame_0000(REG_PC, sr, vector); + if(FLAG_M && CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + /* Create throwaway frame */ + m68ki_set_sm_flag(FLAG_S); /* clear M */ + sr |= 0x2000; /* Same as SR in master stack frame except S is forced high */ + m68ki_stack_frame_0001(REG_PC, sr, vector); + } + + m68ki_jump(new_pc); + + /* Defer cycle counting until later */ + CPU_INT_CYCLES += CYC_EXCEPTION[vector]; + +#if !M68K_EMULATE_INT_ACK + /* Automatically clear IRQ if we are not using an acknowledge scheme */ + CPU_INT_LEVEL = 0; +#endif /* M68K_EMULATE_INT_ACK */ +} + + +/* ASG: Check for interrupts */ +INLINE void m68ki_check_interrupts(void) +{ + if(CPU_INT_LEVEL > FLAG_INT_MASK) + m68ki_exception_interrupt(CPU_INT_LEVEL>>8); +} + + + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ + +#endif /* M68KCPU__HEADER */ diff --git a/cpu/musashi/m68kdasm.c b/cpu/musashi/m68kdasm.c new file mode 100644 index 00000000..f697a09d --- /dev/null +++ b/cpu/musashi/m68kdasm.c @@ -0,0 +1,3604 @@ +/* ======================================================================== */ +/* ========================= LICENSING & COPYRIGHT ======================== */ +/* ======================================================================== */ +/* + * MUSASHI + * Version 3.3 + * + * A portable Motorola M680x0 processor emulation engine. + * Copyright 1998-2001 Karl Stenerud. All rights reserved. + * + * This code may be freely used for non-commercial purposes as long as this + * copyright notice remains unaltered in the source code and any binary files + * containing this code in compiled form. + * + * All other lisencing terms must be negotiated with the author + * (Karl Stenerud). + * + * The latest version of this code can be obtained at: + * http://kstenerud.cjb.net + */ + + + +/* ======================================================================== */ +/* ================================ INCLUDES ============================== */ +/* ======================================================================== */ + +#include +#include +#include +#include "m68k.h" + +#ifndef DECL_SPEC +#define DECL_SPEC +#endif + +/* ======================================================================== */ +/* ============================ GENERAL DEFINES =========================== */ +/* ======================================================================== */ + +/* unsigned int and int must be at least 32 bits wide */ +#undef uint +#define uint unsigned int + +/* Bit Isolation Functions */ +#define BIT_0(A) ((A) & 0x00000001) +#define BIT_1(A) ((A) & 0x00000002) +#define BIT_2(A) ((A) & 0x00000004) +#define BIT_3(A) ((A) & 0x00000008) +#define BIT_4(A) ((A) & 0x00000010) +#define BIT_5(A) ((A) & 0x00000020) +#define BIT_6(A) ((A) & 0x00000040) +#define BIT_7(A) ((A) & 0x00000080) +#define BIT_8(A) ((A) & 0x00000100) +#define BIT_9(A) ((A) & 0x00000200) +#define BIT_A(A) ((A) & 0x00000400) +#define BIT_B(A) ((A) & 0x00000800) +#define BIT_C(A) ((A) & 0x00001000) +#define BIT_D(A) ((A) & 0x00002000) +#define BIT_E(A) ((A) & 0x00004000) +#define BIT_F(A) ((A) & 0x00008000) +#define BIT_10(A) ((A) & 0x00010000) +#define BIT_11(A) ((A) & 0x00020000) +#define BIT_12(A) ((A) & 0x00040000) +#define BIT_13(A) ((A) & 0x00080000) +#define BIT_14(A) ((A) & 0x00100000) +#define BIT_15(A) ((A) & 0x00200000) +#define BIT_16(A) ((A) & 0x00400000) +#define BIT_17(A) ((A) & 0x00800000) +#define BIT_18(A) ((A) & 0x01000000) +#define BIT_19(A) ((A) & 0x02000000) +#define BIT_1A(A) ((A) & 0x04000000) +#define BIT_1B(A) ((A) & 0x08000000) +#define BIT_1C(A) ((A) & 0x10000000) +#define BIT_1D(A) ((A) & 0x20000000) +#define BIT_1E(A) ((A) & 0x40000000) +#define BIT_1F(A) ((A) & 0x80000000) + +/* These are the CPU types understood by this disassembler */ +#define TYPE_68000 1 +#define TYPE_68008 2 +#define TYPE_68010 4 +#define TYPE_68020 8 +#define TYPE_68030 16 +#define TYPE_68040 32 + +#define M68000_ONLY (TYPE_68000 | TYPE_68008) + +#define M68010_ONLY TYPE_68010 +#define M68010_LESS (TYPE_68000 | TYPE_68008 | TYPE_68010) +#define M68010_PLUS (TYPE_68010 | TYPE_68020 | TYPE_68030 | TYPE_68040) + +#define M68020_ONLY TYPE_68020 +#define M68020_LESS (TYPE_68010 | TYPE_68020) +#define M68020_PLUS (TYPE_68020 | TYPE_68030 | TYPE_68040) + +#define M68030_ONLY TYPE_68030 +#define M68030_LESS (TYPE_68010 | TYPE_68020 | TYPE_68030) +#define M68030_PLUS (TYPE_68030 | TYPE_68040) + +#define M68040_PLUS TYPE_68040 + + +/* Extension word formats */ +#define EXT_8BIT_DISPLACEMENT(A) ((A)&0xff) +#define EXT_FULL(A) BIT_8(A) +#define EXT_EFFECTIVE_ZERO(A) (((A)&0xe4) == 0xc4 || ((A)&0xe2) == 0xc0) +#define EXT_BASE_REGISTER_PRESENT(A) (!BIT_7(A)) +#define EXT_INDEX_REGISTER_PRESENT(A) (!BIT_6(A)) +#define EXT_INDEX_REGISTER(A) (((A)>>12)&7) +#define EXT_INDEX_PRE_POST(A) (EXT_INDEX_PRESENT(A) && (A)&3) +#define EXT_INDEX_PRE(A) (EXT_INDEX_PRESENT(A) && ((A)&7) < 4 && ((A)&7) != 0) +#define EXT_INDEX_POST(A) (EXT_INDEX_PRESENT(A) && ((A)&7) > 4) +#define EXT_INDEX_SCALE(A) (((A)>>9)&3) +#define EXT_INDEX_LONG(A) BIT_B(A) +#define EXT_INDEX_AR(A) BIT_F(A) +#define EXT_BASE_DISPLACEMENT_PRESENT(A) (((A)&0x30) > 0x10) +#define EXT_BASE_DISPLACEMENT_WORD(A) (((A)&0x30) == 0x20) +#define EXT_BASE_DISPLACEMENT_LONG(A) (((A)&0x30) == 0x30) +#define EXT_OUTER_DISPLACEMENT_PRESENT(A) (((A)&3) > 1 && ((A)&0x47) < 0x44) +#define EXT_OUTER_DISPLACEMENT_WORD(A) (((A)&3) == 2 && ((A)&0x47) < 0x44) +#define EXT_OUTER_DISPLACEMENT_LONG(A) (((A)&3) == 3 && ((A)&0x47) < 0x44) + + +/* Opcode flags */ +#if M68K_COMPILE_FOR_MAME == OPT_ON +#define SET_OPCODE_FLAGS(x) g_opcode_type = x; +#define COMBINE_OPCODE_FLAGS(x) ((x) | g_opcode_type | DASMFLAG_SUPPORTED) +#else +#define SET_OPCODE_FLAGS(x) +#define COMBINE_OPCODE_FLAGS(x) (x) +#endif + + +/* ======================================================================== */ +/* =============================== PROTOTYPES ============================= */ +/* ======================================================================== */ + +/* Read data at the PC and increment PC */ +uint read_imm_8(void); +uint read_imm_16(void); +uint read_imm_32(void); + +/* Read data at the PC but don't imcrement the PC */ +uint peek_imm_8(void); +uint peek_imm_16(void); +uint peek_imm_32(void); + +/* make signed integers 100% portably */ +static int make_int_8(int value); +static int make_int_16(int value); + +/* make a string of a hex value */ +static char* make_signed_hex_str_8(uint val); +static char* make_signed_hex_str_16(uint val); +static char* make_signed_hex_str_32(uint val); + +/* make string of ea mode */ +static char* get_ea_mode_str(uint instruction, uint size); + +char* get_ea_mode_str_8(uint instruction); +char* get_ea_mode_str_16(uint instruction); +char* get_ea_mode_str_32(uint instruction); + +/* make string of immediate value */ +static char* get_imm_str_s(uint size); +static char* get_imm_str_u(uint size); + +char* get_imm_str_s8(void); +char* get_imm_str_s16(void); +char* get_imm_str_s32(void); + +/* Stuff to build the opcode handler jump table */ +static void build_opcode_table(void); +static int valid_ea(uint opcode, uint mask); +static int DECL_SPEC compare_nof_true_bits(const void *aptr, const void *bptr); + +/* used to build opcode handler jump table */ +typedef struct +{ + void (*opcode_handler)(void); /* handler function */ + uint mask; /* mask on opcode */ + uint match; /* what to match after masking */ + uint ea_mask; /* what ea modes are allowed */ +} opcode_struct; + + + +/* ======================================================================== */ +/* ================================= DATA ================================= */ +/* ======================================================================== */ + +/* Opcode handler jump table */ +static void (*g_instruction_table[0x10000])(void); +/* Flag if disassembler initialized */ +static int g_initialized = 0; + +/* Address mask to simulate address lines */ +static unsigned int g_address_mask = 0xffffffff; + +static char g_dasm_str[100]; /* string to hold disassembly */ +static char g_helper_str[100]; /* string to hold helpful info */ +static uint g_cpu_pc; /* program counter */ +static uint g_cpu_ir; /* instruction register */ +static uint g_cpu_type; +static uint g_opcode_type; +static unsigned char* g_rawop; +static uint g_rawbasepc; +static uint g_rawlength; + +/* used by ops like asr, ror, addq, etc */ +static uint g_3bit_qdata_table[8] = {8, 1, 2, 3, 4, 5, 6, 7}; + +static uint g_5bit_data_table[32] = +{ + 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 +}; + +static const char* g_cc[16] = +{"t", "f", "hi", "ls", "cc", "cs", "ne", "eq", "vc", "vs", "pl", "mi", "ge", "lt", "gt", "le"}; + +static const char* g_cpcc[64] = +{/* 000 001 010 011 100 101 110 111 */ + "f", "eq", "ogt", "oge", "olt", "ole", "ogl", "or", /* 000 */ + "un", "ueq", "ugt", "uge", "ult", "ule", "ne", "t", /* 001 */ + "sf", "seq", "gt", "ge", "lt", "le", "gl" "gle", /* 010 */ + "ngle", "ngl", "nle", "nlt", "nge", "ngt", "sne", "st", /* 011 */ + "?", "?", "?", "?", "?", "?", "?", "?", /* 100 */ + "?", "?", "?", "?", "?", "?", "?", "?", /* 101 */ + "?", "?", "?", "?", "?", "?", "?", "?", /* 110 */ + "?", "?", "?", "?", "?", "?", "?", "?" /* 111 */ +}; + + +/* ======================================================================== */ +/* =========================== UTILITY FUNCTIONS ========================== */ +/* ======================================================================== */ + +#define LIMIT_CPU_TYPES(ALLOWED_CPU_TYPES) \ + if(!(g_cpu_type & ALLOWED_CPU_TYPES)) \ + { \ + if((g_cpu_ir & 0xf000) == 0xf000) \ + d68000_1111(); \ + else d68000_illegal(); \ + return; \ + } + +static uint dasm_read_imm_8(uint advance) +{ + uint result; + if (g_rawop) + result = g_rawop[g_cpu_pc + 1 - g_rawbasepc]; + else + result = m68k_read_disassembler_16(g_cpu_pc & g_address_mask) & 0xff; + g_cpu_pc += advance; + return result; +} + +static uint dasm_read_imm_16(uint advance) +{ + uint result; + if (g_rawop) + result = (g_rawop[g_cpu_pc + 0 - g_rawbasepc] << 8) | + g_rawop[g_cpu_pc + 1 - g_rawbasepc]; + else + result = m68k_read_disassembler_16(g_cpu_pc & g_address_mask) & 0xffff; // & 0xff; ?? + g_cpu_pc += advance; + return result; +} + +static uint dasm_read_imm_32(uint advance) +{ + uint result; + if (g_rawop) + result = (g_rawop[g_cpu_pc + 0 - g_rawbasepc] << 24) | + (g_rawop[g_cpu_pc + 1 - g_rawbasepc] << 16) | + (g_rawop[g_cpu_pc + 2 - g_rawbasepc] << 8) | + g_rawop[g_cpu_pc + 3 - g_rawbasepc]; + else + result = m68k_read_disassembler_32(g_cpu_pc & g_address_mask); // & 0xff; ?? + g_cpu_pc += advance; + return result; +} + +#define read_imm_8() dasm_read_imm_8(2) +#define read_imm_16() dasm_read_imm_16(2) +#define read_imm_32() dasm_read_imm_32(4) + +#define peek_imm_8() dasm_read_imm_8(0) +#define peek_imm_16() dasm_read_imm_16(0) +#define peek_imm_32() dasm_read_imm_32(0) + +/* Fake a split interface */ +#define get_ea_mode_str_8(instruction) get_ea_mode_str(instruction, 0) +#define get_ea_mode_str_16(instruction) get_ea_mode_str(instruction, 1) +#define get_ea_mode_str_32(instruction) get_ea_mode_str(instruction, 2) + +#define get_imm_str_s8() get_imm_str_s(0) +#define get_imm_str_s16() get_imm_str_s(1) +#define get_imm_str_s32() get_imm_str_s(2) + +#define get_imm_str_u8() get_imm_str_u(0) +#define get_imm_str_u16() get_imm_str_u(1) +#define get_imm_str_u32() get_imm_str_u(2) + + +/* 100% portable signed int generators */ +static int make_int_8(int value) +{ + return (value & 0x80) ? value | ~0xff : value & 0xff; +} + +static int make_int_16(int value) +{ + return (value & 0x8000) ? value | ~0xffff : value & 0xffff; +} + + +/* Get string representation of hex values */ +static char* make_signed_hex_str_8(uint val) +{ + static char str[20]; + + val &= 0xff; + + if(val == 0x80) + sprintf(str, "-$80"); + else if(val & 0x80) + sprintf(str, "-$%x", (0-val) & 0x7f); + else + sprintf(str, "$%x", val & 0x7f); + + return str; +} + +static char* make_signed_hex_str_16(uint val) +{ + static char str[20]; + + val &= 0xffff; + + if(val == 0x8000) + sprintf(str, "-$8000"); + else if(val & 0x8000) + sprintf(str, "-$%x", (0-val) & 0x7fff); + else + sprintf(str, "$%x", val & 0x7fff); + + return str; +} + +static char* make_signed_hex_str_32(uint val) +{ + static char str[20]; + + val &= 0xffffffff; + + if(val == 0x80000000) + sprintf(str, "-$80000000"); + else if(val & 0x80000000) + sprintf(str, "-$%x", (0-val) & 0x7fffffff); + else + sprintf(str, "$%x", val & 0x7fffffff); + + return str; +} + + +/* make string of immediate value */ +static char* get_imm_str_s(uint size) +{ + static char str[15]; + if(size == 0) + sprintf(str, "#%s", make_signed_hex_str_8(read_imm_8())); + else if(size == 1) + sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16())); + else + sprintf(str, "#%s", make_signed_hex_str_32(read_imm_32())); + return str; +} + +static char* get_imm_str_u(uint size) +{ + static char str[15]; + if(size == 0) + sprintf(str, "#$%x", read_imm_8() & 0xff); + else if(size == 1) + sprintf(str, "#$%x", read_imm_16() & 0xffff); + else + sprintf(str, "#$%x", read_imm_32() & 0xffffffff); + return str; +} + +/* Make string of effective address mode */ +static char* get_ea_mode_str(uint instruction, uint size) +{ + static char b1[64]; + static char b2[64]; + static char* mode = b2; + uint extension; + uint base; + uint outer; + char base_reg[4]; + char index_reg[8]; + uint preindex; + uint postindex; + uint comma = 0; + uint temp_value; + char invalid_mode = 0; + + /* Switch buffers so we don't clobber on a double-call to this function */ + mode = mode == b1 ? b2 : b1; + + switch(instruction & 0x3f) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + /* data register direct */ + sprintf(mode, "D%d", instruction&7); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + /* address register direct */ + sprintf(mode, "A%d", instruction&7); + break; + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + /* address register indirect */ + sprintf(mode, "(A%d)", instruction&7); + break; + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + /* address register indirect with postincrement */ + sprintf(mode, "(A%d)+", instruction&7); + break; + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + /* address register indirect with predecrement */ + sprintf(mode, "-(A%d)", instruction&7); + break; + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + /* address register indirect with displacement*/ + sprintf(mode, "(%s,A%d)", make_signed_hex_str_16(read_imm_16()), instruction&7); + break; + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: + /* address register indirect with index */ + extension = read_imm_16(); + + if((g_cpu_type & M68010_LESS) && EXT_INDEX_SCALE(extension)) + { + invalid_mode = 1; + break; + } + + if(EXT_FULL(extension)) + { + if(g_cpu_type & M68010_LESS) + { + invalid_mode = 1; + break; + } + + if(EXT_EFFECTIVE_ZERO(extension)) + { + strcpy(mode, "0"); + break; + } + + base = EXT_BASE_DISPLACEMENT_PRESENT(extension) ? (EXT_BASE_DISPLACEMENT_LONG(extension) ? read_imm_32() : read_imm_16()) : 0; + outer = EXT_OUTER_DISPLACEMENT_PRESENT(extension) ? (EXT_OUTER_DISPLACEMENT_LONG(extension) ? read_imm_32() : read_imm_16()) : 0; + if(EXT_BASE_REGISTER_PRESENT(extension)) + sprintf(base_reg, "A%d", instruction&7); + else + *base_reg = 0; + if(EXT_INDEX_REGISTER_PRESENT(extension)) + { + sprintf(index_reg, "%c%d.%c", EXT_INDEX_AR(extension) ? 'A' : 'D', EXT_INDEX_REGISTER(extension), EXT_INDEX_LONG(extension) ? 'l' : 'w'); + if(EXT_INDEX_SCALE(extension)) + sprintf(index_reg+strlen(index_reg), "*%d", 1 << EXT_INDEX_SCALE(extension)); + } + else + *index_reg = 0; + preindex = (extension&7) > 0 && (extension&7) < 4; + postindex = (extension&7) > 4; + + strcpy(mode, "("); + if(preindex || postindex) + strcat(mode, "["); + if(base) + { + strcat(mode, make_signed_hex_str_16(base)); + comma = 1; + } + if(*base_reg) + { + if(comma) + strcat(mode, ","); + strcat(mode, base_reg); + comma = 1; + } + if(postindex) + { + strcat(mode, "]"); + comma = 1; + } + if(*index_reg) + { + if(comma) + strcat(mode, ","); + strcat(mode, index_reg); + comma = 1; + } + if(preindex) + { + strcat(mode, "]"); + comma = 1; + } + if(outer) + { + if(comma) + strcat(mode, ","); + strcat(mode, make_signed_hex_str_16(outer)); + } + strcat(mode, ")"); + break; + } + + if(EXT_8BIT_DISPLACEMENT(extension) == 0) + sprintf(mode, "(A%d,%c%d.%c", instruction&7, EXT_INDEX_AR(extension) ? 'A' : 'D', EXT_INDEX_REGISTER(extension), EXT_INDEX_LONG(extension) ? 'l' : 'w'); + else + sprintf(mode, "(%s,A%d,%c%d.%c", make_signed_hex_str_8(extension), instruction&7, EXT_INDEX_AR(extension) ? 'A' : 'D', EXT_INDEX_REGISTER(extension), EXT_INDEX_LONG(extension) ? 'l' : 'w'); + if(EXT_INDEX_SCALE(extension)) + sprintf(mode+strlen(mode), "*%d", 1 << EXT_INDEX_SCALE(extension)); + strcat(mode, ")"); + break; + case 0x38: + /* absolute short address */ + sprintf(mode, "$%x.w", read_imm_16()); + break; + case 0x39: + /* absolute long address */ + sprintf(mode, "$%x.l", read_imm_32()); + break; + case 0x3a: + /* program counter with displacement */ + temp_value = read_imm_16(); + sprintf(mode, "(%s,PC)", make_signed_hex_str_16(temp_value)); + sprintf(g_helper_str, "; ($%x)", (make_int_16(temp_value) + g_cpu_pc-2) & 0xffffffff); + break; + case 0x3b: + /* program counter with index */ + extension = read_imm_16(); + + if((g_cpu_type & M68010_LESS) && EXT_INDEX_SCALE(extension)) + { + invalid_mode = 1; + break; + } + + if(EXT_FULL(extension)) + { + if(g_cpu_type & M68010_LESS) + { + invalid_mode = 1; + break; + } + + if(EXT_EFFECTIVE_ZERO(extension)) + { + strcpy(mode, "0"); + break; + } + base = EXT_BASE_DISPLACEMENT_PRESENT(extension) ? (EXT_BASE_DISPLACEMENT_LONG(extension) ? read_imm_32() : read_imm_16()) : 0; + outer = EXT_OUTER_DISPLACEMENT_PRESENT(extension) ? (EXT_OUTER_DISPLACEMENT_LONG(extension) ? read_imm_32() : read_imm_16()) : 0; + if(EXT_BASE_REGISTER_PRESENT(extension)) + strcpy(base_reg, "PC"); + else + *base_reg = 0; + if(EXT_INDEX_REGISTER_PRESENT(extension)) + { + sprintf(index_reg, "%c%d.%c", EXT_INDEX_AR(extension) ? 'A' : 'D', EXT_INDEX_REGISTER(extension), EXT_INDEX_LONG(extension) ? 'l' : 'w'); + if(EXT_INDEX_SCALE(extension)) + sprintf(index_reg+strlen(index_reg), "*%d", 1 << EXT_INDEX_SCALE(extension)); + } + else + *index_reg = 0; + preindex = (extension&7) > 0 && (extension&7) < 4; + postindex = (extension&7) > 4; + + strcpy(mode, "("); + if(preindex || postindex) + strcat(mode, "["); + if(base) + { + strcat(mode, make_signed_hex_str_16(base)); + comma = 1; + } + if(*base_reg) + { + if(comma) + strcat(mode, ","); + strcat(mode, base_reg); + comma = 1; + } + if(postindex) + { + strcat(mode, "]"); + comma = 1; + } + if(*index_reg) + { + if(comma) + strcat(mode, ","); + strcat(mode, index_reg); + comma = 1; + } + if(preindex) + { + strcat(mode, "]"); + comma = 1; + } + if(outer) + { + if(comma) + strcat(mode, ","); + strcat(mode, make_signed_hex_str_16(outer)); + } + strcat(mode, ")"); + break; + } + + if(EXT_8BIT_DISPLACEMENT(extension) == 0) + sprintf(mode, "(PC,%c%d.%c", EXT_INDEX_AR(extension) ? 'A' : 'D', EXT_INDEX_REGISTER(extension), EXT_INDEX_LONG(extension) ? 'l' : 'w'); + else + sprintf(mode, "(%s,PC,%c%d.%c", make_signed_hex_str_8(extension), EXT_INDEX_AR(extension) ? 'A' : 'D', EXT_INDEX_REGISTER(extension), EXT_INDEX_LONG(extension) ? 'l' : 'w'); + if(EXT_INDEX_SCALE(extension)) + sprintf(mode+strlen(mode), "*%d", 1 << EXT_INDEX_SCALE(extension)); + strcat(mode, ")"); + break; + case 0x3c: + /* Immediate */ + sprintf(mode, "%s", get_imm_str_u(size)); + break; + default: + invalid_mode = 1; + } + + if(invalid_mode) + sprintf(mode, "INVALID %x", instruction & 0x3f); + + return mode; +} + + + +/* ======================================================================== */ +/* ========================= INSTRUCTION HANDLERS ========================= */ +/* ======================================================================== */ +/* Instruction handler function names follow this convention: + * + * d68000_NAME_EXTENSIONS(void) + * where NAME is the name of the opcode it handles and EXTENSIONS are any + * extensions for special instances of that opcode. + * + * Examples: + * d68000_add_er_8(): add opcode, from effective address to register, + * size = byte + * + * d68000_asr_s_8(): arithmetic shift right, static count, size = byte + * + * + * Common extensions: + * 8 : size = byte + * 16 : size = word + * 32 : size = long + * rr : register to register + * mm : memory to memory + * r : register + * s : static + * er : effective address -> register + * re : register -> effective address + * ea : using effective address mode of operation + * d : data register direct + * a : address register direct + * ai : address register indirect + * pi : address register indirect with postincrement + * pd : address register indirect with predecrement + * di : address register indirect with displacement + * ix : address register indirect with index + * aw : absolute word + * al : absolute long + */ + +static void d68000_illegal(void) +{ + sprintf(g_dasm_str, "dc.w $%04x; ILLEGAL", g_cpu_ir); +} + +static void d68000_1010(void) +{ + sprintf(g_dasm_str, "dc.w $%04x; opcode 1010", g_cpu_ir); +} + + +static void d68000_1111(void) +{ + sprintf(g_dasm_str, "dc.w $%04x; opcode 1111", g_cpu_ir); +} + + +static void d68000_abcd_rr(void) +{ + sprintf(g_dasm_str, "abcd D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + + +static void d68000_abcd_mm(void) +{ + sprintf(g_dasm_str, "abcd -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_add_er_8(void) +{ + sprintf(g_dasm_str, "add.b %s, D%d", get_ea_mode_str_8(g_cpu_ir), (g_cpu_ir>>9)&7); +} + + +static void d68000_add_er_16(void) +{ + sprintf(g_dasm_str, "add.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_add_er_32(void) +{ + sprintf(g_dasm_str, "add.l %s, D%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_add_re_8(void) +{ + sprintf(g_dasm_str, "add.b D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_add_re_16(void) +{ + sprintf(g_dasm_str, "add.w D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_add_re_32(void) +{ + sprintf(g_dasm_str, "add.l D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_adda_16(void) +{ + sprintf(g_dasm_str, "adda.w %s, A%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_adda_32(void) +{ + sprintf(g_dasm_str, "adda.l %s, A%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_addi_8(void) +{ + char* str = get_imm_str_s8(); + sprintf(g_dasm_str, "addi.b %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_addi_16(void) +{ + char* str = get_imm_str_s16(); + sprintf(g_dasm_str, "addi.w %s, %s", str, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_addi_32(void) +{ + char* str = get_imm_str_s32(); + sprintf(g_dasm_str, "addi.l %s, %s", str, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_addq_8(void) +{ + sprintf(g_dasm_str, "addq.b #%d, %s", g_3bit_qdata_table[(g_cpu_ir>>9)&7], get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_addq_16(void) +{ + sprintf(g_dasm_str, "addq.w #%d, %s", g_3bit_qdata_table[(g_cpu_ir>>9)&7], get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_addq_32(void) +{ + sprintf(g_dasm_str, "addq.l #%d, %s", g_3bit_qdata_table[(g_cpu_ir>>9)&7], get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_addx_rr_8(void) +{ + sprintf(g_dasm_str, "addx.b D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_addx_rr_16(void) +{ + sprintf(g_dasm_str, "addx.w D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_addx_rr_32(void) +{ + sprintf(g_dasm_str, "addx.l D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_addx_mm_8(void) +{ + sprintf(g_dasm_str, "addx.b -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_addx_mm_16(void) +{ + sprintf(g_dasm_str, "addx.w -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_addx_mm_32(void) +{ + sprintf(g_dasm_str, "addx.l -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_and_er_8(void) +{ + sprintf(g_dasm_str, "and.b %s, D%d", get_ea_mode_str_8(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_and_er_16(void) +{ + sprintf(g_dasm_str, "and.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_and_er_32(void) +{ + sprintf(g_dasm_str, "and.l %s, D%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_and_re_8(void) +{ + sprintf(g_dasm_str, "and.b D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_and_re_16(void) +{ + sprintf(g_dasm_str, "and.w D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_and_re_32(void) +{ + sprintf(g_dasm_str, "and.l D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_andi_8(void) +{ + char* str = get_imm_str_u8(); + sprintf(g_dasm_str, "andi.b %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_andi_16(void) +{ + char* str = get_imm_str_u16(); + sprintf(g_dasm_str, "andi.w %s, %s", str, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_andi_32(void) +{ + char* str = get_imm_str_u32(); + sprintf(g_dasm_str, "andi.l %s, %s", str, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_andi_to_ccr(void) +{ + sprintf(g_dasm_str, "andi %s, CCR", get_imm_str_u8()); +} + +static void d68000_andi_to_sr(void) +{ + sprintf(g_dasm_str, "andi %s, SR", get_imm_str_u16()); +} + +static void d68000_asr_s_8(void) +{ + sprintf(g_dasm_str, "asr.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_asr_s_16(void) +{ + sprintf(g_dasm_str, "asr.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_asr_s_32(void) +{ + sprintf(g_dasm_str, "asr.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_asr_r_8(void) +{ + sprintf(g_dasm_str, "asr.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_asr_r_16(void) +{ + sprintf(g_dasm_str, "asr.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_asr_r_32(void) +{ + sprintf(g_dasm_str, "asr.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_asr_ea(void) +{ + sprintf(g_dasm_str, "asr.w %s", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_asl_s_8(void) +{ + sprintf(g_dasm_str, "asl.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_asl_s_16(void) +{ + sprintf(g_dasm_str, "asl.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_asl_s_32(void) +{ + sprintf(g_dasm_str, "asl.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_asl_r_8(void) +{ + sprintf(g_dasm_str, "asl.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_asl_r_16(void) +{ + sprintf(g_dasm_str, "asl.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_asl_r_32(void) +{ + sprintf(g_dasm_str, "asl.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_asl_ea(void) +{ + sprintf(g_dasm_str, "asl.w %s", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_bcc_8(void) +{ + uint temp_pc = g_cpu_pc; + sprintf(g_dasm_str, "b%-2s $%x", g_cc[(g_cpu_ir>>8)&0xf], temp_pc + make_int_8(g_cpu_ir)); +} + +static void d68000_bcc_16(void) +{ + uint temp_pc = g_cpu_pc; + sprintf(g_dasm_str, "b%-2s $%x", g_cc[(g_cpu_ir>>8)&0xf], temp_pc + make_int_16(read_imm_16())); +} + +static void d68020_bcc_32(void) +{ + uint temp_pc = g_cpu_pc; + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "b%-2s $%x; (2+)", g_cc[(g_cpu_ir>>8)&0xf], temp_pc + read_imm_32()); +} + +static void d68000_bchg_r(void) +{ + sprintf(g_dasm_str, "bchg D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_bchg_s(void) +{ + char* str = get_imm_str_u8(); + sprintf(g_dasm_str, "bchg %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_bclr_r(void) +{ + sprintf(g_dasm_str, "bclr D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_bclr_s(void) +{ + char* str = get_imm_str_u8(); + sprintf(g_dasm_str, "bclr %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68010_bkpt(void) +{ + LIMIT_CPU_TYPES(M68010_PLUS); + sprintf(g_dasm_str, "bkpt #%d; (1+)", g_cpu_ir&7); +} + +static void d68020_bfchg(void) +{ + uint extension; + char offset[3]; + char width[3]; + + LIMIT_CPU_TYPES(M68020_PLUS); + + extension = read_imm_16(); + + if(BIT_B(extension)) + sprintf(offset, "D%d", (extension>>6)&7); + else + sprintf(offset, "%d", (extension>>6)&31); + if(BIT_5(extension)) + sprintf(width, "D%d", extension&7); + else + sprintf(width, "%d", g_5bit_data_table[extension&31]); + sprintf(g_dasm_str, "bfchg %s {%s:%s}; (2+)", get_ea_mode_str_8(g_cpu_ir), offset, width); +} + +static void d68020_bfclr(void) +{ + uint extension; + char offset[3]; + char width[3]; + + LIMIT_CPU_TYPES(M68020_PLUS); + + extension = read_imm_16(); + + if(BIT_B(extension)) + sprintf(offset, "D%d", (extension>>6)&7); + else + sprintf(offset, "%d", (extension>>6)&31); + if(BIT_5(extension)) + sprintf(width, "D%d", extension&7); + else + sprintf(width, "%d", g_5bit_data_table[extension&31]); + sprintf(g_dasm_str, "bfclr %s {%s:%s}; (2+)", get_ea_mode_str_8(g_cpu_ir), offset, width); +} + +static void d68020_bfexts(void) +{ + uint extension; + char offset[3]; + char width[3]; + + LIMIT_CPU_TYPES(M68020_PLUS); + + extension = read_imm_16(); + + if(BIT_B(extension)) + sprintf(offset, "D%d", (extension>>6)&7); + else + sprintf(offset, "%d", (extension>>6)&31); + if(BIT_5(extension)) + sprintf(width, "D%d", extension&7); + else + sprintf(width, "%d", g_5bit_data_table[extension&31]); + sprintf(g_dasm_str, "bfexts D%d, %s {%s:%s}; (2+)", (extension>>12)&7, get_ea_mode_str_8(g_cpu_ir), offset, width); +} + +static void d68020_bfextu(void) +{ + uint extension; + char offset[3]; + char width[3]; + + LIMIT_CPU_TYPES(M68020_PLUS); + + extension = read_imm_16(); + + if(BIT_B(extension)) + sprintf(offset, "D%d", (extension>>6)&7); + else + sprintf(offset, "%d", (extension>>6)&31); + if(BIT_5(extension)) + sprintf(width, "D%d", extension&7); + else + sprintf(width, "%d", g_5bit_data_table[extension&31]); + sprintf(g_dasm_str, "bfextu D%d, %s {%s:%s}; (2+)", (extension>>12)&7, get_ea_mode_str_8(g_cpu_ir), offset, width); +} + +static void d68020_bfffo(void) +{ + uint extension; + char offset[3]; + char width[3]; + + LIMIT_CPU_TYPES(M68020_PLUS); + + extension = read_imm_16(); + + if(BIT_B(extension)) + sprintf(offset, "D%d", (extension>>6)&7); + else + sprintf(offset, "%d", (extension>>6)&31); + if(BIT_5(extension)) + sprintf(width, "D%d", extension&7); + else + sprintf(width, "%d", g_5bit_data_table[extension&31]); + sprintf(g_dasm_str, "bfffo D%d, %s {%s:%s}; (2+)", (extension>>12)&7, get_ea_mode_str_8(g_cpu_ir), offset, width); +} + +static void d68020_bfins(void) +{ + uint extension; + char offset[3]; + char width[3]; + + LIMIT_CPU_TYPES(M68020_PLUS); + + extension = read_imm_16(); + + if(BIT_B(extension)) + sprintf(offset, "D%d", (extension>>6)&7); + else + sprintf(offset, "%d", (extension>>6)&31); + if(BIT_5(extension)) + sprintf(width, "D%d", extension&7); + else + sprintf(width, "%d", g_5bit_data_table[extension&31]); + sprintf(g_dasm_str, "bfins D%d, %s {%s:%s}; (2+)", (extension>>12)&7, get_ea_mode_str_8(g_cpu_ir), offset, width); +} + +static void d68020_bfset(void) +{ + uint extension; + char offset[3]; + char width[3]; + + LIMIT_CPU_TYPES(M68020_PLUS); + + extension = read_imm_16(); + + if(BIT_B(extension)) + sprintf(offset, "D%d", (extension>>6)&7); + else + sprintf(offset, "%d", (extension>>6)&31); + if(BIT_5(extension)) + sprintf(width, "D%d", extension&7); + else + sprintf(width, "%d", g_5bit_data_table[extension&31]); + sprintf(g_dasm_str, "bfset %s {%s:%s}; (2+)", get_ea_mode_str_8(g_cpu_ir), offset, width); +} + +static void d68020_bftst(void) +{ + uint extension; + char offset[3]; + char width[3]; + + LIMIT_CPU_TYPES(M68020_PLUS); + + extension = read_imm_16(); + + if(BIT_B(extension)) + sprintf(offset, "D%d", (extension>>6)&7); + else + sprintf(offset, "%d", (extension>>6)&31); + if(BIT_5(extension)) + sprintf(width, "D%d", extension&7); + else + sprintf(width, "%d", g_5bit_data_table[extension&31]); + sprintf(g_dasm_str, "bftst %s {%s:%s}; (2+)", get_ea_mode_str_8(g_cpu_ir), offset, width); +} + +static void d68000_bra_8(void) +{ + uint temp_pc = g_cpu_pc; + sprintf(g_dasm_str, "bra $%x", temp_pc + make_int_8(g_cpu_ir)); +} + +static void d68000_bra_16(void) +{ + uint temp_pc = g_cpu_pc; + sprintf(g_dasm_str, "bra $%x", temp_pc + make_int_16(read_imm_16())); +} + +static void d68020_bra_32(void) +{ + uint temp_pc = g_cpu_pc; + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "bra $%x; (2+)", temp_pc + read_imm_32()); +} + +static void d68000_bset_r(void) +{ + sprintf(g_dasm_str, "bset D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_bset_s(void) +{ + char* str = get_imm_str_u8(); + sprintf(g_dasm_str, "bset %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_bsr_8(void) +{ + uint temp_pc = g_cpu_pc; + sprintf(g_dasm_str, "bsr $%x", temp_pc + make_int_8(g_cpu_ir)); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER); +} + +static void d68000_bsr_16(void) +{ + uint temp_pc = g_cpu_pc; + sprintf(g_dasm_str, "bsr $%x", temp_pc + make_int_16(read_imm_16())); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER); +} + +static void d68020_bsr_32(void) +{ + uint temp_pc = g_cpu_pc; + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "bsr $%x; (2+)", temp_pc + read_imm_32()); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER); +} + +static void d68000_btst_r(void) +{ + sprintf(g_dasm_str, "btst D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_btst_s(void) +{ + char* str = get_imm_str_u8(); + sprintf(g_dasm_str, "btst %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68020_callm(void) +{ + char* str; + LIMIT_CPU_TYPES(M68020_ONLY); + str = get_imm_str_u8(); + + sprintf(g_dasm_str, "callm %s, %s; (2)", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68020_cas_8(void) +{ + uint extension; + LIMIT_CPU_TYPES(M68020_PLUS); + extension = read_imm_16(); + sprintf(g_dasm_str, "cas.b D%d, D%d, %s; (2+)", extension&7, (extension>>8)&7, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68020_cas_16(void) +{ + uint extension; + LIMIT_CPU_TYPES(M68020_PLUS); + extension = read_imm_16(); + sprintf(g_dasm_str, "cas.w D%d, D%d, %s; (2+)", extension&7, (extension>>8)&7, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68020_cas_32(void) +{ + uint extension; + LIMIT_CPU_TYPES(M68020_PLUS); + extension = read_imm_16(); + sprintf(g_dasm_str, "cas.l D%d, D%d, %s; (2+)", extension&7, (extension>>8)&7, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68020_cas2_16(void) +{ +/* CAS2 Dc1:Dc2,Du1:Dc2:(Rn1):(Rn2) +f e d c b a 9 8 7 6 5 4 3 2 1 0 + DARn1 0 0 0 Du1 0 0 0 Dc1 + DARn2 0 0 0 Du2 0 0 0 Dc2 +*/ + + uint extension; + LIMIT_CPU_TYPES(M68020_PLUS); + extension = read_imm_32(); + sprintf(g_dasm_str, "cas2.w D%d:D%d:D%d:D%d, (%c%d):(%c%d); (2+)", + (extension>>16)&7, extension&7, (extension>>22)&7, (extension>>6)&7, + BIT_1F(extension) ? 'A' : 'D', (extension>>28)&7, + BIT_F(extension) ? 'A' : 'D', (extension>>12)&7); +} + +static void d68020_cas2_32(void) +{ + uint extension; + LIMIT_CPU_TYPES(M68020_PLUS); + extension = read_imm_32(); + sprintf(g_dasm_str, "cas2.l D%d:D%d:D%d:D%d, (%c%d):(%c%d); (2+)", + (extension>>16)&7, extension&7, (extension>>22)&7, (extension>>6)&7, + BIT_1F(extension) ? 'A' : 'D', (extension>>28)&7, + BIT_F(extension) ? 'A' : 'D', (extension>>12)&7); +} + +static void d68000_chk_16(void) +{ + sprintf(g_dasm_str, "chk.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER); +} + +static void d68020_chk_32(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "chk.l %s, D%d; (2+)", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER); +} + +static void d68020_chk2_cmp2_8(void) +{ + uint extension; + LIMIT_CPU_TYPES(M68020_PLUS); + extension = read_imm_16(); + sprintf(g_dasm_str, "%s.b %s, %c%d; (2+)", BIT_B(extension) ? "chk2" : "cmp2", get_ea_mode_str_8(g_cpu_ir), BIT_F(extension) ? 'A' : 'D', (extension>>12)&7); +} + +static void d68020_chk2_cmp2_16(void) +{ + uint extension; + LIMIT_CPU_TYPES(M68020_PLUS); + extension = read_imm_16(); + sprintf(g_dasm_str, "%s.w %s, %c%d; (2+)", BIT_B(extension) ? "chk2" : "cmp2", get_ea_mode_str_16(g_cpu_ir), BIT_F(extension) ? 'A' : 'D', (extension>>12)&7); +} + +static void d68020_chk2_cmp2_32(void) +{ + uint extension; + LIMIT_CPU_TYPES(M68020_PLUS); + extension = read_imm_16(); + sprintf(g_dasm_str, "%s.l %s, %c%d; (2+)", BIT_B(extension) ? "chk2" : "cmp2", get_ea_mode_str_32(g_cpu_ir), BIT_F(extension) ? 'A' : 'D', (extension>>12)&7); +} + +static void d68040_cinv(void) +{ + LIMIT_CPU_TYPES(M68040_PLUS); + switch((g_cpu_ir>>3)&3) + { + case 0: + sprintf(g_dasm_str, "cinv (illegal scope); (4)"); + break; + case 1: + sprintf(g_dasm_str, "cinvl %d, (A%d); (4)", (g_cpu_ir>>6)&3, g_cpu_ir&7); + break; + case 2: + sprintf(g_dasm_str, "cinvp %d, (A%d); (4)", (g_cpu_ir>>6)&3, g_cpu_ir&7); + break; + case 3: + sprintf(g_dasm_str, "cinva %d; (4)", (g_cpu_ir>>6)&3); + break; + } +} + +static void d68000_clr_8(void) +{ + sprintf(g_dasm_str, "clr.b %s", get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_clr_16(void) +{ + sprintf(g_dasm_str, "clr.w %s", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_clr_32(void) +{ + sprintf(g_dasm_str, "clr.l %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_cmp_8(void) +{ + sprintf(g_dasm_str, "cmp.b %s, D%d", get_ea_mode_str_8(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_cmp_16(void) +{ + sprintf(g_dasm_str, "cmp.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_cmp_32(void) +{ + sprintf(g_dasm_str, "cmp.l %s, D%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_cmpa_16(void) +{ + sprintf(g_dasm_str, "cmpa.w %s, A%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_cmpa_32(void) +{ + sprintf(g_dasm_str, "cmpa.l %s, A%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_cmpi_8(void) +{ + char* str = get_imm_str_s8(); + sprintf(g_dasm_str, "cmpi.b %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68020_cmpi_pcdi_8(void) +{ + char* str; + LIMIT_CPU_TYPES(M68010_PLUS); + str = get_imm_str_s8(); + sprintf(g_dasm_str, "cmpi.b %s, %s; (2+)", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68020_cmpi_pcix_8(void) +{ + char* str; + LIMIT_CPU_TYPES(M68010_PLUS); + str = get_imm_str_s8(); + sprintf(g_dasm_str, "cmpi.b %s, %s; (2+)", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_cmpi_16(void) +{ + char* str; + str = get_imm_str_s16(); + sprintf(g_dasm_str, "cmpi.w %s, %s", str, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68020_cmpi_pcdi_16(void) +{ + char* str; + LIMIT_CPU_TYPES(M68010_PLUS); + str = get_imm_str_s16(); + sprintf(g_dasm_str, "cmpi.w %s, %s; (2+)", str, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68020_cmpi_pcix_16(void) +{ + char* str; + LIMIT_CPU_TYPES(M68010_PLUS); + str = get_imm_str_s16(); + sprintf(g_dasm_str, "cmpi.w %s, %s; (2+)", str, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_cmpi_32(void) +{ + char* str; + str = get_imm_str_s32(); + sprintf(g_dasm_str, "cmpi.l %s, %s", str, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68020_cmpi_pcdi_32(void) +{ + char* str; + LIMIT_CPU_TYPES(M68010_PLUS); + str = get_imm_str_s32(); + sprintf(g_dasm_str, "cmpi.l %s, %s; (2+)", str, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68020_cmpi_pcix_32(void) +{ + char* str; + LIMIT_CPU_TYPES(M68010_PLUS); + str = get_imm_str_s32(); + sprintf(g_dasm_str, "cmpi.l %s, %s; (2+)", str, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_cmpm_8(void) +{ + sprintf(g_dasm_str, "cmpm.b (A%d)+, (A%d)+", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_cmpm_16(void) +{ + sprintf(g_dasm_str, "cmpm.w (A%d)+, (A%d)+", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_cmpm_32(void) +{ + sprintf(g_dasm_str, "cmpm.l (A%d)+, (A%d)+", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68020_cpbcc_16(void) +{ + uint extension; + uint new_pc = g_cpu_pc; + LIMIT_CPU_TYPES(M68020_PLUS); + extension = read_imm_16(); + new_pc += make_int_16(read_imm_16()); + sprintf(g_dasm_str, "%db%-4s %s; %x (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[g_cpu_ir&0x3f], get_imm_str_s16(), new_pc, extension); +} + +static void d68020_cpbcc_32(void) +{ + uint extension; + uint new_pc = g_cpu_pc; + LIMIT_CPU_TYPES(M68020_PLUS); + extension = read_imm_16(); + new_pc += read_imm_32(); + sprintf(g_dasm_str, "%db%-4s %s; %x (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[g_cpu_ir&0x3f], get_imm_str_s16(), new_pc, extension); +} + +static void d68020_cpdbcc(void) +{ + uint extension1; + uint extension2; + uint new_pc = g_cpu_pc; + LIMIT_CPU_TYPES(M68020_PLUS); + extension1 = read_imm_16(); + extension2 = read_imm_16(); + new_pc += make_int_16(read_imm_16()); + sprintf(g_dasm_str, "%ddb%-4s D%d,%s; %x (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[extension1&0x3f], g_cpu_ir&7, get_imm_str_s16(), new_pc, extension2); +} + +static void d68020_cpgen(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "%dgen %s; (2-3)", (g_cpu_ir>>9)&7, get_imm_str_u32()); +} + +static void d68020_cprestore(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "%drestore %s; (2-3)", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68020_cpsave(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "%dsave %s; (2-3)", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68020_cpscc(void) +{ + uint extension1; + uint extension2; + LIMIT_CPU_TYPES(M68020_PLUS); + extension1 = read_imm_16(); + extension2 = read_imm_16(); + sprintf(g_dasm_str, "%ds%-4s %s; (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[extension1&0x3f], get_ea_mode_str_8(g_cpu_ir), extension2); +} + +static void d68020_cptrapcc_0(void) +{ + uint extension1; + uint extension2; + LIMIT_CPU_TYPES(M68020_PLUS); + extension1 = read_imm_16(); + extension2 = read_imm_16(); + sprintf(g_dasm_str, "%dtrap%-4s; (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[extension1&0x3f], extension2); +} + +static void d68020_cptrapcc_16(void) +{ + uint extension1; + uint extension2; + LIMIT_CPU_TYPES(M68020_PLUS); + extension1 = read_imm_16(); + extension2 = read_imm_16(); + sprintf(g_dasm_str, "%dtrap%-4s %s; (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[extension1&0x3f], get_imm_str_u16(), extension2); +} + +static void d68020_cptrapcc_32(void) +{ + uint extension1; + uint extension2; + LIMIT_CPU_TYPES(M68020_PLUS); + extension1 = read_imm_16(); + extension2 = read_imm_16(); + sprintf(g_dasm_str, "%dtrap%-4s %s; (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[extension1&0x3f], get_imm_str_u32(), extension2); +} + +static void d68040_cpush(void) +{ + LIMIT_CPU_TYPES(M68040_PLUS); + switch((g_cpu_ir>>3)&3) + { + case 0: + sprintf(g_dasm_str, "cpush (illegal scope); (4)"); + break; + case 1: + sprintf(g_dasm_str, "cpushl %d, (A%d); (4)", (g_cpu_ir>>6)&3, g_cpu_ir&7); + break; + case 2: + sprintf(g_dasm_str, "cpushp %d, (A%d); (4)", (g_cpu_ir>>6)&3, g_cpu_ir&7); + break; + case 3: + sprintf(g_dasm_str, "cpusha %d; (4)", (g_cpu_ir>>6)&3); + break; + } +} + +static void d68000_dbra(void) +{ + uint temp_pc = g_cpu_pc; + sprintf(g_dasm_str, "dbra D%d, $%x", g_cpu_ir & 7, temp_pc + make_int_16(read_imm_16())); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER); +} + +static void d68000_dbcc(void) +{ + uint temp_pc = g_cpu_pc; + sprintf(g_dasm_str, "db%-2s D%d, $%x", g_cc[(g_cpu_ir>>8)&0xf], g_cpu_ir & 7, temp_pc + make_int_16(read_imm_16())); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER); +} + +static void d68000_divs(void) +{ + sprintf(g_dasm_str, "divs.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_divu(void) +{ + sprintf(g_dasm_str, "divu.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68020_divl(void) +{ + uint extension; + LIMIT_CPU_TYPES(M68020_PLUS); + extension = read_imm_16(); + + if(BIT_A(extension)) + sprintf(g_dasm_str, "div%c.l %s, D%d:D%d; (2+)", BIT_B(extension) ? 's' : 'u', get_ea_mode_str_32(g_cpu_ir), extension&7, (extension>>12)&7); + else if((extension&7) == ((extension>>12)&7)) + sprintf(g_dasm_str, "div%c.l %s, D%d; (2+)", BIT_B(extension) ? 's' : 'u', get_ea_mode_str_32(g_cpu_ir), (extension>>12)&7); + else + sprintf(g_dasm_str, "div%cl.l %s, D%d:D%d; (2+)", BIT_B(extension) ? 's' : 'u', get_ea_mode_str_32(g_cpu_ir), extension&7, (extension>>12)&7); +} + +static void d68000_eor_8(void) +{ + sprintf(g_dasm_str, "eor.b D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_eor_16(void) +{ + sprintf(g_dasm_str, "eor.w D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_eor_32(void) +{ + sprintf(g_dasm_str, "eor.l D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_eori_8(void) +{ + char* str = get_imm_str_u8(); + sprintf(g_dasm_str, "eori.b %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_eori_16(void) +{ + char* str = get_imm_str_u16(); + sprintf(g_dasm_str, "eori.w %s, %s", str, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_eori_32(void) +{ + char* str = get_imm_str_u32(); + sprintf(g_dasm_str, "eori.l %s, %s", str, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_eori_to_ccr(void) +{ + sprintf(g_dasm_str, "eori %s, CCR", get_imm_str_u8()); +} + +static void d68000_eori_to_sr(void) +{ + sprintf(g_dasm_str, "eori %s, SR", get_imm_str_u16()); +} + +static void d68000_exg_dd(void) +{ + sprintf(g_dasm_str, "exg D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_exg_aa(void) +{ + sprintf(g_dasm_str, "exg A%d, A%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_exg_da(void) +{ + sprintf(g_dasm_str, "exg D%d, A%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_ext_16(void) +{ + sprintf(g_dasm_str, "ext.w D%d", g_cpu_ir&7); +} + +static void d68000_ext_32(void) +{ + sprintf(g_dasm_str, "ext.l D%d", g_cpu_ir&7); +} + +static void d68020_extb_32(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "extb.l D%d; (2+)", g_cpu_ir&7); +} + +static void d68000_jmp(void) +{ + sprintf(g_dasm_str, "jmp %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_jsr(void) +{ + sprintf(g_dasm_str, "jsr %s", get_ea_mode_str_32(g_cpu_ir)); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER); +} + +static void d68000_lea(void) +{ + sprintf(g_dasm_str, "lea %s, A%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_link_16(void) +{ + sprintf(g_dasm_str, "link A%d, %s", g_cpu_ir&7, get_imm_str_s16()); +} + +static void d68020_link_32(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "link A%d, %s; (2+)", g_cpu_ir&7, get_imm_str_s32()); +} + +static void d68000_lsr_s_8(void) +{ + sprintf(g_dasm_str, "lsr.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_lsr_s_16(void) +{ + sprintf(g_dasm_str, "lsr.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_lsr_s_32(void) +{ + sprintf(g_dasm_str, "lsr.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_lsr_r_8(void) +{ + sprintf(g_dasm_str, "lsr.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_lsr_r_16(void) +{ + sprintf(g_dasm_str, "lsr.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_lsr_r_32(void) +{ + sprintf(g_dasm_str, "lsr.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_lsr_ea(void) +{ + sprintf(g_dasm_str, "lsr.w %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_lsl_s_8(void) +{ + sprintf(g_dasm_str, "lsl.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_lsl_s_16(void) +{ + sprintf(g_dasm_str, "lsl.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_lsl_s_32(void) +{ + sprintf(g_dasm_str, "lsl.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_lsl_r_8(void) +{ + sprintf(g_dasm_str, "lsl.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_lsl_r_16(void) +{ + sprintf(g_dasm_str, "lsl.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_lsl_r_32(void) +{ + sprintf(g_dasm_str, "lsl.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_lsl_ea(void) +{ + sprintf(g_dasm_str, "lsl.w %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_move_8(void) +{ + char* str = get_ea_mode_str_8(g_cpu_ir); + sprintf(g_dasm_str, "move.b %s, %s", str, get_ea_mode_str_8(((g_cpu_ir>>9) & 7) | ((g_cpu_ir>>3) & 0x38))); +} + +static void d68000_move_16(void) +{ + char* str = get_ea_mode_str_16(g_cpu_ir); + sprintf(g_dasm_str, "move.w %s, %s", str, get_ea_mode_str_16(((g_cpu_ir>>9) & 7) | ((g_cpu_ir>>3) & 0x38))); +} + +static void d68000_move_32(void) +{ + char* str = get_ea_mode_str_32(g_cpu_ir); + sprintf(g_dasm_str, "move.l %s, %s", str, get_ea_mode_str_32(((g_cpu_ir>>9) & 7) | ((g_cpu_ir>>3) & 0x38))); +} + +static void d68000_movea_16(void) +{ + sprintf(g_dasm_str, "movea.w %s, A%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_movea_32(void) +{ + sprintf(g_dasm_str, "movea.l %s, A%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_move_to_ccr(void) +{ + sprintf(g_dasm_str, "move %s, CCR", get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68010_move_fr_ccr(void) +{ + LIMIT_CPU_TYPES(M68010_PLUS); + sprintf(g_dasm_str, "move CCR, %s; (1+)", get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_move_fr_sr(void) +{ + sprintf(g_dasm_str, "move SR, %s", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_move_to_sr(void) +{ + sprintf(g_dasm_str, "move %s, SR", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_move_fr_usp(void) +{ + sprintf(g_dasm_str, "move USP, A%d", g_cpu_ir&7); +} + +static void d68000_move_to_usp(void) +{ + sprintf(g_dasm_str, "move A%d, USP", g_cpu_ir&7); +} + +static void d68010_movec(void) +{ + uint extension; + const char* reg_name; + const char* processor; + LIMIT_CPU_TYPES(M68010_PLUS); + extension = read_imm_16(); + + switch(extension & 0xfff) + { + case 0x000: + reg_name = "SFC"; + processor = "1+"; + break; + case 0x001: + reg_name = "DFC"; + processor = "1+"; + break; + case 0x800: + reg_name = "USP"; + processor = "1+"; + break; + case 0x801: + reg_name = "VBR"; + processor = "1+"; + break; + case 0x002: + reg_name = "CACR"; + processor = "2+"; + break; + case 0x802: + reg_name = "CAAR"; + processor = "2,3"; + break; + case 0x803: + reg_name = "MSP"; + processor = "2+"; + break; + case 0x804: + reg_name = "ISP"; + processor = "2+"; + break; + case 0x003: + reg_name = "TC"; + processor = "4+"; + break; + case 0x004: + reg_name = "ITT0"; + processor = "4+"; + break; + case 0x005: + reg_name = "ITT1"; + processor = "4+"; + break; + case 0x006: + reg_name = "DTT0"; + processor = "4+"; + break; + case 0x007: + reg_name = "DTT1"; + processor = "4+"; + break; + case 0x805: + reg_name = "MMUSR"; + processor = "4+"; + break; + case 0x806: + reg_name = "URP"; + processor = "4+"; + break; + case 0x807: + reg_name = "SRP"; + processor = "4+"; + break; + default: + reg_name = make_signed_hex_str_16(extension & 0xfff); + processor = "?"; + } + + if(BIT_1(g_cpu_ir)) + sprintf(g_dasm_str, "movec %c%d, %s; (%s)", BIT_F(extension) ? 'A' : 'D', (extension>>12)&7, reg_name, processor); + else + sprintf(g_dasm_str, "movec %s, %c%d; (%s)", reg_name, BIT_F(extension) ? 'A' : 'D', (extension>>12)&7, processor); +} + +static void d68000_movem_pd_16(void) +{ + uint data = read_imm_16(); + char buffer[40]; + uint first; + uint run_length; + uint i; + + buffer[0] = 0; + for(i=0;i<8;i++) + { + if(data&(1<<(15-i))) + { + first = i; + run_length = 0; + while(i<7 && (data&(1<<(15-(i+1))))) + { + i++; + run_length++; + } + if(buffer[0] != 0) + strcat(buffer, "/"); + sprintf(buffer+strlen(buffer), "D%d", first); + if(run_length > 0) + sprintf(buffer+strlen(buffer), "-D%d", first + run_length); + } + } + for(i=0;i<8;i++) + { + if(data&(1<<(7-i))) + { + first = i; + run_length = 0; + while(i<7 && (data&(1<<(7-(i+1))))) + { + i++; + run_length++; + } + if(buffer[0] != 0) + strcat(buffer, "/"); + sprintf(buffer+strlen(buffer), "A%d", first); + if(run_length > 0) + sprintf(buffer+strlen(buffer), "-A%d", first + run_length); + } + } + sprintf(g_dasm_str, "movem.w %s, %s", buffer, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_movem_pd_32(void) +{ + uint data = read_imm_16(); + char buffer[40]; + uint first; + uint run_length; + uint i; + + buffer[0] = 0; + for(i=0;i<8;i++) + { + if(data&(1<<(15-i))) + { + first = i; + run_length = 0; + while(i<7 && (data&(1<<(15-(i+1))))) + { + i++; + run_length++; + } + if(buffer[0] != 0) + strcat(buffer, "/"); + sprintf(buffer+strlen(buffer), "D%d", first); + if(run_length > 0) + sprintf(buffer+strlen(buffer), "-D%d", first + run_length); + } + } + for(i=0;i<8;i++) + { + if(data&(1<<(7-i))) + { + first = i; + run_length = 0; + while(i<7 && (data&(1<<(7-(i+1))))) + { + i++; + run_length++; + } + if(buffer[0] != 0) + strcat(buffer, "/"); + sprintf(buffer+strlen(buffer), "A%d", first); + if(run_length > 0) + sprintf(buffer+strlen(buffer), "-A%d", first + run_length); + } + } + sprintf(g_dasm_str, "movem.l %s, %s", buffer, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_movem_er_16(void) +{ + uint data = read_imm_16(); + char buffer[40]; + uint first; + uint run_length; + uint i; + + buffer[0] = 0; + for(i=0;i<8;i++) + { + if(data&(1< 0) + sprintf(buffer+strlen(buffer), "-D%d", first + run_length); + } + } + for(i=0;i<8;i++) + { + if(data&(1<<(i+8))) + { + first = i; + run_length = 0; + while(i<7 && (data&(1<<(i+8+1)))) + { + i++; + run_length++; + } + if(buffer[0] != 0) + strcat(buffer, "/"); + sprintf(buffer+strlen(buffer), "A%d", first); + if(run_length > 0) + sprintf(buffer+strlen(buffer), "-A%d", first + run_length); + } + } + sprintf(g_dasm_str, "movem.w %s, %s", get_ea_mode_str_16(g_cpu_ir), buffer); +} + +static void d68000_movem_er_32(void) +{ + uint data = read_imm_16(); + char buffer[40]; + uint first; + uint run_length; + uint i; + + buffer[0] = 0; + for(i=0;i<8;i++) + { + if(data&(1< 0) + sprintf(buffer+strlen(buffer), "-D%d", first + run_length); + } + } + for(i=0;i<8;i++) + { + if(data&(1<<(i+8))) + { + first = i; + run_length = 0; + while(i<7 && (data&(1<<(i+8+1)))) + { + i++; + run_length++; + } + if(buffer[0] != 0) + strcat(buffer, "/"); + sprintf(buffer+strlen(buffer), "A%d", first); + if(run_length > 0) + sprintf(buffer+strlen(buffer), "-A%d", first + run_length); + } + } + sprintf(g_dasm_str, "movem.l %s, %s", get_ea_mode_str_32(g_cpu_ir), buffer); +} + +static void d68000_movem_re_16(void) +{ + uint data = read_imm_16(); + char buffer[40]; + uint first; + uint run_length; + uint i; + + buffer[0] = 0; + for(i=0;i<8;i++) + { + if(data&(1< 0) + sprintf(buffer+strlen(buffer), "-D%d", first + run_length); + } + } + for(i=0;i<8;i++) + { + if(data&(1<<(i+8))) + { + first = i; + run_length = 0; + while(i<7 && (data&(1<<(i+8+1)))) + { + i++; + run_length++; + } + if(buffer[0] != 0) + strcat(buffer, "/"); + sprintf(buffer+strlen(buffer), "A%d", first); + if(run_length > 0) + sprintf(buffer+strlen(buffer), "-A%d", first + run_length); + } + } + sprintf(g_dasm_str, "movem.w %s, %s", buffer, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_movem_re_32(void) +{ + uint data = read_imm_16(); + char buffer[40]; + uint first; + uint run_length; + uint i; + + buffer[0] = 0; + for(i=0;i<8;i++) + { + if(data&(1< 0) + sprintf(buffer+strlen(buffer), "-D%d", first + run_length); + } + } + for(i=0;i<8;i++) + { + if(data&(1<<(i+8))) + { + first = i; + run_length = 0; + while(i<7 && (data&(1<<(i+8+1)))) + { + i++; + run_length++; + } + if(buffer[0] != 0) + strcat(buffer, "/"); + sprintf(buffer+strlen(buffer), "A%d", first); + if(run_length > 0) + sprintf(buffer+strlen(buffer), "-A%d", first + run_length); + } + } + sprintf(g_dasm_str, "movem.l %s, %s", buffer, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_movep_re_16(void) +{ + sprintf(g_dasm_str, "movep.w D%d, ($%x,A%d)", (g_cpu_ir>>9)&7, read_imm_16(), g_cpu_ir&7); +} + +static void d68000_movep_re_32(void) +{ + sprintf(g_dasm_str, "movep.l D%d, ($%x,A%d)", (g_cpu_ir>>9)&7, read_imm_16(), g_cpu_ir&7); +} + +static void d68000_movep_er_16(void) +{ + sprintf(g_dasm_str, "movep.w ($%x,A%d), D%d", read_imm_16(), g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_movep_er_32(void) +{ + sprintf(g_dasm_str, "movep.l ($%x,A%d), D%d", read_imm_16(), g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68010_moves_8(void) +{ + uint extension; + LIMIT_CPU_TYPES(M68010_PLUS); + extension = read_imm_16(); + if(BIT_B(extension)) + sprintf(g_dasm_str, "moves.b %c%d, %s; (1+)", BIT_F(extension) ? 'A' : 'D', (extension>>12)&7, get_ea_mode_str_8(g_cpu_ir)); + else + sprintf(g_dasm_str, "moves.b %s, %c%d; (1+)", get_ea_mode_str_8(g_cpu_ir), BIT_F(extension) ? 'A' : 'D', (extension>>12)&7); +} + +static void d68010_moves_16(void) +{ + uint extension; + LIMIT_CPU_TYPES(M68010_PLUS); + extension = read_imm_16(); + if(BIT_B(extension)) + sprintf(g_dasm_str, "moves.w %c%d, %s; (1+)", BIT_F(extension) ? 'A' : 'D', (extension>>12)&7, get_ea_mode_str_16(g_cpu_ir)); + else + sprintf(g_dasm_str, "moves.w %s, %c%d; (1+)", get_ea_mode_str_16(g_cpu_ir), BIT_F(extension) ? 'A' : 'D', (extension>>12)&7); +} + +static void d68010_moves_32(void) +{ + uint extension; + LIMIT_CPU_TYPES(M68010_PLUS); + extension = read_imm_16(); + if(BIT_B(extension)) + sprintf(g_dasm_str, "moves.l %c%d, %s; (1+)", BIT_F(extension) ? 'A' : 'D', (extension>>12)&7, get_ea_mode_str_32(g_cpu_ir)); + else + sprintf(g_dasm_str, "moves.l %s, %c%d; (1+)", get_ea_mode_str_32(g_cpu_ir), BIT_F(extension) ? 'A' : 'D', (extension>>12)&7); +} + +static void d68000_moveq(void) +{ + sprintf(g_dasm_str, "moveq #%s, D%d", make_signed_hex_str_8(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68040_move16_pi_pi(void) +{ + LIMIT_CPU_TYPES(M68040_PLUS); + sprintf(g_dasm_str, "move16 (A%d)+, (A%d)+; (4)", g_cpu_ir&7, (read_imm_16()>>12)&7); +} + +static void d68040_move16_pi_al(void) +{ + LIMIT_CPU_TYPES(M68040_PLUS); + sprintf(g_dasm_str, "move16 (A%d)+, %s; (4)", g_cpu_ir&7, get_imm_str_u32()); +} + +static void d68040_move16_al_pi(void) +{ + LIMIT_CPU_TYPES(M68040_PLUS); + sprintf(g_dasm_str, "move16 %s, (A%d)+; (4)", get_imm_str_u32(), g_cpu_ir&7); +} + +static void d68040_move16_ai_al(void) +{ + LIMIT_CPU_TYPES(M68040_PLUS); + sprintf(g_dasm_str, "move16 (A%d), %s; (4)", g_cpu_ir&7, get_imm_str_u32()); +} + +static void d68040_move16_al_ai(void) +{ + LIMIT_CPU_TYPES(M68040_PLUS); + sprintf(g_dasm_str, "move16 %s, (A%d); (4)", get_imm_str_u32(), g_cpu_ir&7); +} + +static void d68000_muls(void) +{ + sprintf(g_dasm_str, "muls.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_mulu(void) +{ + sprintf(g_dasm_str, "mulu.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68020_mull(void) +{ + uint extension; + LIMIT_CPU_TYPES(M68020_PLUS); + extension = read_imm_16(); + + if(BIT_A(extension)) + sprintf(g_dasm_str, "mul%c.l %s, D%d-D%d; (2+)", BIT_B(extension) ? 's' : 'u', get_ea_mode_str_32(g_cpu_ir), extension&7, (extension>>12)&7); + else + sprintf(g_dasm_str, "mul%c.l %s, D%d; (2+)", BIT_B(extension) ? 's' : 'u', get_ea_mode_str_32(g_cpu_ir), (extension>>12)&7); +} + +static void d68000_nbcd(void) +{ + sprintf(g_dasm_str, "nbcd %s", get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_neg_8(void) +{ + sprintf(g_dasm_str, "neg.b %s", get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_neg_16(void) +{ + sprintf(g_dasm_str, "neg.w %s", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_neg_32(void) +{ + sprintf(g_dasm_str, "neg.l %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_negx_8(void) +{ + sprintf(g_dasm_str, "negx.b %s", get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_negx_16(void) +{ + sprintf(g_dasm_str, "negx.w %s", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_negx_32(void) +{ + sprintf(g_dasm_str, "negx.l %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_nop(void) +{ + sprintf(g_dasm_str, "nop"); +} + +static void d68000_not_8(void) +{ + sprintf(g_dasm_str, "not.b %s", get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_not_16(void) +{ + sprintf(g_dasm_str, "not.w %s", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_not_32(void) +{ + sprintf(g_dasm_str, "not.l %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_or_er_8(void) +{ + sprintf(g_dasm_str, "or.b %s, D%d", get_ea_mode_str_8(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_or_er_16(void) +{ + sprintf(g_dasm_str, "or.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_or_er_32(void) +{ + sprintf(g_dasm_str, "or.l %s, D%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_or_re_8(void) +{ + sprintf(g_dasm_str, "or.b D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_or_re_16(void) +{ + sprintf(g_dasm_str, "or.w D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_or_re_32(void) +{ + sprintf(g_dasm_str, "or.l D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_ori_8(void) +{ + char* str = get_imm_str_u8(); + sprintf(g_dasm_str, "ori.b %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_ori_16(void) +{ + char* str = get_imm_str_u16(); + sprintf(g_dasm_str, "ori.w %s, %s", str, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_ori_32(void) +{ + char* str = get_imm_str_u32(); + sprintf(g_dasm_str, "ori.l %s, %s", str, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_ori_to_ccr(void) +{ + sprintf(g_dasm_str, "ori %s, CCR", get_imm_str_u8()); +} + +static void d68000_ori_to_sr(void) +{ + sprintf(g_dasm_str, "ori %s, SR", get_imm_str_u16()); +} + +static void d68020_pack_rr(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "pack D%d, D%d, %s; (2+)", g_cpu_ir&7, (g_cpu_ir>>9)&7, get_imm_str_u16()); +} + +static void d68020_pack_mm(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "pack -(A%d), -(A%d), %s; (2+)", g_cpu_ir&7, (g_cpu_ir>>9)&7, get_imm_str_u16()); +} + +static void d68000_pea(void) +{ + sprintf(g_dasm_str, "pea %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68040_pflush(void) +{ + LIMIT_CPU_TYPES(M68040_PLUS); + + if (g_cpu_ir & 0x10) + { + sprintf(g_dasm_str, "pflusha%s", (g_cpu_ir & 8) ? "" : "n"); + } + else + { + sprintf(g_dasm_str, "pflush%s(A%d)", (g_cpu_ir & 8) ? "" : "n", g_cpu_ir & 7); + } +} + +static void d68000_reset(void) +{ + sprintf(g_dasm_str, "reset"); +} + +static void d68000_ror_s_8(void) +{ + sprintf(g_dasm_str, "ror.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_ror_s_16(void) +{ + sprintf(g_dasm_str, "ror.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7],g_cpu_ir&7); +} + +static void d68000_ror_s_32(void) +{ + sprintf(g_dasm_str, "ror.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_ror_r_8(void) +{ + sprintf(g_dasm_str, "ror.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_ror_r_16(void) +{ + sprintf(g_dasm_str, "ror.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_ror_r_32(void) +{ + sprintf(g_dasm_str, "ror.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_ror_ea(void) +{ + sprintf(g_dasm_str, "ror.w %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_rol_s_8(void) +{ + sprintf(g_dasm_str, "rol.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_rol_s_16(void) +{ + sprintf(g_dasm_str, "rol.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_rol_s_32(void) +{ + sprintf(g_dasm_str, "rol.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_rol_r_8(void) +{ + sprintf(g_dasm_str, "rol.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_rol_r_16(void) +{ + sprintf(g_dasm_str, "rol.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_rol_r_32(void) +{ + sprintf(g_dasm_str, "rol.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_rol_ea(void) +{ + sprintf(g_dasm_str, "rol.w %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_roxr_s_8(void) +{ + sprintf(g_dasm_str, "roxr.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_roxr_s_16(void) +{ + sprintf(g_dasm_str, "roxr.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + + +static void d68000_roxr_s_32(void) +{ + sprintf(g_dasm_str, "roxr.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_roxr_r_8(void) +{ + sprintf(g_dasm_str, "roxr.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_roxr_r_16(void) +{ + sprintf(g_dasm_str, "roxr.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_roxr_r_32(void) +{ + sprintf(g_dasm_str, "roxr.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_roxr_ea(void) +{ + sprintf(g_dasm_str, "roxr.w %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_roxl_s_8(void) +{ + sprintf(g_dasm_str, "roxl.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_roxl_s_16(void) +{ + sprintf(g_dasm_str, "roxl.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_roxl_s_32(void) +{ + sprintf(g_dasm_str, "roxl.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_roxl_r_8(void) +{ + sprintf(g_dasm_str, "roxl.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_roxl_r_16(void) +{ + sprintf(g_dasm_str, "roxl.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_roxl_r_32(void) +{ + sprintf(g_dasm_str, "roxl.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_roxl_ea(void) +{ + sprintf(g_dasm_str, "roxl.w %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68010_rtd(void) +{ + LIMIT_CPU_TYPES(M68010_PLUS); + sprintf(g_dasm_str, "rtd %s; (1+)", get_imm_str_s16()); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OUT); +} + +static void d68000_rte(void) +{ + sprintf(g_dasm_str, "rte"); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OUT); +} + +static void d68020_rtm(void) +{ + LIMIT_CPU_TYPES(M68020_ONLY); + sprintf(g_dasm_str, "rtm %c%d; (2+)", BIT_3(g_cpu_ir) ? 'A' : 'D', g_cpu_ir&7); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OUT); +} + +static void d68000_rtr(void) +{ + sprintf(g_dasm_str, "rtr"); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OUT); +} + +static void d68000_rts(void) +{ + sprintf(g_dasm_str, "rts"); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OUT); +} + +static void d68000_sbcd_rr(void) +{ + sprintf(g_dasm_str, "sbcd D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_sbcd_mm(void) +{ + sprintf(g_dasm_str, "sbcd -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_scc(void) +{ + sprintf(g_dasm_str, "s%-2s %s", g_cc[(g_cpu_ir>>8)&0xf], get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_stop(void) +{ + sprintf(g_dasm_str, "stop %s", get_imm_str_s16()); +} + +static void d68000_sub_er_8(void) +{ + sprintf(g_dasm_str, "sub.b %s, D%d", get_ea_mode_str_8(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_sub_er_16(void) +{ + sprintf(g_dasm_str, "sub.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_sub_er_32(void) +{ + sprintf(g_dasm_str, "sub.l %s, D%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_sub_re_8(void) +{ + sprintf(g_dasm_str, "sub.b D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_sub_re_16(void) +{ + sprintf(g_dasm_str, "sub.w D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_sub_re_32(void) +{ + sprintf(g_dasm_str, "sub.l D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_suba_16(void) +{ + sprintf(g_dasm_str, "suba.w %s, A%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_suba_32(void) +{ + sprintf(g_dasm_str, "suba.l %s, A%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_subi_8(void) +{ + char* str = get_imm_str_s8(); + sprintf(g_dasm_str, "subi.b %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_subi_16(void) +{ + char* str = get_imm_str_s16(); + sprintf(g_dasm_str, "subi.w %s, %s", str, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_subi_32(void) +{ + char* str = get_imm_str_s32(); + sprintf(g_dasm_str, "subi.l %s, %s", str, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_subq_8(void) +{ + sprintf(g_dasm_str, "subq.b #%d, %s", g_3bit_qdata_table[(g_cpu_ir>>9)&7], get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_subq_16(void) +{ + sprintf(g_dasm_str, "subq.w #%d, %s", g_3bit_qdata_table[(g_cpu_ir>>9)&7], get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_subq_32(void) +{ + sprintf(g_dasm_str, "subq.l #%d, %s", g_3bit_qdata_table[(g_cpu_ir>>9)&7], get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_subx_rr_8(void) +{ + sprintf(g_dasm_str, "subx.b D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_subx_rr_16(void) +{ + sprintf(g_dasm_str, "subx.w D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_subx_rr_32(void) +{ + sprintf(g_dasm_str, "subx.l D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_subx_mm_8(void) +{ + sprintf(g_dasm_str, "subx.b -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_subx_mm_16(void) +{ + sprintf(g_dasm_str, "subx.w -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_subx_mm_32(void) +{ + sprintf(g_dasm_str, "subx.l -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_swap(void) +{ + sprintf(g_dasm_str, "swap D%d", g_cpu_ir&7); +} + +static void d68000_tas(void) +{ + sprintf(g_dasm_str, "tas %s", get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_trap(void) +{ + sprintf(g_dasm_str, "trap #$%x", g_cpu_ir&0xf); +} + +static void d68020_trapcc_0(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "trap%-2s; (2+)", g_cc[(g_cpu_ir>>8)&0xf]); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER); +} + +static void d68020_trapcc_16(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "trap%-2s %s; (2+)", g_cc[(g_cpu_ir>>8)&0xf], get_imm_str_u16()); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER); +} + +static void d68020_trapcc_32(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "trap%-2s %s; (2+)", g_cc[(g_cpu_ir>>8)&0xf], get_imm_str_u32()); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER); +} + +static void d68000_trapv(void) +{ + sprintf(g_dasm_str, "trapv"); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER); +} + +static void d68000_tst_8(void) +{ + sprintf(g_dasm_str, "tst.b %s", get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68020_tst_pcdi_8(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "tst.b %s; (2+)", get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68020_tst_pcix_8(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "tst.b %s; (2+)", get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68020_tst_i_8(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "tst.b %s; (2+)", get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_tst_16(void) +{ + sprintf(g_dasm_str, "tst.w %s", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68020_tst_a_16(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "tst.w %s; (2+)", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68020_tst_pcdi_16(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "tst.w %s; (2+)", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68020_tst_pcix_16(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "tst.w %s; (2+)", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68020_tst_i_16(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "tst.w %s; (2+)", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_tst_32(void) +{ + sprintf(g_dasm_str, "tst.l %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68020_tst_a_32(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "tst.l %s; (2+)", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68020_tst_pcdi_32(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "tst.l %s; (2+)", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68020_tst_pcix_32(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "tst.l %s; (2+)", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68020_tst_i_32(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "tst.l %s; (2+)", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_unlk(void) +{ + sprintf(g_dasm_str, "unlk A%d", g_cpu_ir&7); +} + +static void d68020_unpk_rr(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "unpk D%d, D%d, %s; (2+)", g_cpu_ir&7, (g_cpu_ir>>9)&7, get_imm_str_u16()); +} + +static void d68020_unpk_mm(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "unpk -(A%d), -(A%d), %s; (2+)", g_cpu_ir&7, (g_cpu_ir>>9)&7, get_imm_str_u16()); +} + + + +/* ======================================================================== */ +/* ======================= INSTRUCTION TABLE BUILDER ====================== */ +/* ======================================================================== */ + +/* EA Masks: +800 = data register direct +400 = address register direct +200 = address register indirect +100 = ARI postincrement + 80 = ARI pre-decrement + 40 = ARI displacement + 20 = ARI index + 10 = absolute short + 8 = absolute long + 4 = immediate / sr + 2 = pc displacement + 1 = pc idx +*/ + +static opcode_struct g_opcode_info[] = +{ +/* opcode handler mask match ea mask */ + {d68000_1010 , 0xf000, 0xa000, 0x000}, + {d68000_1111 , 0xf000, 0xf000, 0x000}, + {d68000_abcd_rr , 0xf1f8, 0xc100, 0x000}, + {d68000_abcd_mm , 0xf1f8, 0xc108, 0x000}, + {d68000_add_er_8 , 0xf1c0, 0xd000, 0xbff}, + {d68000_add_er_16 , 0xf1c0, 0xd040, 0xfff}, + {d68000_add_er_32 , 0xf1c0, 0xd080, 0xfff}, + {d68000_add_re_8 , 0xf1c0, 0xd100, 0x3f8}, + {d68000_add_re_16 , 0xf1c0, 0xd140, 0x3f8}, + {d68000_add_re_32 , 0xf1c0, 0xd180, 0x3f8}, + {d68000_adda_16 , 0xf1c0, 0xd0c0, 0xfff}, + {d68000_adda_32 , 0xf1c0, 0xd1c0, 0xfff}, + {d68000_addi_8 , 0xffc0, 0x0600, 0xbf8}, + {d68000_addi_16 , 0xffc0, 0x0640, 0xbf8}, + {d68000_addi_32 , 0xffc0, 0x0680, 0xbf8}, + {d68000_addq_8 , 0xf1c0, 0x5000, 0xbf8}, + {d68000_addq_16 , 0xf1c0, 0x5040, 0xff8}, + {d68000_addq_32 , 0xf1c0, 0x5080, 0xff8}, + {d68000_addx_rr_8 , 0xf1f8, 0xd100, 0x000}, + {d68000_addx_rr_16 , 0xf1f8, 0xd140, 0x000}, + {d68000_addx_rr_32 , 0xf1f8, 0xd180, 0x000}, + {d68000_addx_mm_8 , 0xf1f8, 0xd108, 0x000}, + {d68000_addx_mm_16 , 0xf1f8, 0xd148, 0x000}, + {d68000_addx_mm_32 , 0xf1f8, 0xd188, 0x000}, + {d68000_and_er_8 , 0xf1c0, 0xc000, 0xbff}, + {d68000_and_er_16 , 0xf1c0, 0xc040, 0xbff}, + {d68000_and_er_32 , 0xf1c0, 0xc080, 0xbff}, + {d68000_and_re_8 , 0xf1c0, 0xc100, 0x3f8}, + {d68000_and_re_16 , 0xf1c0, 0xc140, 0x3f8}, + {d68000_and_re_32 , 0xf1c0, 0xc180, 0x3f8}, + {d68000_andi_to_ccr , 0xffff, 0x023c, 0x000}, + {d68000_andi_to_sr , 0xffff, 0x027c, 0x000}, + {d68000_andi_8 , 0xffc0, 0x0200, 0xbf8}, + {d68000_andi_16 , 0xffc0, 0x0240, 0xbf8}, + {d68000_andi_32 , 0xffc0, 0x0280, 0xbf8}, + {d68000_asr_s_8 , 0xf1f8, 0xe000, 0x000}, + {d68000_asr_s_16 , 0xf1f8, 0xe040, 0x000}, + {d68000_asr_s_32 , 0xf1f8, 0xe080, 0x000}, + {d68000_asr_r_8 , 0xf1f8, 0xe020, 0x000}, + {d68000_asr_r_16 , 0xf1f8, 0xe060, 0x000}, + {d68000_asr_r_32 , 0xf1f8, 0xe0a0, 0x000}, + {d68000_asr_ea , 0xffc0, 0xe0c0, 0x3f8}, + {d68000_asl_s_8 , 0xf1f8, 0xe100, 0x000}, + {d68000_asl_s_16 , 0xf1f8, 0xe140, 0x000}, + {d68000_asl_s_32 , 0xf1f8, 0xe180, 0x000}, + {d68000_asl_r_8 , 0xf1f8, 0xe120, 0x000}, + {d68000_asl_r_16 , 0xf1f8, 0xe160, 0x000}, + {d68000_asl_r_32 , 0xf1f8, 0xe1a0, 0x000}, + {d68000_asl_ea , 0xffc0, 0xe1c0, 0x3f8}, + {d68000_bcc_8 , 0xf000, 0x6000, 0x000}, + {d68000_bcc_16 , 0xf0ff, 0x6000, 0x000}, + {d68020_bcc_32 , 0xf0ff, 0x60ff, 0x000}, + {d68000_bchg_r , 0xf1c0, 0x0140, 0xbf8}, + {d68000_bchg_s , 0xffc0, 0x0840, 0xbf8}, + {d68000_bclr_r , 0xf1c0, 0x0180, 0xbf8}, + {d68000_bclr_s , 0xffc0, 0x0880, 0xbf8}, + {d68020_bfchg , 0xffc0, 0xeac0, 0xa78}, + {d68020_bfclr , 0xffc0, 0xecc0, 0xa78}, + {d68020_bfexts , 0xffc0, 0xebc0, 0xa7b}, + {d68020_bfextu , 0xffc0, 0xe9c0, 0xa7b}, + {d68020_bfffo , 0xffc0, 0xedc0, 0xa7b}, + {d68020_bfins , 0xffc0, 0xefc0, 0xa78}, + {d68020_bfset , 0xffc0, 0xeec0, 0xa78}, + {d68020_bftst , 0xffc0, 0xe8c0, 0xa7b}, + {d68010_bkpt , 0xfff8, 0x4848, 0x000}, + {d68000_bra_8 , 0xff00, 0x6000, 0x000}, + {d68000_bra_16 , 0xffff, 0x6000, 0x000}, + {d68020_bra_32 , 0xffff, 0x60ff, 0x000}, + {d68000_bset_r , 0xf1c0, 0x01c0, 0xbf8}, + {d68000_bset_s , 0xffc0, 0x08c0, 0xbf8}, + {d68000_bsr_8 , 0xff00, 0x6100, 0x000}, + {d68000_bsr_16 , 0xffff, 0x6100, 0x000}, + {d68020_bsr_32 , 0xffff, 0x61ff, 0x000}, + {d68000_btst_r , 0xf1c0, 0x0100, 0xbff}, + {d68000_btst_s , 0xffc0, 0x0800, 0xbfb}, + {d68020_callm , 0xffc0, 0x06c0, 0x27b}, + {d68020_cas_8 , 0xffc0, 0x0ac0, 0x3f8}, + {d68020_cas_16 , 0xffc0, 0x0cc0, 0x3f8}, + {d68020_cas_32 , 0xffc0, 0x0ec0, 0x3f8}, + {d68020_cas2_16 , 0xffff, 0x0cfc, 0x000}, + {d68020_cas2_32 , 0xffff, 0x0efc, 0x000}, + {d68000_chk_16 , 0xf1c0, 0x4180, 0xbff}, + {d68020_chk_32 , 0xf1c0, 0x4100, 0xbff}, + {d68020_chk2_cmp2_8 , 0xffc0, 0x00c0, 0x27b}, + {d68020_chk2_cmp2_16 , 0xffc0, 0x02c0, 0x27b}, + {d68020_chk2_cmp2_32 , 0xffc0, 0x04c0, 0x27b}, + {d68040_cinv , 0xff20, 0xf400, 0x000}, + {d68000_clr_8 , 0xffc0, 0x4200, 0xbf8}, + {d68000_clr_16 , 0xffc0, 0x4240, 0xbf8}, + {d68000_clr_32 , 0xffc0, 0x4280, 0xbf8}, + {d68000_cmp_8 , 0xf1c0, 0xb000, 0xbff}, + {d68000_cmp_16 , 0xf1c0, 0xb040, 0xfff}, + {d68000_cmp_32 , 0xf1c0, 0xb080, 0xfff}, + {d68000_cmpa_16 , 0xf1c0, 0xb0c0, 0xfff}, + {d68000_cmpa_32 , 0xf1c0, 0xb1c0, 0xfff}, + {d68000_cmpi_8 , 0xffc0, 0x0c00, 0xbf8}, + {d68020_cmpi_pcdi_8 , 0xffff, 0x0c3a, 0x000}, + {d68020_cmpi_pcix_8 , 0xffff, 0x0c3b, 0x000}, + {d68000_cmpi_16 , 0xffc0, 0x0c40, 0xbf8}, + {d68020_cmpi_pcdi_16 , 0xffff, 0x0c7a, 0x000}, + {d68020_cmpi_pcix_16 , 0xffff, 0x0c7b, 0x000}, + {d68000_cmpi_32 , 0xffc0, 0x0c80, 0xbf8}, + {d68020_cmpi_pcdi_32 , 0xffff, 0x0cba, 0x000}, + {d68020_cmpi_pcix_32 , 0xffff, 0x0cbb, 0x000}, + {d68000_cmpm_8 , 0xf1f8, 0xb108, 0x000}, + {d68000_cmpm_16 , 0xf1f8, 0xb148, 0x000}, + {d68000_cmpm_32 , 0xf1f8, 0xb188, 0x000}, + {d68020_cpbcc_16 , 0xf1c0, 0xf080, 0x000}, + {d68020_cpbcc_32 , 0xf1c0, 0xf0c0, 0x000}, + {d68020_cpdbcc , 0xf1f8, 0xf048, 0x000}, + {d68020_cpgen , 0xf1c0, 0xf000, 0x000}, + {d68020_cprestore , 0xf1c0, 0xf140, 0x37f}, + {d68020_cpsave , 0xf1c0, 0xf100, 0x2f8}, + {d68020_cpscc , 0xf1c0, 0xf040, 0xbf8}, + {d68020_cptrapcc_0 , 0xf1ff, 0xf07c, 0x000}, + {d68020_cptrapcc_16 , 0xf1ff, 0xf07a, 0x000}, + {d68020_cptrapcc_32 , 0xf1ff, 0xf07b, 0x000}, + {d68040_cpush , 0xff20, 0xf420, 0x000}, + {d68000_dbcc , 0xf0f8, 0x50c8, 0x000}, + {d68000_dbra , 0xfff8, 0x51c8, 0x000}, + {d68000_divs , 0xf1c0, 0x81c0, 0xbff}, + {d68000_divu , 0xf1c0, 0x80c0, 0xbff}, + {d68020_divl , 0xffc0, 0x4c40, 0xbff}, + {d68000_eor_8 , 0xf1c0, 0xb100, 0xbf8}, + {d68000_eor_16 , 0xf1c0, 0xb140, 0xbf8}, + {d68000_eor_32 , 0xf1c0, 0xb180, 0xbf8}, + {d68000_eori_to_ccr , 0xffff, 0x0a3c, 0x000}, + {d68000_eori_to_sr , 0xffff, 0x0a7c, 0x000}, + {d68000_eori_8 , 0xffc0, 0x0a00, 0xbf8}, + {d68000_eori_16 , 0xffc0, 0x0a40, 0xbf8}, + {d68000_eori_32 , 0xffc0, 0x0a80, 0xbf8}, + {d68000_exg_dd , 0xf1f8, 0xc140, 0x000}, + {d68000_exg_aa , 0xf1f8, 0xc148, 0x000}, + {d68000_exg_da , 0xf1f8, 0xc188, 0x000}, + {d68020_extb_32 , 0xfff8, 0x49c0, 0x000}, + {d68000_ext_16 , 0xfff8, 0x4880, 0x000}, + {d68000_ext_32 , 0xfff8, 0x48c0, 0x000}, + {d68000_illegal , 0xffff, 0x4afc, 0x000}, + {d68000_jmp , 0xffc0, 0x4ec0, 0x27b}, + {d68000_jsr , 0xffc0, 0x4e80, 0x27b}, + {d68000_lea , 0xf1c0, 0x41c0, 0x27b}, + {d68000_link_16 , 0xfff8, 0x4e50, 0x000}, + {d68020_link_32 , 0xfff8, 0x4808, 0x000}, + {d68000_lsr_s_8 , 0xf1f8, 0xe008, 0x000}, + {d68000_lsr_s_16 , 0xf1f8, 0xe048, 0x000}, + {d68000_lsr_s_32 , 0xf1f8, 0xe088, 0x000}, + {d68000_lsr_r_8 , 0xf1f8, 0xe028, 0x000}, + {d68000_lsr_r_16 , 0xf1f8, 0xe068, 0x000}, + {d68000_lsr_r_32 , 0xf1f8, 0xe0a8, 0x000}, + {d68000_lsr_ea , 0xffc0, 0xe2c0, 0x3f8}, + {d68000_lsl_s_8 , 0xf1f8, 0xe108, 0x000}, + {d68000_lsl_s_16 , 0xf1f8, 0xe148, 0x000}, + {d68000_lsl_s_32 , 0xf1f8, 0xe188, 0x000}, + {d68000_lsl_r_8 , 0xf1f8, 0xe128, 0x000}, + {d68000_lsl_r_16 , 0xf1f8, 0xe168, 0x000}, + {d68000_lsl_r_32 , 0xf1f8, 0xe1a8, 0x000}, + {d68000_lsl_ea , 0xffc0, 0xe3c0, 0x3f8}, + {d68000_move_8 , 0xf000, 0x1000, 0xbff}, + {d68000_move_16 , 0xf000, 0x3000, 0xfff}, + {d68000_move_32 , 0xf000, 0x2000, 0xfff}, + {d68000_movea_16 , 0xf1c0, 0x3040, 0xfff}, + {d68000_movea_32 , 0xf1c0, 0x2040, 0xfff}, + {d68000_move_to_ccr , 0xffc0, 0x44c0, 0xbff}, + {d68010_move_fr_ccr , 0xffc0, 0x42c0, 0xbf8}, + {d68000_move_to_sr , 0xffc0, 0x46c0, 0xbff}, + {d68000_move_fr_sr , 0xffc0, 0x40c0, 0xbf8}, + {d68000_move_to_usp , 0xfff8, 0x4e60, 0x000}, + {d68000_move_fr_usp , 0xfff8, 0x4e68, 0x000}, + {d68010_movec , 0xfffe, 0x4e7a, 0x000}, + {d68000_movem_pd_16 , 0xfff8, 0x48a0, 0x000}, + {d68000_movem_pd_32 , 0xfff8, 0x48e0, 0x000}, + {d68000_movem_re_16 , 0xffc0, 0x4880, 0x2f8}, + {d68000_movem_re_32 , 0xffc0, 0x48c0, 0x2f8}, + {d68000_movem_er_16 , 0xffc0, 0x4c80, 0x37b}, + {d68000_movem_er_32 , 0xffc0, 0x4cc0, 0x37b}, + {d68000_movep_er_16 , 0xf1f8, 0x0108, 0x000}, + {d68000_movep_er_32 , 0xf1f8, 0x0148, 0x000}, + {d68000_movep_re_16 , 0xf1f8, 0x0188, 0x000}, + {d68000_movep_re_32 , 0xf1f8, 0x01c8, 0x000}, + {d68010_moves_8 , 0xffc0, 0x0e00, 0x3f8}, + {d68010_moves_16 , 0xffc0, 0x0e40, 0x3f8}, + {d68010_moves_32 , 0xffc0, 0x0e80, 0x3f8}, + {d68000_moveq , 0xf100, 0x7000, 0x000}, + {d68040_move16_pi_pi , 0xfff8, 0xf620, 0x000}, + {d68040_move16_pi_al , 0xfff8, 0xf600, 0x000}, + {d68040_move16_al_pi , 0xfff8, 0xf608, 0x000}, + {d68040_move16_ai_al , 0xfff8, 0xf610, 0x000}, + {d68040_move16_al_ai , 0xfff8, 0xf618, 0x000}, + {d68000_muls , 0xf1c0, 0xc1c0, 0xbff}, + {d68000_mulu , 0xf1c0, 0xc0c0, 0xbff}, + {d68020_mull , 0xffc0, 0x4c00, 0xbff}, + {d68000_nbcd , 0xffc0, 0x4800, 0xbf8}, + {d68000_neg_8 , 0xffc0, 0x4400, 0xbf8}, + {d68000_neg_16 , 0xffc0, 0x4440, 0xbf8}, + {d68000_neg_32 , 0xffc0, 0x4480, 0xbf8}, + {d68000_negx_8 , 0xffc0, 0x4000, 0xbf8}, + {d68000_negx_16 , 0xffc0, 0x4040, 0xbf8}, + {d68000_negx_32 , 0xffc0, 0x4080, 0xbf8}, + {d68000_nop , 0xffff, 0x4e71, 0x000}, + {d68000_not_8 , 0xffc0, 0x4600, 0xbf8}, + {d68000_not_16 , 0xffc0, 0x4640, 0xbf8}, + {d68000_not_32 , 0xffc0, 0x4680, 0xbf8}, + {d68000_or_er_8 , 0xf1c0, 0x8000, 0xbff}, + {d68000_or_er_16 , 0xf1c0, 0x8040, 0xbff}, + {d68000_or_er_32 , 0xf1c0, 0x8080, 0xbff}, + {d68000_or_re_8 , 0xf1c0, 0x8100, 0x3f8}, + {d68000_or_re_16 , 0xf1c0, 0x8140, 0x3f8}, + {d68000_or_re_32 , 0xf1c0, 0x8180, 0x3f8}, + {d68000_ori_to_ccr , 0xffff, 0x003c, 0x000}, + {d68000_ori_to_sr , 0xffff, 0x007c, 0x000}, + {d68000_ori_8 , 0xffc0, 0x0000, 0xbf8}, + {d68000_ori_16 , 0xffc0, 0x0040, 0xbf8}, + {d68000_ori_32 , 0xffc0, 0x0080, 0xbf8}, + {d68020_pack_rr , 0xf1f8, 0x8140, 0x000}, + {d68020_pack_mm , 0xf1f8, 0x8148, 0x000}, + {d68000_pea , 0xffc0, 0x4840, 0x27b}, + {d68040_pflush , 0xffe0, 0xf500, 0x000}, + {d68000_reset , 0xffff, 0x4e70, 0x000}, + {d68000_ror_s_8 , 0xf1f8, 0xe018, 0x000}, + {d68000_ror_s_16 , 0xf1f8, 0xe058, 0x000}, + {d68000_ror_s_32 , 0xf1f8, 0xe098, 0x000}, + {d68000_ror_r_8 , 0xf1f8, 0xe038, 0x000}, + {d68000_ror_r_16 , 0xf1f8, 0xe078, 0x000}, + {d68000_ror_r_32 , 0xf1f8, 0xe0b8, 0x000}, + {d68000_ror_ea , 0xffc0, 0xe6c0, 0x3f8}, + {d68000_rol_s_8 , 0xf1f8, 0xe118, 0x000}, + {d68000_rol_s_16 , 0xf1f8, 0xe158, 0x000}, + {d68000_rol_s_32 , 0xf1f8, 0xe198, 0x000}, + {d68000_rol_r_8 , 0xf1f8, 0xe138, 0x000}, + {d68000_rol_r_16 , 0xf1f8, 0xe178, 0x000}, + {d68000_rol_r_32 , 0xf1f8, 0xe1b8, 0x000}, + {d68000_rol_ea , 0xffc0, 0xe7c0, 0x3f8}, + {d68000_roxr_s_8 , 0xf1f8, 0xe010, 0x000}, + {d68000_roxr_s_16 , 0xf1f8, 0xe050, 0x000}, + {d68000_roxr_s_32 , 0xf1f8, 0xe090, 0x000}, + {d68000_roxr_r_8 , 0xf1f8, 0xe030, 0x000}, + {d68000_roxr_r_16 , 0xf1f8, 0xe070, 0x000}, + {d68000_roxr_r_32 , 0xf1f8, 0xe0b0, 0x000}, + {d68000_roxr_ea , 0xffc0, 0xe4c0, 0x3f8}, + {d68000_roxl_s_8 , 0xf1f8, 0xe110, 0x000}, + {d68000_roxl_s_16 , 0xf1f8, 0xe150, 0x000}, + {d68000_roxl_s_32 , 0xf1f8, 0xe190, 0x000}, + {d68000_roxl_r_8 , 0xf1f8, 0xe130, 0x000}, + {d68000_roxl_r_16 , 0xf1f8, 0xe170, 0x000}, + {d68000_roxl_r_32 , 0xf1f8, 0xe1b0, 0x000}, + {d68000_roxl_ea , 0xffc0, 0xe5c0, 0x3f8}, + {d68010_rtd , 0xffff, 0x4e74, 0x000}, + {d68000_rte , 0xffff, 0x4e73, 0x000}, + {d68020_rtm , 0xfff0, 0x06c0, 0x000}, + {d68000_rtr , 0xffff, 0x4e77, 0x000}, + {d68000_rts , 0xffff, 0x4e75, 0x000}, + {d68000_sbcd_rr , 0xf1f8, 0x8100, 0x000}, + {d68000_sbcd_mm , 0xf1f8, 0x8108, 0x000}, + {d68000_scc , 0xf0c0, 0x50c0, 0xbf8}, + {d68000_stop , 0xffff, 0x4e72, 0x000}, + {d68000_sub_er_8 , 0xf1c0, 0x9000, 0xbff}, + {d68000_sub_er_16 , 0xf1c0, 0x9040, 0xfff}, + {d68000_sub_er_32 , 0xf1c0, 0x9080, 0xfff}, + {d68000_sub_re_8 , 0xf1c0, 0x9100, 0x3f8}, + {d68000_sub_re_16 , 0xf1c0, 0x9140, 0x3f8}, + {d68000_sub_re_32 , 0xf1c0, 0x9180, 0x3f8}, + {d68000_suba_16 , 0xf1c0, 0x90c0, 0xfff}, + {d68000_suba_32 , 0xf1c0, 0x91c0, 0xfff}, + {d68000_subi_8 , 0xffc0, 0x0400, 0xbf8}, + {d68000_subi_16 , 0xffc0, 0x0440, 0xbf8}, + {d68000_subi_32 , 0xffc0, 0x0480, 0xbf8}, + {d68000_subq_8 , 0xf1c0, 0x5100, 0xbf8}, + {d68000_subq_16 , 0xf1c0, 0x5140, 0xff8}, + {d68000_subq_32 , 0xf1c0, 0x5180, 0xff8}, + {d68000_subx_rr_8 , 0xf1f8, 0x9100, 0x000}, + {d68000_subx_rr_16 , 0xf1f8, 0x9140, 0x000}, + {d68000_subx_rr_32 , 0xf1f8, 0x9180, 0x000}, + {d68000_subx_mm_8 , 0xf1f8, 0x9108, 0x000}, + {d68000_subx_mm_16 , 0xf1f8, 0x9148, 0x000}, + {d68000_subx_mm_32 , 0xf1f8, 0x9188, 0x000}, + {d68000_swap , 0xfff8, 0x4840, 0x000}, + {d68000_tas , 0xffc0, 0x4ac0, 0xbf8}, + {d68000_trap , 0xfff0, 0x4e40, 0x000}, + {d68020_trapcc_0 , 0xf0ff, 0x50fc, 0x000}, + {d68020_trapcc_16 , 0xf0ff, 0x50fa, 0x000}, + {d68020_trapcc_32 , 0xf0ff, 0x50fb, 0x000}, + {d68000_trapv , 0xffff, 0x4e76, 0x000}, + {d68000_tst_8 , 0xffc0, 0x4a00, 0xbf8}, + {d68020_tst_pcdi_8 , 0xffff, 0x4a3a, 0x000}, + {d68020_tst_pcix_8 , 0xffff, 0x4a3b, 0x000}, + {d68020_tst_i_8 , 0xffff, 0x4a3c, 0x000}, + {d68000_tst_16 , 0xffc0, 0x4a40, 0xbf8}, + {d68020_tst_a_16 , 0xfff8, 0x4a48, 0x000}, + {d68020_tst_pcdi_16 , 0xffff, 0x4a7a, 0x000}, + {d68020_tst_pcix_16 , 0xffff, 0x4a7b, 0x000}, + {d68020_tst_i_16 , 0xffff, 0x4a7c, 0x000}, + {d68000_tst_32 , 0xffc0, 0x4a80, 0xbf8}, + {d68020_tst_a_32 , 0xfff8, 0x4a88, 0x000}, + {d68020_tst_pcdi_32 , 0xffff, 0x4aba, 0x000}, + {d68020_tst_pcix_32 , 0xffff, 0x4abb, 0x000}, + {d68020_tst_i_32 , 0xffff, 0x4abc, 0x000}, + {d68000_unlk , 0xfff8, 0x4e58, 0x000}, + {d68020_unpk_rr , 0xf1f8, 0x8180, 0x000}, + {d68020_unpk_mm , 0xf1f8, 0x8188, 0x000}, + {0, 0, 0, 0} +}; + +/* Check if opcode is using a valid ea mode */ +static int valid_ea(uint opcode, uint mask) +{ + if(mask == 0) + return 1; + + switch(opcode & 0x3f) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + return (mask & 0x800) != 0; + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + return (mask & 0x400) != 0; + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + return (mask & 0x200) != 0; + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + return (mask & 0x100) != 0; + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + return (mask & 0x080) != 0; + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + return (mask & 0x040) != 0; + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x34: case 0x35: case 0x36: case 0x37: + return (mask & 0x020) != 0; + case 0x38: + return (mask & 0x010) != 0; + case 0x39: + return (mask & 0x008) != 0; + case 0x3a: + return (mask & 0x002) != 0; + case 0x3b: + return (mask & 0x001) != 0; + case 0x3c: + return (mask & 0x004) != 0; + } + return 0; + +} + +/* Used by qsort */ +static int DECL_SPEC compare_nof_true_bits(const void *aptr, const void *bptr) +{ + uint a = ((const opcode_struct*)aptr)->mask; + uint b = ((const opcode_struct*)bptr)->mask; + + a = ((a & 0xAAAA) >> 1) + (a & 0x5555); + a = ((a & 0xCCCC) >> 2) + (a & 0x3333); + a = ((a & 0xF0F0) >> 4) + (a & 0x0F0F); + a = ((a & 0xFF00) >> 8) + (a & 0x00FF); + + b = ((b & 0xAAAA) >> 1) + (b & 0x5555); + b = ((b & 0xCCCC) >> 2) + (b & 0x3333); + b = ((b & 0xF0F0) >> 4) + (b & 0x0F0F); + b = ((b & 0xFF00) >> 8) + (b & 0x00FF); + + return b - a; /* reversed to get greatest to least sorting */ +} + +/* build the opcode handler jump table */ +static void build_opcode_table(void) +{ + uint i; + uint opcode; + opcode_struct* ostruct; + uint opcode_info_length = 0; + + for(ostruct = g_opcode_info;ostruct->opcode_handler != 0;ostruct++) + opcode_info_length++; + + qsort((void *)g_opcode_info, opcode_info_length, sizeof(g_opcode_info[0]), compare_nof_true_bits); + + for(i=0;i<0x10000;i++) + { + g_instruction_table[i] = d68000_illegal; /* default to illegal */ + opcode = i; + /* search through opcode info for a match */ + for(ostruct = g_opcode_info;ostruct->opcode_handler != 0;ostruct++) + { + /* match opcode mask and allowed ea modes */ + if((opcode & ostruct->mask) == ostruct->match) + { + /* Handle destination ea for move instructions */ + if((ostruct->opcode_handler == d68000_move_8 || + ostruct->opcode_handler == d68000_move_16 || + ostruct->opcode_handler == d68000_move_32) && + !valid_ea(((opcode>>9)&7) | ((opcode>>3)&0x38), 0xbf8)) + continue; + if(valid_ea(opcode, ostruct->ea_mask)) + { + g_instruction_table[i] = ostruct->opcode_handler; + break; + } + } + } + } +} + + + +/* ======================================================================== */ +/* ================================= API ================================== */ +/* ======================================================================== */ + +/* Disasemble one instruction at pc and store in str_buff */ +unsigned int m68k_disassemble(char* str_buff, unsigned int pc, unsigned int cpu_type) +{ + if(!g_initialized) + { + build_opcode_table(); + g_initialized = 1; + } + switch(cpu_type) + { + case M68K_CPU_TYPE_68000: + g_cpu_type = TYPE_68000; + g_address_mask = 0x00ffffff; + break; + case M68K_CPU_TYPE_68008: + g_cpu_type = TYPE_68008; + g_address_mask = 0x003fffff; + break; + case M68K_CPU_TYPE_68010: + g_cpu_type = TYPE_68010; + g_address_mask = 0x00ffffff; + break; + case M68K_CPU_TYPE_68EC020: + g_cpu_type = TYPE_68020; + g_address_mask = 0x00ffffff; + break; + case M68K_CPU_TYPE_68020: + g_cpu_type = TYPE_68020; + g_address_mask = 0xffffffff; + break; + case M68K_CPU_TYPE_68030: + g_cpu_type = TYPE_68030; + g_address_mask = 0xffffffff; + break; + case M68K_CPU_TYPE_68040: + g_cpu_type = TYPE_68040; + g_address_mask = 0xffffffff; + break; + default: + return 0; + } + + g_cpu_pc = pc; + g_helper_str[0] = 0; + g_cpu_ir = read_imm_16(); + g_opcode_type = 0; + g_instruction_table[g_cpu_ir](); + sprintf(str_buff, "%s%s", g_dasm_str, g_helper_str); + return COMBINE_OPCODE_FLAGS(g_cpu_pc - pc); +} + +char* m68ki_disassemble_quick(unsigned int pc, unsigned int cpu_type) +{ + static char buff[100]; + buff[0] = 0; + m68k_disassemble(buff, pc, cpu_type); + return buff; +} + +unsigned int m68k_disassemble_raw(char* str_buff, unsigned int pc, unsigned char* opdata, unsigned char* argdata, int length, unsigned int cpu_type) +{ + unsigned int result; + + g_rawop = opdata; + g_rawbasepc = pc; + g_rawlength = length; + result = m68k_disassemble(str_buff, pc, cpu_type); + g_rawop = NULL; + return result; +} + +/* Check if the instruction is a valid one */ +unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cpu_type) +{ + if(!g_initialized) + { + build_opcode_table(); + g_initialized = 1; + } + + instruction &= 0xffff; + if(g_instruction_table[instruction] == d68000_illegal) + return 0; + + switch(cpu_type) + { + case M68K_CPU_TYPE_68000: + case M68K_CPU_TYPE_68008: + if(g_instruction_table[instruction] == d68010_bkpt) + return 0; + if(g_instruction_table[instruction] == d68010_move_fr_ccr) + return 0; + if(g_instruction_table[instruction] == d68010_movec) + return 0; + if(g_instruction_table[instruction] == d68010_moves_8) + return 0; + if(g_instruction_table[instruction] == d68010_moves_16) + return 0; + if(g_instruction_table[instruction] == d68010_moves_32) + return 0; + if(g_instruction_table[instruction] == d68010_rtd) + return 0; + case M68K_CPU_TYPE_68010: + if(g_instruction_table[instruction] == d68020_bcc_32) + return 0; + if(g_instruction_table[instruction] == d68020_bfchg) + return 0; + if(g_instruction_table[instruction] == d68020_bfclr) + return 0; + if(g_instruction_table[instruction] == d68020_bfexts) + return 0; + if(g_instruction_table[instruction] == d68020_bfextu) + return 0; + if(g_instruction_table[instruction] == d68020_bfffo) + return 0; + if(g_instruction_table[instruction] == d68020_bfins) + return 0; + if(g_instruction_table[instruction] == d68020_bfset) + return 0; + if(g_instruction_table[instruction] == d68020_bftst) + return 0; + if(g_instruction_table[instruction] == d68020_bra_32) + return 0; + if(g_instruction_table[instruction] == d68020_bsr_32) + return 0; + if(g_instruction_table[instruction] == d68020_callm) + return 0; + if(g_instruction_table[instruction] == d68020_cas_8) + return 0; + if(g_instruction_table[instruction] == d68020_cas_16) + return 0; + if(g_instruction_table[instruction] == d68020_cas_32) + return 0; + if(g_instruction_table[instruction] == d68020_cas2_16) + return 0; + if(g_instruction_table[instruction] == d68020_cas2_32) + return 0; + if(g_instruction_table[instruction] == d68020_chk_32) + return 0; + if(g_instruction_table[instruction] == d68020_chk2_cmp2_8) + return 0; + if(g_instruction_table[instruction] == d68020_chk2_cmp2_16) + return 0; + if(g_instruction_table[instruction] == d68020_chk2_cmp2_32) + return 0; + if(g_instruction_table[instruction] == d68020_cmpi_pcdi_8) + return 0; + if(g_instruction_table[instruction] == d68020_cmpi_pcix_8) + return 0; + if(g_instruction_table[instruction] == d68020_cmpi_pcdi_16) + return 0; + if(g_instruction_table[instruction] == d68020_cmpi_pcix_16) + return 0; + if(g_instruction_table[instruction] == d68020_cmpi_pcdi_32) + return 0; + if(g_instruction_table[instruction] == d68020_cmpi_pcix_32) + return 0; + if(g_instruction_table[instruction] == d68020_cpbcc_16) + return 0; + if(g_instruction_table[instruction] == d68020_cpbcc_32) + return 0; + if(g_instruction_table[instruction] == d68020_cpdbcc) + return 0; + if(g_instruction_table[instruction] == d68020_cpgen) + return 0; + if(g_instruction_table[instruction] == d68020_cprestore) + return 0; + if(g_instruction_table[instruction] == d68020_cpsave) + return 0; + if(g_instruction_table[instruction] == d68020_cpscc) + return 0; + if(g_instruction_table[instruction] == d68020_cptrapcc_0) + return 0; + if(g_instruction_table[instruction] == d68020_cptrapcc_16) + return 0; + if(g_instruction_table[instruction] == d68020_cptrapcc_32) + return 0; + if(g_instruction_table[instruction] == d68020_divl) + return 0; + if(g_instruction_table[instruction] == d68020_extb_32) + return 0; + if(g_instruction_table[instruction] == d68020_link_32) + return 0; + if(g_instruction_table[instruction] == d68020_mull) + return 0; + if(g_instruction_table[instruction] == d68020_pack_rr) + return 0; + if(g_instruction_table[instruction] == d68020_pack_mm) + return 0; + if(g_instruction_table[instruction] == d68020_rtm) + return 0; + if(g_instruction_table[instruction] == d68020_trapcc_0) + return 0; + if(g_instruction_table[instruction] == d68020_trapcc_16) + return 0; + if(g_instruction_table[instruction] == d68020_trapcc_32) + return 0; + if(g_instruction_table[instruction] == d68020_tst_pcdi_8) + return 0; + if(g_instruction_table[instruction] == d68020_tst_pcix_8) + return 0; + if(g_instruction_table[instruction] == d68020_tst_i_8) + return 0; + if(g_instruction_table[instruction] == d68020_tst_a_16) + return 0; + if(g_instruction_table[instruction] == d68020_tst_pcdi_16) + return 0; + if(g_instruction_table[instruction] == d68020_tst_pcix_16) + return 0; + if(g_instruction_table[instruction] == d68020_tst_i_16) + return 0; + if(g_instruction_table[instruction] == d68020_tst_a_32) + return 0; + if(g_instruction_table[instruction] == d68020_tst_pcdi_32) + return 0; + if(g_instruction_table[instruction] == d68020_tst_pcix_32) + return 0; + if(g_instruction_table[instruction] == d68020_tst_i_32) + return 0; + if(g_instruction_table[instruction] == d68020_unpk_rr) + return 0; + if(g_instruction_table[instruction] == d68020_unpk_mm) + return 0; + case M68K_CPU_TYPE_68EC020: + case M68K_CPU_TYPE_68020: + case M68K_CPU_TYPE_68030: + if(g_instruction_table[instruction] == d68040_cinv) + return 0; + if(g_instruction_table[instruction] == d68040_cpush) + return 0; + if(g_instruction_table[instruction] == d68040_move16_pi_pi) + return 0; + if(g_instruction_table[instruction] == d68040_move16_pi_al) + return 0; + if(g_instruction_table[instruction] == d68040_move16_al_pi) + return 0; + if(g_instruction_table[instruction] == d68040_move16_ai_al) + return 0; + if(g_instruction_table[instruction] == d68040_move16_al_ai) + return 0; + if(g_instruction_table[instruction] == d68040_pflush) + return 0; + } + if(cpu_type != M68K_CPU_TYPE_68020 && cpu_type != M68K_CPU_TYPE_68EC020 && + (g_instruction_table[instruction] == d68020_callm || + g_instruction_table[instruction] == d68020_rtm)) + return 0; + + return 1; +} + + + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ diff --git a/cpu/musashi/m68kmake.c b/cpu/musashi/m68kmake.c new file mode 100644 index 00000000..d7cbc373 --- /dev/null +++ b/cpu/musashi/m68kmake.c @@ -0,0 +1,1484 @@ +/* ======================================================================== */ +/* ========================= LICENSING & COPYRIGHT ======================== */ +/* ======================================================================== */ +/* + * MUSASHI + * Version 3.3 + * + * A portable Motorola M680x0 processor emulation engine. + * Copyright 1998-2001 Karl Stenerud. All rights reserved. + * + * This code may be freely used for non-commercial purposes as long as this + * copyright notice remains unaltered in the source code and any binary files + * containing this code in compiled form. + * + * All other lisencing terms must be negotiated with the author + * (Karl Stenerud). + * + * The latest version of this code can be obtained at: + * http://kstenerud.cjb.net + */ + +/* + * Modified For OpenVMS By: Robert Alan Byer + * byer@mail.ourservers.net + */ + + +/* ======================================================================== */ +/* ============================ CODE GENERATOR ============================ */ +/* ======================================================================== */ +/* + * This is the code generator program which will generate the opcode table + * and the final opcode handlers. + * + * It requires an input file to function (default m68k_in.c), but you can + * specify your own like so: + * + * m68kmake + * + * where output path is the path where the output files should be placed, and + * input file is the file to use for input. + * + * If you modify the input file greatly from its released form, you may have + * to tweak the configuration section a bit since I'm using static allocation + * to keep things simple. + * + * + * TODO: - build a better code generator for the move instruction. + * - Add callm and rtm instructions + * - Fix RTE to handle other format words + * - Add address error (and bus error?) handling + */ + + +const char* g_version = "3.3"; + +/* ======================================================================== */ +/* =============================== INCLUDES =============================== */ +/* ======================================================================== */ + +#include +#include +#include +#include +#include + + + +/* ======================================================================== */ +/* ============================= CONFIGURATION ============================ */ +/* ======================================================================== */ + +#define M68K_MAX_PATH 1024 +#define M68K_MAX_DIR 1024 + +#define MAX_LINE_LENGTH 200 /* length of 1 line */ +#define MAX_BODY_LENGTH 300 /* Number of lines in 1 function */ +#define MAX_REPLACE_LENGTH 30 /* Max number of replace strings */ +#define MAX_INSERT_LENGTH 5000 /* Max size of insert piece */ +#define MAX_NAME_LENGTH 30 /* Max length of ophandler name */ +#define MAX_SPEC_PROC_LENGTH 4 /* Max length of special processing str */ +#define MAX_SPEC_EA_LENGTH 5 /* Max length of specified EA str */ +#define EA_ALLOWED_LENGTH 11 /* Max length of ea allowed str */ +#define MAX_OPCODE_INPUT_TABLE_LENGTH 1000 /* Max length of opcode handler tbl */ +#define MAX_OPCODE_OUTPUT_TABLE_LENGTH 3000 /* Max length of opcode handler tbl */ + +/* Default filenames */ +#define FILENAME_INPUT "m68k_in.c" +#define FILENAME_PROTOTYPE "m68kops.h" +#define FILENAME_TABLE "m68kops.c" +#define FILENAME_OPS_AC "m68kopac.c" +#define FILENAME_OPS_DM "m68kopdm.c" +#define FILENAME_OPS_NZ "m68kopnz.c" + + +/* Identifier sequences recognized by this program */ + +#define ID_INPUT_SEPARATOR "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + +#define ID_BASE "M68KMAKE" +#define ID_PROTOTYPE_HEADER ID_BASE "_PROTOTYPE_HEADER" +#define ID_PROTOTYPE_FOOTER ID_BASE "_PROTOTYPE_FOOTER" +#define ID_TABLE_HEADER ID_BASE "_TABLE_HEADER" +#define ID_TABLE_FOOTER ID_BASE "_TABLE_FOOTER" +#define ID_TABLE_BODY ID_BASE "_TABLE_BODY" +#define ID_TABLE_START ID_BASE "_TABLE_START" +#define ID_OPHANDLER_HEADER ID_BASE "_OPCODE_HANDLER_HEADER" +#define ID_OPHANDLER_FOOTER ID_BASE "_OPCODE_HANDLER_FOOTER" +#define ID_OPHANDLER_BODY ID_BASE "_OPCODE_HANDLER_BODY" +#define ID_END ID_BASE "_END" + +#define ID_OPHANDLER_NAME ID_BASE "_OP" +#define ID_OPHANDLER_EA_AY_8 ID_BASE "_GET_EA_AY_8" +#define ID_OPHANDLER_EA_AY_16 ID_BASE "_GET_EA_AY_16" +#define ID_OPHANDLER_EA_AY_32 ID_BASE "_GET_EA_AY_32" +#define ID_OPHANDLER_OPER_AY_8 ID_BASE "_GET_OPER_AY_8" +#define ID_OPHANDLER_OPER_AY_16 ID_BASE "_GET_OPER_AY_16" +#define ID_OPHANDLER_OPER_AY_32 ID_BASE "_GET_OPER_AY_32" +#define ID_OPHANDLER_CC ID_BASE "_CC" +#define ID_OPHANDLER_NOT_CC ID_BASE "_NOT_CC" + + +#ifndef DECL_SPEC +#define DECL_SPEC +#endif /* DECL_SPEC */ + + + +/* ======================================================================== */ +/* ============================== PROTOTYPES ============================== */ +/* ======================================================================== */ + +enum { + CPU_TYPE_000 = 0, + CPU_TYPE_010, + CPU_TYPE_020, + CPU_TYPE_040, + NUM_CPUS +}; + +#define UNSPECIFIED "." +#define UNSPECIFIED_CH '.' + +#define HAS_NO_EA_MODE(A) (strcmp(A, "..........") == 0) +#define HAS_EA_AI(A) ((A)[0] == 'A') +#define HAS_EA_PI(A) ((A)[1] == '+') +#define HAS_EA_PD(A) ((A)[2] == '-') +#define HAS_EA_DI(A) ((A)[3] == 'D') +#define HAS_EA_IX(A) ((A)[4] == 'X') +#define HAS_EA_AW(A) ((A)[5] == 'W') +#define HAS_EA_AL(A) ((A)[6] == 'L') +#define HAS_EA_PCDI(A) ((A)[7] == 'd') +#define HAS_EA_PCIX(A) ((A)[8] == 'x') +#define HAS_EA_I(A) ((A)[9] == 'I') + +enum +{ + EA_MODE_NONE, /* No special addressing mode */ + EA_MODE_AI, /* Address register indirect */ + EA_MODE_PI, /* Address register indirect with postincrement */ + EA_MODE_PI7, /* Address register 7 indirect with postincrement */ + EA_MODE_PD, /* Address register indirect with predecrement */ + EA_MODE_PD7, /* Address register 7 indirect with predecrement */ + EA_MODE_DI, /* Address register indirect with displacement */ + EA_MODE_IX, /* Address register indirect with index */ + EA_MODE_AW, /* Absolute word */ + EA_MODE_AL, /* Absolute long */ + EA_MODE_PCDI, /* Program counter indirect with displacement */ + EA_MODE_PCIX, /* Program counter indirect with index */ + EA_MODE_I /* Immediate */ +}; + + +/* Everything we need to know about an opcode */ +typedef struct +{ + char name[MAX_NAME_LENGTH]; /* opcode handler name */ + unsigned char size; /* Size of operation */ + char spec_proc[MAX_SPEC_PROC_LENGTH]; /* Special processing mode */ + char spec_ea[MAX_SPEC_EA_LENGTH]; /* Specified effective addressing mode */ + unsigned char bits; /* Number of significant bits (used for sorting the table) */ + unsigned short op_mask; /* Mask to apply for matching an opcode to a handler */ + unsigned short op_match; /* Value to match after masking */ + char ea_allowed[EA_ALLOWED_LENGTH]; /* Effective addressing modes allowed */ + char cpu_mode[NUM_CPUS]; /* User or supervisor mode */ + char cpus[NUM_CPUS+1]; /* Allowed CPUs */ + unsigned char cycles[NUM_CPUS]; /* cycles for 000, 010, 020 */ +} opcode_struct; + + +/* All modifications necessary for a specific EA mode of an instruction */ +typedef struct +{ + const char* fname_add; + const char* ea_add; + unsigned int mask_add; + unsigned int match_add; +} ea_info_struct; + + +/* Holds the body of a function */ +typedef struct +{ + char body[MAX_BODY_LENGTH][MAX_LINE_LENGTH+1]; + int length; +} body_struct; + + +/* Holds a sequence of search / replace strings */ +typedef struct +{ + char replace[MAX_REPLACE_LENGTH][2][MAX_LINE_LENGTH+1]; + int length; +} replace_struct; + + +/* Function Prototypes */ +void error_exit(const char* fmt, ...); +void perror_exit(const char* fmt, ...); +int check_strsncpy(char* dst, char* src, int maxlength); +int check_atoi(char* str, int *result); +int skip_spaces(char* str); +int num_bits(int value); +int atoh(char* buff); +int fgetline(char* buff, int nchars, FILE* file); +int get_oper_cycles(opcode_struct* op, int ea_mode, int cpu_type); +opcode_struct* find_opcode(char* name, int size, char* spec_proc, char* spec_ea); +opcode_struct* find_illegal_opcode(void); +int extract_opcode_info(char* src, char* name, int* size, char* spec_proc, char* spec_ea); +void add_replace_string(replace_struct* replace, const char* search_str, const char* replace_str); +void write_body(FILE* filep, body_struct* body, replace_struct* replace); +void get_base_name(char* base_name, opcode_struct* op); +void write_prototype(FILE* filep, char* base_name); +void write_function_name(FILE* filep, char* base_name); +void add_opcode_output_table_entry(opcode_struct* op, char* name); +static int DECL_SPEC compare_nof_true_bits(const void* aptr, const void* bptr); +void print_opcode_output_table(FILE* filep); +void write_table_entry(FILE* filep, opcode_struct* op); +void set_opcode_struct(opcode_struct* src, opcode_struct* dst, int ea_mode); +void generate_opcode_handler(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* opinfo, int ea_mode); +void generate_opcode_ea_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op); +void generate_opcode_cc_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op_in, int offset); +void process_opcode_handlers(void); +void populate_table(void); +void read_insert(char* insert); + + + +/* ======================================================================== */ +/* ================================= DATA ================================= */ +/* ======================================================================== */ + +/* Name of the input file */ +char g_input_filename[M68K_MAX_PATH] = FILENAME_INPUT; + +/* File handles */ +FILE* g_input_file = NULL; +FILE* g_prototype_file = NULL; +FILE* g_table_file = NULL; +FILE* g_ops_ac_file = NULL; +FILE* g_ops_dm_file = NULL; +FILE* g_ops_nz_file = NULL; + +int g_num_functions = 0; /* Number of functions processed */ +int g_num_primitives = 0; /* Number of function primitives read */ +int g_line_number = 1; /* Current line number */ + +/* Opcode handler table */ +opcode_struct g_opcode_input_table[MAX_OPCODE_INPUT_TABLE_LENGTH]; + +opcode_struct g_opcode_output_table[MAX_OPCODE_OUTPUT_TABLE_LENGTH]; +int g_opcode_output_table_length = 0; + +ea_info_struct g_ea_info_table[13] = +{/* fname ea mask match */ + {"", "", 0x00, 0x00}, /* EA_MODE_NONE */ + {"ai", "AY_AI", 0x38, 0x10}, /* EA_MODE_AI */ + {"pi", "AY_PI", 0x38, 0x18}, /* EA_MODE_PI */ + {"pi7", "A7_PI", 0x3f, 0x1f}, /* EA_MODE_PI7 */ + {"pd", "AY_PD", 0x38, 0x20}, /* EA_MODE_PD */ + {"pd7", "A7_PD", 0x3f, 0x27}, /* EA_MODE_PD7 */ + {"di", "AY_DI", 0x38, 0x28}, /* EA_MODE_DI */ + {"ix", "AY_IX", 0x38, 0x30}, /* EA_MODE_IX */ + {"aw", "AW", 0x3f, 0x38}, /* EA_MODE_AW */ + {"al", "AL", 0x3f, 0x39}, /* EA_MODE_AL */ + {"pcdi", "PCDI", 0x3f, 0x3a}, /* EA_MODE_PCDI */ + {"pcix", "PCIX", 0x3f, 0x3b}, /* EA_MODE_PCIX */ + {"i", "I", 0x3f, 0x3c}, /* EA_MODE_I */ +}; + + +const char* g_cc_table[16][2] = +{ + { "t", "T"}, /* 0000 */ + { "f", "F"}, /* 0001 */ + {"hi", "HI"}, /* 0010 */ + {"ls", "LS"}, /* 0011 */ + {"cc", "CC"}, /* 0100 */ + {"cs", "CS"}, /* 0101 */ + {"ne", "NE"}, /* 0110 */ + {"eq", "EQ"}, /* 0111 */ + {"vc", "VC"}, /* 1000 */ + {"vs", "VS"}, /* 1001 */ + {"pl", "PL"}, /* 1010 */ + {"mi", "MI"}, /* 1011 */ + {"ge", "GE"}, /* 1100 */ + {"lt", "LT"}, /* 1101 */ + {"gt", "GT"}, /* 1110 */ + {"le", "LE"}, /* 1111 */ +}; + +/* size to index translator (0 -> 0, 8 and 16 -> 1, 32 -> 2) */ +int g_size_select_table[33] = +{ + 0, /* unsized */ + 0, 0, 0, 0, 0, 0, 0, 1, /* 8 */ + 0, 0, 0, 0, 0, 0, 0, 1, /* 16 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 /* 32 */ +}; + +/* Extra cycles required for certain EA modes */ +/* TODO: correct timings for 040 */ +int g_ea_cycle_table[13][NUM_CPUS][3] = +{/* 000 010 020 040 */ + {{ 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}}, /* EA_MODE_NONE */ + {{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_AI */ + {{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_PI */ + {{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_PI7 */ + {{ 0, 6, 10}, { 0, 6, 10}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_PD */ + {{ 0, 6, 10}, { 0, 6, 10}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_PD7 */ + {{ 0, 8, 12}, { 0, 8, 12}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_DI */ + {{ 0, 10, 14}, { 0, 10, 14}, { 0, 7, 7}, { 0, 7, 7}}, /* EA_MODE_IX */ + {{ 0, 8, 12}, { 0, 8, 12}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_AW */ + {{ 0, 12, 16}, { 0, 12, 16}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_AL */ + {{ 0, 8, 12}, { 0, 8, 12}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_PCDI */ + {{ 0, 10, 14}, { 0, 10, 14}, { 0, 7, 7}, { 0, 7, 7}}, /* EA_MODE_PCIX */ + {{ 0, 4, 8}, { 0, 4, 8}, { 0, 2, 4}, { 0, 2, 4}}, /* EA_MODE_I */ +}; + +/* Extra cycles for JMP instruction (000, 010) */ +int g_jmp_cycle_table[13] = +{ + 0, /* EA_MODE_NONE */ + 4, /* EA_MODE_AI */ + 0, /* EA_MODE_PI */ + 0, /* EA_MODE_PI7 */ + 0, /* EA_MODE_PD */ + 0, /* EA_MODE_PD7 */ + 6, /* EA_MODE_DI */ + 10, /* EA_MODE_IX */ + 6, /* EA_MODE_AW */ + 8, /* EA_MODE_AL */ + 6, /* EA_MODE_PCDI */ + 10, /* EA_MODE_PCIX */ + 0, /* EA_MODE_I */ +}; + +/* Extra cycles for JSR instruction (000, 010) */ +int g_jsr_cycle_table[13] = +{ + 0, /* EA_MODE_NONE */ + 4, /* EA_MODE_AI */ + 0, /* EA_MODE_PI */ + 0, /* EA_MODE_PI7 */ + 0, /* EA_MODE_PD */ + 0, /* EA_MODE_PD7 */ + 6, /* EA_MODE_DI */ + 10, /* EA_MODE_IX */ + 6, /* EA_MODE_AW */ + 8, /* EA_MODE_AL */ + 6, /* EA_MODE_PCDI */ + 10, /* EA_MODE_PCIX */ + 0, /* EA_MODE_I */ +}; + +/* Extra cycles for LEA instruction (000, 010) */ +int g_lea_cycle_table[13] = +{ + 0, /* EA_MODE_NONE */ + 4, /* EA_MODE_AI */ + 0, /* EA_MODE_PI */ + 0, /* EA_MODE_PI7 */ + 0, /* EA_MODE_PD */ + 0, /* EA_MODE_PD7 */ + 8, /* EA_MODE_DI */ + 12, /* EA_MODE_IX */ + 8, /* EA_MODE_AW */ + 12, /* EA_MODE_AL */ + 8, /* EA_MODE_PCDI */ + 12, /* EA_MODE_PCIX */ + 0, /* EA_MODE_I */ +}; + +/* Extra cycles for PEA instruction (000, 010) */ +int g_pea_cycle_table[13] = +{ + 0, /* EA_MODE_NONE */ + 6, /* EA_MODE_AI */ + 0, /* EA_MODE_PI */ + 0, /* EA_MODE_PI7 */ + 0, /* EA_MODE_PD */ + 0, /* EA_MODE_PD7 */ + 10, /* EA_MODE_DI */ + 14, /* EA_MODE_IX */ + 10, /* EA_MODE_AW */ + 14, /* EA_MODE_AL */ + 10, /* EA_MODE_PCDI */ + 14, /* EA_MODE_PCIX */ + 0, /* EA_MODE_I */ +}; + +/* Extra cycles for MOVEM instruction (000, 010) */ +int g_movem_cycle_table[13] = +{ + 0, /* EA_MODE_NONE */ + 0, /* EA_MODE_AI */ + 0, /* EA_MODE_PI */ + 0, /* EA_MODE_PI7 */ + 0, /* EA_MODE_PD */ + 0, /* EA_MODE_PD7 */ + 4, /* EA_MODE_DI */ + 6, /* EA_MODE_IX */ + 4, /* EA_MODE_AW */ + 8, /* EA_MODE_AL */ + 0, /* EA_MODE_PCDI */ + 0, /* EA_MODE_PCIX */ + 0, /* EA_MODE_I */ +}; + +/* Extra cycles for MOVES instruction (010) */ +int g_moves_cycle_table[13][3] = +{ + { 0, 0, 0}, /* EA_MODE_NONE */ + { 0, 4, 6}, /* EA_MODE_AI */ + { 0, 4, 6}, /* EA_MODE_PI */ + { 0, 4, 6}, /* EA_MODE_PI7 */ + { 0, 6, 12}, /* EA_MODE_PD */ + { 0, 6, 12}, /* EA_MODE_PD7 */ + { 0, 12, 16}, /* EA_MODE_DI */ + { 0, 16, 20}, /* EA_MODE_IX */ + { 0, 12, 16}, /* EA_MODE_AW */ + { 0, 16, 20}, /* EA_MODE_AL */ + { 0, 0, 0}, /* EA_MODE_PCDI */ + { 0, 0, 0}, /* EA_MODE_PCIX */ + { 0, 0, 0}, /* EA_MODE_I */ +}; + +/* Extra cycles for CLR instruction (010) */ +int g_clr_cycle_table[13][3] = +{ + { 0, 0, 0}, /* EA_MODE_NONE */ + { 0, 4, 6}, /* EA_MODE_AI */ + { 0, 4, 6}, /* EA_MODE_PI */ + { 0, 4, 6}, /* EA_MODE_PI7 */ + { 0, 6, 8}, /* EA_MODE_PD */ + { 0, 6, 8}, /* EA_MODE_PD7 */ + { 0, 8, 10}, /* EA_MODE_DI */ + { 0, 10, 14}, /* EA_MODE_IX */ + { 0, 8, 10}, /* EA_MODE_AW */ + { 0, 10, 14}, /* EA_MODE_AL */ + { 0, 0, 0}, /* EA_MODE_PCDI */ + { 0, 0, 0}, /* EA_MODE_PCIX */ + { 0, 0, 0}, /* EA_MODE_I */ +}; + + + +/* ======================================================================== */ +/* =========================== UTILITY FUNCTIONS ========================== */ +/* ======================================================================== */ + +/* Print an error message and exit with status error */ +void error_exit(const char* fmt, ...) +{ + va_list args; + fprintf(stderr, "In %s, near or on line %d:\n\t", g_input_filename, g_line_number); + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + fprintf(stderr, "\n"); + + if(g_prototype_file) fclose(g_prototype_file); + if(g_table_file) fclose(g_table_file); + if(g_ops_ac_file) fclose(g_ops_ac_file); + if(g_ops_dm_file) fclose(g_ops_dm_file); + if(g_ops_nz_file) fclose(g_ops_nz_file); + if(g_input_file) fclose(g_input_file); + + exit(EXIT_FAILURE); +} + +/* Print an error message, call perror(), and exit with status error */ +void perror_exit(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + perror(""); + + if(g_prototype_file) fclose(g_prototype_file); + if(g_table_file) fclose(g_table_file); + if(g_ops_ac_file) fclose(g_ops_ac_file); + if(g_ops_dm_file) fclose(g_ops_dm_file); + if(g_ops_nz_file) fclose(g_ops_nz_file); + if(g_input_file) fclose(g_input_file); + + exit(EXIT_FAILURE); +} + + +/* copy until 0 or space and exit with error if we read too far */ +int check_strsncpy(char* dst, char* src, int maxlength) +{ + char* p = dst; + while(*src && *src != ' ') + { + *p++ = *src++; + if(p - dst > maxlength) + error_exit("Field too long"); + } + *p = 0; + return p - dst; +} + +/* copy until 0 or specified character and exit with error if we read too far */ +int check_strcncpy(char* dst, char* src, char delim, int maxlength) +{ + char* p = dst; + while(*src && *src != delim) + { + *p++ = *src++; + if(p - dst > maxlength) + error_exit("Field too long"); + } + *p = 0; + return p - dst; +} + +/* convert ascii to integer and exit with error if we find invalid data */ +int check_atoi(char* str, int *result) +{ + int accum = 0; + char* p = str; + while(*p >= '0' && *p <= '9') + { + accum *= 10; + accum += *p++ - '0'; + } + if(*p != ' ' && *p != 0) + error_exit("Malformed integer value (%c)", *p); + *result = accum; + return p - str; +} + +/* Skip past spaces in a string */ +int skip_spaces(char* str) +{ + char* p = str; + + while(*p == ' ') + p++; + + return p - str; +} + +/* Count the number of set bits in a value */ +int num_bits(int value) +{ + value = ((value & 0xaaaa) >> 1) + (value & 0x5555); + value = ((value & 0xcccc) >> 2) + (value & 0x3333); + value = ((value & 0xf0f0) >> 4) + (value & 0x0f0f); + value = ((value & 0xff00) >> 8) + (value & 0x00ff); + return value; +} + +/* Convert a hex value written in ASCII */ +int atoh(char* buff) +{ + int accum = 0; + + for(;;buff++) + { + if(*buff >= '0' && *buff <= '9') + { + accum <<= 4; + accum += *buff - '0'; + } + else if(*buff >= 'a' && *buff <= 'f') + { + accum <<= 4; + accum += *buff - 'a' + 10; + } + else break; + } + return accum; +} + +/* Get a line of text from a file, discarding any end-of-line characters */ +int fgetline(char* buff, int nchars, FILE* file) +{ + int length; + + if(fgets(buff, nchars, file) == NULL) + return -1; + if(buff[0] == '\r') + memcpy(buff, buff + 1, nchars - 1); + + length = strlen(buff); + while(length && (buff[length-1] == '\r' || buff[length-1] == '\n')) + length--; + buff[length] = 0; + g_line_number++; + + return length; +} + + + +/* ======================================================================== */ +/* =========================== HELPER FUNCTIONS =========================== */ +/* ======================================================================== */ + +/* Calculate the number of cycles an opcode requires */ +int get_oper_cycles(opcode_struct* op, int ea_mode, int cpu_type) +{ + int size = g_size_select_table[op->size]; + + if(op->cpus[cpu_type] == '.') + return 0; + + if(cpu_type < CPU_TYPE_020) + { + if(cpu_type == CPU_TYPE_010) + { + if(strcmp(op->name, "moves") == 0) + return op->cycles[cpu_type] + g_moves_cycle_table[ea_mode][size]; + if(strcmp(op->name, "clr") == 0) + return op->cycles[cpu_type] + g_clr_cycle_table[ea_mode][size]; + } + + /* ASG: added these cases -- immediate modes take 2 extra cycles here */ + /* SV: but only when operating on long, and also on register direct mode */ + if(cpu_type == CPU_TYPE_000 && (ea_mode == EA_MODE_I || ea_mode == EA_MODE_NONE) && op->size == 32 && + ((strcmp(op->name, "add") == 0 && strcmp(op->spec_proc, "er") == 0) || + strcmp(op->name, "adda") == 0 || + (strcmp(op->name, "and") == 0 && strcmp(op->spec_proc, "er") == 0) || + (strcmp(op->name, "or") == 0 && strcmp(op->spec_proc, "er") == 0) || + (strcmp(op->name, "sub") == 0 && strcmp(op->spec_proc, "er") == 0) || + strcmp(op->name, "suba") == 0)) + return op->cycles[cpu_type] + g_ea_cycle_table[ea_mode][cpu_type][size] + 2; + + if(strcmp(op->name, "jmp") == 0) + return op->cycles[cpu_type] + g_jmp_cycle_table[ea_mode]; + if(strcmp(op->name, "jsr") == 0) + return op->cycles[cpu_type] + g_jsr_cycle_table[ea_mode]; + if(strcmp(op->name, "lea") == 0) + return op->cycles[cpu_type] + g_lea_cycle_table[ea_mode]; + if(strcmp(op->name, "pea") == 0) + return op->cycles[cpu_type] + g_pea_cycle_table[ea_mode]; + if(strcmp(op->name, "movem") == 0) + return op->cycles[cpu_type] + g_movem_cycle_table[ea_mode]; + } + return op->cycles[cpu_type] + g_ea_cycle_table[ea_mode][cpu_type][size]; +} + +/* Find an opcode in the opcode handler list */ +opcode_struct* find_opcode(char* name, int size, char* spec_proc, char* spec_ea) +{ + opcode_struct* op; + + + for(op = g_opcode_input_table;op->name != NULL;op++) + { + if( strcmp(name, op->name) == 0 && + (size == op->size) && + strcmp(spec_proc, op->spec_proc) == 0 && + strcmp(spec_ea, op->spec_ea) == 0) + return op; + } + return NULL; +} + +/* Specifically find the illegal opcode in the list */ +opcode_struct* find_illegal_opcode(void) +{ + opcode_struct* op; + + for(op = g_opcode_input_table;op->name != NULL;op++) + { + if(strcmp(op->name, "illegal") == 0) + return op; + } + return NULL; +} + +/* Parse an opcode handler name */ +int extract_opcode_info(char* src, char* name, int* size, char* spec_proc, char* spec_ea) +{ + char* ptr = strstr(src, ID_OPHANDLER_NAME); + + if(ptr == NULL) + return 0; + + ptr += strlen(ID_OPHANDLER_NAME) + 1; + + ptr += check_strcncpy(name, ptr, ',', MAX_NAME_LENGTH); + if(*ptr != ',') return 0; + ptr++; + ptr += skip_spaces(ptr); + + *size = atoi(ptr); + ptr = strstr(ptr, ","); + if(ptr == NULL) return 0; + ptr++; + ptr += skip_spaces(ptr); + + ptr += check_strcncpy(spec_proc, ptr, ',', MAX_SPEC_PROC_LENGTH); + if(*ptr != ',') return 0; + ptr++; + ptr += skip_spaces(ptr); + + ptr += check_strcncpy(spec_ea, ptr, ')', MAX_SPEC_EA_LENGTH); + if(*ptr != ')') return 0; + ptr++; + ptr += skip_spaces(ptr); + + return 1; +} + + +/* Add a search/replace pair to a replace structure */ +void add_replace_string(replace_struct* replace, const char* search_str, const char* replace_str) +{ + if(replace->length >= MAX_REPLACE_LENGTH) + error_exit("overflow in replace structure"); + + strcpy(replace->replace[replace->length][0], search_str); + strcpy(replace->replace[replace->length++][1], replace_str); +} + +/* Write a function body while replacing any selected strings */ +void write_body(FILE* filep, body_struct* body, replace_struct* replace) +{ + int i; + int j; + char* ptr; + char output[MAX_LINE_LENGTH+1]; + char temp_buff[MAX_LINE_LENGTH+1]; + int found; + + for(i=0;ilength;i++) + { + strcpy(output, body->body[i]); + /* Check for the base directive header */ + if(strstr(output, ID_BASE) != NULL) + { + /* Search for any text we need to replace */ + found = 0; + for(j=0;jlength;j++) + { + ptr = strstr(output, replace->replace[j][0]); + if(ptr) + { + /* We found something to replace */ + found = 1; + strcpy(temp_buff, ptr+strlen(replace->replace[j][0])); + strcpy(ptr, replace->replace[j][1]); + strcat(ptr, temp_buff); + } + } + /* Found a directive with no matching replace string */ + if(!found) + error_exit("Unknown " ID_BASE " directive"); + } + fprintf(filep, "%s\n", output); + } + fprintf(filep, "\n\n"); +} + +/* Generate a base function name from an opcode struct */ +void get_base_name(char* base_name, opcode_struct* op) +{ + sprintf(base_name, "m68k_op_%s", op->name); + if(op->size > 0) + sprintf(base_name+strlen(base_name), "_%d", op->size); + if(strcmp(op->spec_proc, UNSPECIFIED) != 0) + sprintf(base_name+strlen(base_name), "_%s", op->spec_proc); + if(strcmp(op->spec_ea, UNSPECIFIED) != 0) + sprintf(base_name+strlen(base_name), "_%s", op->spec_ea); +} + +/* Write the prototype of an opcode handler function */ +void write_prototype(FILE* filep, char* base_name) +{ + fprintf(filep, "void %s(void);\n", base_name); +} + +/* Write the name of an opcode handler function */ +void write_function_name(FILE* filep, char* base_name) +{ + fprintf(filep, "void %s(void)\n", base_name); +} + +void add_opcode_output_table_entry(opcode_struct* op, char* name) +{ + opcode_struct* ptr; + if(g_opcode_output_table_length > MAX_OPCODE_OUTPUT_TABLE_LENGTH) + error_exit("Opcode output table overflow"); + + ptr = g_opcode_output_table + g_opcode_output_table_length++; + + *ptr = *op; + strcpy(ptr->name, name); + ptr->bits = num_bits(ptr->op_mask); +} + +/* + * Comparison function for qsort() + * For entries with an equal number of set bits in + * the mask compare the match values + */ +static int DECL_SPEC compare_nof_true_bits(const void* aptr, const void* bptr) +{ + const opcode_struct *a = aptr, *b = bptr; + if(a->bits != b->bits) + return a->bits - b->bits; + if(a->op_mask != b->op_mask) + return a->op_mask - b->op_mask; + return a->op_match - b->op_match; +} + +void print_opcode_output_table(FILE* filep) +{ + int i; + qsort((void *)g_opcode_output_table, g_opcode_output_table_length, sizeof(g_opcode_output_table[0]), compare_nof_true_bits); + + for(i=0;iname, op->op_mask, op->op_match); + + for(i=0;icycles[i]); + if(i < NUM_CPUS-1) + fprintf(filep, ", "); + } + + fprintf(filep, "}},\n"); +} + +/* Fill out an opcode struct with a specific addressing mode of the source opcode struct */ +void set_opcode_struct(opcode_struct* src, opcode_struct* dst, int ea_mode) +{ + int i; + + *dst = *src; + + for(i=0;icycles[i] = get_oper_cycles(dst, ea_mode, i); + if(strcmp(dst->spec_ea, UNSPECIFIED) == 0 && ea_mode != EA_MODE_NONE) + sprintf(dst->spec_ea, "%s", g_ea_info_table[ea_mode].fname_add); + dst->op_mask |= g_ea_info_table[ea_mode].mask_add; + dst->op_match |= g_ea_info_table[ea_mode].match_add; +} + + +/* Generate a final opcode handler from the provided data */ +void generate_opcode_handler(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* opinfo, int ea_mode) +{ + char str[MAX_LINE_LENGTH+1]; + opcode_struct* op = malloc(sizeof(opcode_struct)); + + /* Set the opcode structure and write the tables, prototypes, etc */ + set_opcode_struct(opinfo, op, ea_mode); + get_base_name(str, op); + write_prototype(g_prototype_file, str); + add_opcode_output_table_entry(op, str); + write_function_name(filep, str); + + /* Add any replace strings needed */ + if(ea_mode != EA_MODE_NONE) + { + sprintf(str, "EA_%s_8()", g_ea_info_table[ea_mode].ea_add); + add_replace_string(replace, ID_OPHANDLER_EA_AY_8, str); + sprintf(str, "EA_%s_16()", g_ea_info_table[ea_mode].ea_add); + add_replace_string(replace, ID_OPHANDLER_EA_AY_16, str); + sprintf(str, "EA_%s_32()", g_ea_info_table[ea_mode].ea_add); + add_replace_string(replace, ID_OPHANDLER_EA_AY_32, str); + sprintf(str, "OPER_%s_8()", g_ea_info_table[ea_mode].ea_add); + add_replace_string(replace, ID_OPHANDLER_OPER_AY_8, str); + sprintf(str, "OPER_%s_16()", g_ea_info_table[ea_mode].ea_add); + add_replace_string(replace, ID_OPHANDLER_OPER_AY_16, str); + sprintf(str, "OPER_%s_32()", g_ea_info_table[ea_mode].ea_add); + add_replace_string(replace, ID_OPHANDLER_OPER_AY_32, str); + } + + /* Now write the function body with the selected replace strings */ + write_body(filep, body, replace); + g_num_functions++; + free(op); +} + +/* Generate opcode variants based on available addressing modes */ +void generate_opcode_ea_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op) +{ + int old_length = replace->length; + + /* No ea modes available for this opcode */ + if(HAS_NO_EA_MODE(op->ea_allowed)) + { + generate_opcode_handler(filep, body, replace, op, EA_MODE_NONE); + return; + } + + /* Check for and create specific opcodes for each available addressing mode */ + if(HAS_EA_AI(op->ea_allowed)) + generate_opcode_handler(filep, body, replace, op, EA_MODE_AI); + replace->length = old_length; + if(HAS_EA_PI(op->ea_allowed)) + { + generate_opcode_handler(filep, body, replace, op, EA_MODE_PI); + replace->length = old_length; + if(op->size == 8) + generate_opcode_handler(filep, body, replace, op, EA_MODE_PI7); + } + replace->length = old_length; + if(HAS_EA_PD(op->ea_allowed)) + { + generate_opcode_handler(filep, body, replace, op, EA_MODE_PD); + replace->length = old_length; + if(op->size == 8) + generate_opcode_handler(filep, body, replace, op, EA_MODE_PD7); + } + replace->length = old_length; + if(HAS_EA_DI(op->ea_allowed)) + generate_opcode_handler(filep, body, replace, op, EA_MODE_DI); + replace->length = old_length; + if(HAS_EA_IX(op->ea_allowed)) + generate_opcode_handler(filep, body, replace, op, EA_MODE_IX); + replace->length = old_length; + if(HAS_EA_AW(op->ea_allowed)) + generate_opcode_handler(filep, body, replace, op, EA_MODE_AW); + replace->length = old_length; + if(HAS_EA_AL(op->ea_allowed)) + generate_opcode_handler(filep, body, replace, op, EA_MODE_AL); + replace->length = old_length; + if(HAS_EA_PCDI(op->ea_allowed)) + generate_opcode_handler(filep, body, replace, op, EA_MODE_PCDI); + replace->length = old_length; + if(HAS_EA_PCIX(op->ea_allowed)) + generate_opcode_handler(filep, body, replace, op, EA_MODE_PCIX); + replace->length = old_length; + if(HAS_EA_I(op->ea_allowed)) + generate_opcode_handler(filep, body, replace, op, EA_MODE_I); + replace->length = old_length; +} + +/* Generate variants of condition code opcodes */ +void generate_opcode_cc_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op_in, int offset) +{ + char repl[20]; + char replnot[20]; + int i; + int old_length = replace->length; + opcode_struct* op = malloc(sizeof(opcode_struct)); + + *op = *op_in; + + op->op_mask |= 0x0f00; + + /* Do all condition codes except t and f */ + for(i=2;i<16;i++) + { + /* Add replace strings for this condition code */ + sprintf(repl, "COND_%s()", g_cc_table[i][1]); + sprintf(replnot, "COND_NOT_%s()", g_cc_table[i][1]); + + add_replace_string(replace, ID_OPHANDLER_CC, repl); + add_replace_string(replace, ID_OPHANDLER_NOT_CC, replnot); + + /* Set the new opcode info */ + strcpy(op->name+offset, g_cc_table[i][0]); + + op->op_match = (op->op_match & 0xf0ff) | (i<<8); + + /* Generate all opcode variants for this modified opcode */ + generate_opcode_ea_variants(filep, body, replace, op); + /* Remove the above replace strings */ + replace->length = old_length; + } + free(op); +} + +/* Process the opcode handlers section of the input file */ +void process_opcode_handlers(void) +{ + FILE* input_file = g_input_file; + FILE* output_file; + char func_name[MAX_LINE_LENGTH+1]; + char oper_name[MAX_LINE_LENGTH+1]; + int oper_size; + char oper_spec_proc[MAX_LINE_LENGTH+1]; + char oper_spec_ea[MAX_LINE_LENGTH+1]; + opcode_struct* opinfo; + replace_struct* replace = malloc(sizeof(replace_struct)); + body_struct* body = malloc(sizeof(body_struct)); + + + output_file = g_ops_ac_file; + + for(;;) + { + /* Find the first line of the function */ + func_name[0] = 0; + while(strstr(func_name, ID_OPHANDLER_NAME) == NULL) + { + if(strcmp(func_name, ID_INPUT_SEPARATOR) == 0) + { + free(replace); + free(body); + return; /* all done */ + } + if(fgetline(func_name, MAX_LINE_LENGTH, input_file) < 0) + error_exit("Premature end of file when getting function name"); + } + /* Get the rest of the function */ + for(body->length=0;;body->length++) + { + if(body->length > MAX_BODY_LENGTH) + error_exit("Function too long"); + + if(fgetline(body->body[body->length], MAX_LINE_LENGTH, input_file) < 0) + error_exit("Premature end of file when getting function body"); + + if(body->body[body->length][0] == '}') + { + body->length++; + break; + } + } + + g_num_primitives++; + + /* Extract the function name information */ + if(!extract_opcode_info(func_name, oper_name, &oper_size, oper_spec_proc, oper_spec_ea)) + error_exit("Invalid " ID_OPHANDLER_NAME " format"); + + /* Find the corresponding table entry */ + opinfo = find_opcode(oper_name, oper_size, oper_spec_proc, oper_spec_ea); + if(opinfo == NULL) + error_exit("Unable to find matching table entry for %s", func_name); + + /* Change output files if we pass 'c' or 'n' */ + if(output_file == g_ops_ac_file && oper_name[0] > 'c') + output_file = g_ops_dm_file; + else if(output_file == g_ops_dm_file && oper_name[0] > 'm') + output_file = g_ops_nz_file; + + replace->length = 0; + + /* Generate opcode variants */ + if(strcmp(opinfo->name, "bcc") == 0 || strcmp(opinfo->name, "scc") == 0) + generate_opcode_cc_variants(output_file, body, replace, opinfo, 1); + else if(strcmp(opinfo->name, "dbcc") == 0) + generate_opcode_cc_variants(output_file, body, replace, opinfo, 2); + else if(strcmp(opinfo->name, "trapcc") == 0) + generate_opcode_cc_variants(output_file, body, replace, opinfo, 4); + else + generate_opcode_ea_variants(output_file, body, replace, opinfo); + } + + free(replace); + free(body); +} + + +/* Populate the opcode handler table from the input file */ +void populate_table(void) +{ + char* ptr; + char bitpattern[17]; + opcode_struct* op; + char buff[MAX_LINE_LENGTH]; + int i; + int temp; + + buff[0] = 0; + + /* Find the start of the table */ + while(strcmp(buff, ID_TABLE_START) != 0) + if(fgetline(buff, MAX_LINE_LENGTH, g_input_file) < 0) + error_exit("Premature EOF while reading table"); + + /* Process the entire table */ + for(op = g_opcode_input_table;;op++) + { + if(fgetline(buff, MAX_LINE_LENGTH, g_input_file) < 0) + error_exit("Premature EOF while reading table"); + if(strlen(buff) == 0) + continue; + /* We finish when we find an input separator */ + if(strcmp(buff, ID_INPUT_SEPARATOR) == 0) + break; + + /* Extract the info from the table */ + ptr = buff; + + /* Name */ + ptr += skip_spaces(ptr); + ptr += check_strsncpy(op->name, ptr, MAX_NAME_LENGTH); + + /* Size */ + ptr += skip_spaces(ptr); + ptr += check_atoi(ptr, &temp); + op->size = (unsigned char)temp; + + /* Special processing */ + ptr += skip_spaces(ptr); + ptr += check_strsncpy(op->spec_proc, ptr, MAX_SPEC_PROC_LENGTH); + + /* Specified EA Mode */ + ptr += skip_spaces(ptr); + ptr += check_strsncpy(op->spec_ea, ptr, MAX_SPEC_EA_LENGTH); + + /* Bit Pattern (more processing later) */ + ptr += skip_spaces(ptr); + ptr += check_strsncpy(bitpattern, ptr, 17); + + /* Allowed Addressing Mode List */ + ptr += skip_spaces(ptr); + ptr += check_strsncpy(op->ea_allowed, ptr, EA_ALLOWED_LENGTH); + + /* CPU operating mode (U = user or supervisor, S = supervisor only */ + ptr += skip_spaces(ptr); + for(i=0;icpu_mode[i] = *ptr++; + ptr += skip_spaces(ptr); + } + + /* Allowed CPUs for this instruction */ + for(i=0;icpus[i] = UNSPECIFIED_CH; + op->cycles[i] = 0; + ptr++; + } + else + { + op->cpus[i] = '0' + i; + ptr += check_atoi(ptr, &temp); + op->cycles[i] = (unsigned char)temp; + } + } + + /* generate mask and match from bitpattern */ + op->op_mask = 0; + op->op_match = 0; + for(i=0;i<16;i++) + { + op->op_mask |= (bitpattern[i] != '.') << (15-i); + op->op_match |= (bitpattern[i] == '1') << (15-i); + } + } + /* Terminate the list */ + op->name[0] = 0; +} + +/* Read a header or footer insert from the input file */ +void read_insert(char* insert) +{ + char* ptr = insert; + char* overflow = insert + MAX_INSERT_LENGTH - MAX_LINE_LENGTH; + int length; + char* first_blank = NULL; + + first_blank = NULL; + + /* Skip any leading blank lines */ + for(length = 0;length == 0;length = fgetline(ptr, MAX_LINE_LENGTH, g_input_file)) + if(ptr >= overflow) + error_exit("Buffer overflow reading inserts"); + if(length < 0) + error_exit("Premature EOF while reading inserts"); + + /* Advance and append newline */ + ptr += length; + strcpy(ptr++, "\n"); + + /* Read until next separator */ + for(;;) + { + /* Read a new line */ + if(ptr >= overflow) + error_exit("Buffer overflow reading inserts"); + if((length = fgetline(ptr, MAX_LINE_LENGTH, g_input_file)) < 0) + error_exit("Premature EOF while reading inserts"); + + /* Stop if we read a separator */ + if(strcmp(ptr, ID_INPUT_SEPARATOR) == 0) + break; + + /* keep track in case there are trailing blanks */ + if(length == 0) + { + if(first_blank == NULL) + first_blank = ptr; + } + else + first_blank = NULL; + + /* Advance and append newline */ + ptr += length; + strcpy(ptr++, "\n"); + } + + /* kill any trailing blank lines */ + if(first_blank) + ptr = first_blank; + *ptr++ = 0; +} + + + +/* ======================================================================== */ +/* ============================= MAIN FUNCTION ============================ */ +/* ======================================================================== */ + +int main(int argc, char **argv) +{ + /* File stuff */ + char output_path[M68K_MAX_DIR] = ""; + char filename[M68K_MAX_PATH]; + /* Section identifier */ + char section_id[MAX_LINE_LENGTH+1]; + /* Inserts */ + char temp_insert[MAX_INSERT_LENGTH+1]; + char prototype_footer_insert[MAX_INSERT_LENGTH+1]; + char table_footer_insert[MAX_INSERT_LENGTH+1]; + char ophandler_footer_insert[MAX_INSERT_LENGTH+1]; + /* Flags if we've processed certain parts already */ + int prototype_header_read = 0; + int prototype_footer_read = 0; + int table_header_read = 0; + int table_footer_read = 0; + int ophandler_header_read = 0; + int ophandler_footer_read = 0; + int table_body_read = 0; + int ophandler_body_read = 0; + + printf("\n\t\tMusashi v%s 68000, 68008, 68010, 68EC020, 68020 emulator\n", g_version); + printf("\t\tCopyright 1998-2000 Karl Stenerud (karl@mame.net)\n\n"); + + /* Check if output path and source for the input file are given */ + if(argc > 1) + { + char *ptr; + strcpy(output_path, argv[1]); + + for(ptr = strchr(output_path, '\\'); ptr; ptr = strchr(ptr, '\\')) + *ptr = '/'; + +#if !(defined(__DECC) && defined(VMS)) + if(output_path[strlen(output_path)-1] != '/') + strcat(output_path, "/"); +#endif + + if(argc > 2) + strcpy(g_input_filename, argv[2]); + } + + +#if defined(__DECC) && defined(VMS) + + /* Open the files we need */ + sprintf(filename, "%s%s", output_path, FILENAME_PROTOTYPE); + if((g_prototype_file = fopen(filename, "w")) == NULL) + perror_exit("Unable to create prototype file (%s)\n", filename); + + sprintf(filename, "%s%s", output_path, FILENAME_TABLE); + if((g_table_file = fopen(filename, "w")) == NULL) + perror_exit("Unable to create table file (%s)\n", filename); + + sprintf(filename, "%s%s", output_path, FILENAME_OPS_AC); + if((g_ops_ac_file = fopen(filename, "w")) == NULL) + perror_exit("Unable to create ops ac file (%s)\n", filename); + + sprintf(filename, "%s%s", output_path, FILENAME_OPS_DM); + if((g_ops_dm_file = fopen(filename, "w")) == NULL) + perror_exit("Unable to create ops dm file (%s)\n", filename); + + sprintf(filename, "%s%s", output_path, FILENAME_OPS_NZ); + if((g_ops_nz_file = fopen(filename, "w")) == NULL) + perror_exit("Unable to create ops nz file (%s)\n", filename); + + if((g_input_file=fopen(g_input_filename, "r")) == NULL) + perror_exit("can't open %s for input", g_input_filename); + +#else + + + /* Open the files we need */ + sprintf(filename, "%s%s", output_path, FILENAME_PROTOTYPE); + if((g_prototype_file = fopen(filename, "wt")) == NULL) + perror_exit("Unable to create prototype file (%s)\n", filename); + + sprintf(filename, "%s%s", output_path, FILENAME_TABLE); + if((g_table_file = fopen(filename, "wt")) == NULL) + perror_exit("Unable to create table file (%s)\n", filename); + + sprintf(filename, "%s%s", output_path, FILENAME_OPS_AC); + if((g_ops_ac_file = fopen(filename, "wt")) == NULL) + perror_exit("Unable to create ops ac file (%s)\n", filename); + + sprintf(filename, "%s%s", output_path, FILENAME_OPS_DM); + if((g_ops_dm_file = fopen(filename, "wt")) == NULL) + perror_exit("Unable to create ops dm file (%s)\n", filename); + + sprintf(filename, "%s%s", output_path, FILENAME_OPS_NZ); + if((g_ops_nz_file = fopen(filename, "wt")) == NULL) + perror_exit("Unable to create ops nz file (%s)\n", filename); + + if((g_input_file=fopen(g_input_filename, "rt")) == NULL) + perror_exit("can't open %s for input", g_input_filename); + +#endif + + /* Get to the first section of the input file */ + section_id[0] = 0; + while(strcmp(section_id, ID_INPUT_SEPARATOR) != 0) + if(fgetline(section_id, MAX_LINE_LENGTH, g_input_file) < 0) + error_exit("Premature EOF while reading input file"); + + /* Now process all sections */ + for(;;) + { + if(fgetline(section_id, MAX_LINE_LENGTH, g_input_file) < 0) + error_exit("Premature EOF while reading input file"); + if(strcmp(section_id, ID_PROTOTYPE_HEADER) == 0) + { + if(prototype_header_read) + error_exit("Duplicate prototype header"); + read_insert(temp_insert); + fprintf(g_prototype_file, "%s\n\n", temp_insert); + prototype_header_read = 1; + } + else if(strcmp(section_id, ID_TABLE_HEADER) == 0) + { + if(table_header_read) + error_exit("Duplicate table header"); + read_insert(temp_insert); + fprintf(g_table_file, "%s", temp_insert); + table_header_read = 1; + } + else if(strcmp(section_id, ID_OPHANDLER_HEADER) == 0) + { + if(ophandler_header_read) + error_exit("Duplicate opcode handler header"); + read_insert(temp_insert); + fprintf(g_ops_ac_file, "%s\n\n", temp_insert); + fprintf(g_ops_dm_file, "%s\n\n", temp_insert); + fprintf(g_ops_nz_file, "%s\n\n", temp_insert); + ophandler_header_read = 1; + } + else if(strcmp(section_id, ID_PROTOTYPE_FOOTER) == 0) + { + if(prototype_footer_read) + error_exit("Duplicate prototype footer"); + read_insert(prototype_footer_insert); + prototype_footer_read = 1; + } + else if(strcmp(section_id, ID_TABLE_FOOTER) == 0) + { + if(table_footer_read) + error_exit("Duplicate table footer"); + read_insert(table_footer_insert); + table_footer_read = 1; + } + else if(strcmp(section_id, ID_OPHANDLER_FOOTER) == 0) + { + if(ophandler_footer_read) + error_exit("Duplicate opcode handler footer"); + read_insert(ophandler_footer_insert); + ophandler_footer_read = 1; + } + else if(strcmp(section_id, ID_TABLE_BODY) == 0) + { + if(!prototype_header_read) + error_exit("Table body encountered before prototype header"); + if(!table_header_read) + error_exit("Table body encountered before table header"); + if(!ophandler_header_read) + error_exit("Table body encountered before opcode handler header"); + + if(table_body_read) + error_exit("Duplicate table body"); + + populate_table(); + table_body_read = 1; + } + else if(strcmp(section_id, ID_OPHANDLER_BODY) == 0) + { + if(!prototype_header_read) + error_exit("Opcode handlers encountered before prototype header"); + if(!table_header_read) + error_exit("Opcode handlers encountered before table header"); + if(!ophandler_header_read) + error_exit("Opcode handlers encountered before opcode handler header"); + if(!table_body_read) + error_exit("Opcode handlers encountered before table body"); + + if(ophandler_body_read) + error_exit("Duplicate opcode handler section"); + + process_opcode_handlers(); + + ophandler_body_read = 1; + } + else if(strcmp(section_id, ID_END) == 0) + { + /* End of input file. Do a sanity check and then write footers */ + if(!prototype_header_read) + error_exit("Missing prototype header"); + if(!prototype_footer_read) + error_exit("Missing prototype footer"); + if(!table_header_read) + error_exit("Missing table header"); + if(!table_footer_read) + error_exit("Missing table footer"); + if(!table_body_read) + error_exit("Missing table body"); + if(!ophandler_header_read) + error_exit("Missing opcode handler header"); + if(!ophandler_footer_read) + error_exit("Missing opcode handler footer"); + if(!ophandler_body_read) + error_exit("Missing opcode handler body"); + + print_opcode_output_table(g_table_file); + + fprintf(g_prototype_file, "%s\n\n", prototype_footer_insert); + fprintf(g_table_file, "%s\n\n", table_footer_insert); + fprintf(g_ops_ac_file, "%s\n\n", ophandler_footer_insert); + fprintf(g_ops_dm_file, "%s\n\n", ophandler_footer_insert); + fprintf(g_ops_nz_file, "%s\n\n", ophandler_footer_insert); + + break; + } + else + { + error_exit("Unknown section identifier: %s", section_id); + } + } + + /* Close all files and exit */ + fclose(g_prototype_file); + fclose(g_table_file); + fclose(g_ops_ac_file); + fclose(g_ops_dm_file); + fclose(g_ops_nz_file); + fclose(g_input_file); + + printf("Generated %d opcode handlers from %d primitives\n", g_num_functions, g_num_primitives); + + return 0; +} + + + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ diff --git a/cpu/musashi/m68kopac.c b/cpu/musashi/m68kopac.c new file mode 100644 index 00000000..736ba2ea --- /dev/null +++ b/cpu/musashi/m68kopac.c @@ -0,0 +1,12199 @@ +#include "m68kcpu.h" + +/* ======================================================================== */ +/* ========================= INSTRUCTION HANDLERS ========================= */ +/* ======================================================================== */ + + +void m68k_op_1010(void) +{ + m68ki_exception_1010(); +} + + +void m68k_op_1111(void) +{ + m68ki_exception_1111(); +} + + +void m68k_op_abcd_8_rr(void) +{ + uint* r_dst = &DX; + uint src = DY; + uint dst = *r_dst; + uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(); + + FLAG_V = ~res; /* Undefined V behavior */ + + if(res > 9) + res += 6; + res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); + FLAG_X = FLAG_C = (res > 0x99) << 8; + if(FLAG_C) + res -= 0xa0; + + FLAG_V &= res; /* Undefined V behavior part II */ + FLAG_N = NFLAG_8(res); /* Undefined N behavior */ + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; +} + + +void m68k_op_abcd_8_mm_ax7(void) +{ + uint src = OPER_AY_PD_8(); + uint ea = EA_A7_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(); + + FLAG_V = ~res; /* Undefined V behavior */ + + if(res > 9) + res += 6; + res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); + FLAG_X = FLAG_C = (res > 0x99) << 8; + if(FLAG_C) + res -= 0xa0; + + FLAG_V &= res; /* Undefined V behavior part II */ + FLAG_N = NFLAG_8(res); /* Undefined N behavior */ + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_abcd_8_mm_ay7(void) +{ + uint src = OPER_A7_PD_8(); + uint ea = EA_AX_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(); + + FLAG_V = ~res; /* Undefined V behavior */ + + if(res > 9) + res += 6; + res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); + FLAG_X = FLAG_C = (res > 0x99) << 8; + if(FLAG_C) + res -= 0xa0; + + FLAG_V &= res; /* Undefined V behavior part II */ + FLAG_N = NFLAG_8(res); /* Undefined N behavior */ + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_abcd_8_mm_axy7(void) +{ + uint src = OPER_A7_PD_8(); + uint ea = EA_A7_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(); + + FLAG_V = ~res; /* Undefined V behavior */ + + if(res > 9) + res += 6; + res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); + FLAG_X = FLAG_C = (res > 0x99) << 8; + if(FLAG_C) + res -= 0xa0; + + FLAG_V &= res; /* Undefined V behavior part II */ + FLAG_N = NFLAG_8(res); /* Undefined N behavior */ + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_abcd_8_mm(void) +{ + uint src = OPER_AY_PD_8(); + uint ea = EA_AX_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(); + + FLAG_V = ~res; /* Undefined V behavior */ + + if(res > 9) + res += 6; + res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); + FLAG_X = FLAG_C = (res > 0x99) << 8; + if(FLAG_C) + res -= 0xa0; + + FLAG_V &= res; /* Undefined V behavior part II */ + FLAG_N = NFLAG_8(res); /* Undefined N behavior */ + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_add_8_er_d(void) +{ + uint* r_dst = &DX; + uint src = MASK_OUT_ABOVE_8(DY); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_8_er_ai(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_AI_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_8_er_pi(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_PI_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_8_er_pi7(void) +{ + uint* r_dst = &DX; + uint src = OPER_A7_PI_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_8_er_pd(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_PD_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_8_er_pd7(void) +{ + uint* r_dst = &DX; + uint src = OPER_A7_PD_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_8_er_di(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_DI_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_8_er_ix(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_IX_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_8_er_aw(void) +{ + uint* r_dst = &DX; + uint src = OPER_AW_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_8_er_al(void) +{ + uint* r_dst = &DX; + uint src = OPER_AL_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_8_er_pcdi(void) +{ + uint* r_dst = &DX; + uint src = OPER_PCDI_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_8_er_pcix(void) +{ + uint* r_dst = &DX; + uint src = OPER_PCIX_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_8_er_i(void) +{ + uint* r_dst = &DX; + uint src = OPER_I_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_16_er_d(void) +{ + uint* r_dst = &DX; + uint src = MASK_OUT_ABOVE_16(DY); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_16_er_a(void) +{ + uint* r_dst = &DX; + uint src = MASK_OUT_ABOVE_16(AY); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_16_er_ai(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_AI_16(); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_16_er_pi(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_PI_16(); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_16_er_pd(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_PD_16(); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_16_er_di(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_DI_16(); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_16_er_ix(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_IX_16(); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_16_er_aw(void) +{ + uint* r_dst = &DX; + uint src = OPER_AW_16(); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_16_er_al(void) +{ + uint* r_dst = &DX; + uint src = OPER_AL_16(); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_16_er_pcdi(void) +{ + uint* r_dst = &DX; + uint src = OPER_PCDI_16(); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_16_er_pcix(void) +{ + uint* r_dst = &DX; + uint src = OPER_PCIX_16(); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_16_er_i(void) +{ + uint* r_dst = &DX; + uint src = OPER_I_16(); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_add_32_er_d(void) +{ + uint* r_dst = &DX; + uint src = DY; + uint dst = *r_dst; + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_add_32_er_a(void) +{ + uint* r_dst = &DX; + uint src = AY; + uint dst = *r_dst; + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_add_32_er_ai(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_AI_32(); + uint dst = *r_dst; + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_add_32_er_pi(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_PI_32(); + uint dst = *r_dst; + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_add_32_er_pd(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_PD_32(); + uint dst = *r_dst; + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_add_32_er_di(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_DI_32(); + uint dst = *r_dst; + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_add_32_er_ix(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_IX_32(); + uint dst = *r_dst; + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_add_32_er_aw(void) +{ + uint* r_dst = &DX; + uint src = OPER_AW_32(); + uint dst = *r_dst; + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_add_32_er_al(void) +{ + uint* r_dst = &DX; + uint src = OPER_AL_32(); + uint dst = *r_dst; + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_add_32_er_pcdi(void) +{ + uint* r_dst = &DX; + uint src = OPER_PCDI_32(); + uint dst = *r_dst; + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_add_32_er_pcix(void) +{ + uint* r_dst = &DX; + uint src = OPER_PCIX_32(); + uint dst = *r_dst; + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_add_32_er_i(void) +{ + uint* r_dst = &DX; + uint src = OPER_I_32(); + uint dst = *r_dst; + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_add_8_re_ai(void) +{ + uint ea = EA_AY_AI_8(); + uint src = MASK_OUT_ABOVE_8(DX); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_add_8_re_pi(void) +{ + uint ea = EA_AY_PI_8(); + uint src = MASK_OUT_ABOVE_8(DX); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_add_8_re_pi7(void) +{ + uint ea = EA_A7_PI_8(); + uint src = MASK_OUT_ABOVE_8(DX); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_add_8_re_pd(void) +{ + uint ea = EA_AY_PD_8(); + uint src = MASK_OUT_ABOVE_8(DX); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_add_8_re_pd7(void) +{ + uint ea = EA_A7_PD_8(); + uint src = MASK_OUT_ABOVE_8(DX); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_add_8_re_di(void) +{ + uint ea = EA_AY_DI_8(); + uint src = MASK_OUT_ABOVE_8(DX); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_add_8_re_ix(void) +{ + uint ea = EA_AY_IX_8(); + uint src = MASK_OUT_ABOVE_8(DX); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_add_8_re_aw(void) +{ + uint ea = EA_AW_8(); + uint src = MASK_OUT_ABOVE_8(DX); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_add_8_re_al(void) +{ + uint ea = EA_AL_8(); + uint src = MASK_OUT_ABOVE_8(DX); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_add_16_re_ai(void) +{ + uint ea = EA_AY_AI_16(); + uint src = MASK_OUT_ABOVE_16(DX); + uint dst = m68ki_read_16(ea); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_add_16_re_pi(void) +{ + uint ea = EA_AY_PI_16(); + uint src = MASK_OUT_ABOVE_16(DX); + uint dst = m68ki_read_16(ea); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_add_16_re_pd(void) +{ + uint ea = EA_AY_PD_16(); + uint src = MASK_OUT_ABOVE_16(DX); + uint dst = m68ki_read_16(ea); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_add_16_re_di(void) +{ + uint ea = EA_AY_DI_16(); + uint src = MASK_OUT_ABOVE_16(DX); + uint dst = m68ki_read_16(ea); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_add_16_re_ix(void) +{ + uint ea = EA_AY_IX_16(); + uint src = MASK_OUT_ABOVE_16(DX); + uint dst = m68ki_read_16(ea); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_add_16_re_aw(void) +{ + uint ea = EA_AW_16(); + uint src = MASK_OUT_ABOVE_16(DX); + uint dst = m68ki_read_16(ea); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_add_16_re_al(void) +{ + uint ea = EA_AL_16(); + uint src = MASK_OUT_ABOVE_16(DX); + uint dst = m68ki_read_16(ea); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_add_32_re_ai(void) +{ + uint ea = EA_AY_AI_32(); + uint src = DX; + uint dst = m68ki_read_32(ea); + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_add_32_re_pi(void) +{ + uint ea = EA_AY_PI_32(); + uint src = DX; + uint dst = m68ki_read_32(ea); + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_add_32_re_pd(void) +{ + uint ea = EA_AY_PD_32(); + uint src = DX; + uint dst = m68ki_read_32(ea); + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_add_32_re_di(void) +{ + uint ea = EA_AY_DI_32(); + uint src = DX; + uint dst = m68ki_read_32(ea); + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_add_32_re_ix(void) +{ + uint ea = EA_AY_IX_32(); + uint src = DX; + uint dst = m68ki_read_32(ea); + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_add_32_re_aw(void) +{ + uint ea = EA_AW_32(); + uint src = DX; + uint dst = m68ki_read_32(ea); + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_add_32_re_al(void) +{ + uint ea = EA_AL_32(); + uint src = DX; + uint dst = m68ki_read_32(ea); + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_adda_16_d(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + MAKE_INT_16(DY)); +} + + +void m68k_op_adda_16_a(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + MAKE_INT_16(AY)); +} + + +void m68k_op_adda_16_ai(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + MAKE_INT_16(OPER_AY_AI_16())); +} + + +void m68k_op_adda_16_pi(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + MAKE_INT_16(OPER_AY_PI_16())); +} + + +void m68k_op_adda_16_pd(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + MAKE_INT_16(OPER_AY_PD_16())); +} + + +void m68k_op_adda_16_di(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + MAKE_INT_16(OPER_AY_DI_16())); +} + + +void m68k_op_adda_16_ix(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + MAKE_INT_16(OPER_AY_IX_16())); +} + + +void m68k_op_adda_16_aw(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + MAKE_INT_16(OPER_AW_16())); +} + + +void m68k_op_adda_16_al(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + MAKE_INT_16(OPER_AL_16())); +} + + +void m68k_op_adda_16_pcdi(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + MAKE_INT_16(OPER_PCDI_16())); +} + + +void m68k_op_adda_16_pcix(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + MAKE_INT_16(OPER_PCIX_16())); +} + + +void m68k_op_adda_16_i(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + MAKE_INT_16(OPER_I_16())); +} + + +void m68k_op_adda_32_d(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + DY); +} + + +void m68k_op_adda_32_a(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + AY); +} + + +void m68k_op_adda_32_ai(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + OPER_AY_AI_32()); +} + + +void m68k_op_adda_32_pi(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + OPER_AY_PI_32()); +} + + +void m68k_op_adda_32_pd(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + OPER_AY_PD_32()); +} + + +void m68k_op_adda_32_di(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + OPER_AY_DI_32()); +} + + +void m68k_op_adda_32_ix(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + OPER_AY_IX_32()); +} + + +void m68k_op_adda_32_aw(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + OPER_AW_32()); +} + + +void m68k_op_adda_32_al(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + OPER_AL_32()); +} + + +void m68k_op_adda_32_pcdi(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + OPER_PCDI_32()); +} + + +void m68k_op_adda_32_pcix(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + OPER_PCIX_32()); +} + + +void m68k_op_adda_32_i(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + OPER_I_32()); +} + + +void m68k_op_addi_8_d(void) +{ + uint* r_dst = &DY; + uint src = OPER_I_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_addi_8_ai(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_AI_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_addi_8_pi(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_PI_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_addi_8_pi7(void) +{ + uint src = OPER_I_8(); + uint ea = EA_A7_PI_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_addi_8_pd(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_addi_8_pd7(void) +{ + uint src = OPER_I_8(); + uint ea = EA_A7_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_addi_8_di(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_DI_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_addi_8_ix(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_IX_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_addi_8_aw(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AW_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_addi_8_al(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AL_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_addi_16_d(void) +{ + uint* r_dst = &DY; + uint src = OPER_I_16(); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_addi_16_ai(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_AI_16(); + uint dst = m68ki_read_16(ea); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_addi_16_pi(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_PI_16(); + uint dst = m68ki_read_16(ea); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_addi_16_pd(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_PD_16(); + uint dst = m68ki_read_16(ea); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_addi_16_di(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_DI_16(); + uint dst = m68ki_read_16(ea); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_addi_16_ix(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_IX_16(); + uint dst = m68ki_read_16(ea); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_addi_16_aw(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AW_16(); + uint dst = m68ki_read_16(ea); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_addi_16_al(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AL_16(); + uint dst = m68ki_read_16(ea); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_addi_32_d(void) +{ + uint* r_dst = &DY; + uint src = OPER_I_32(); + uint dst = *r_dst; + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_addi_32_ai(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_AI_32(); + uint dst = m68ki_read_32(ea); + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_addi_32_pi(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_PI_32(); + uint dst = m68ki_read_32(ea); + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_addi_32_pd(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_PD_32(); + uint dst = m68ki_read_32(ea); + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_addi_32_di(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_DI_32(); + uint dst = m68ki_read_32(ea); + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_addi_32_ix(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_IX_32(); + uint dst = m68ki_read_32(ea); + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_addi_32_aw(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AW_32(); + uint dst = m68ki_read_32(ea); + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_addi_32_al(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AL_32(); + uint dst = m68ki_read_32(ea); + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_addq_8_d(void) +{ + uint* r_dst = &DY; + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_addq_8_ai(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_AI_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_addq_8_pi(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_PI_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_addq_8_pi7(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_A7_PI_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_addq_8_pd(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_addq_8_pd7(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_A7_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_addq_8_di(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_DI_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_addq_8_ix(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_IX_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_addq_8_aw(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AW_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_addq_8_al(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AL_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst; + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_addq_16_d(void) +{ + uint* r_dst = &DY; + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_addq_16_a(void) +{ + uint* r_dst = &AY; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + (((REG_IR >> 9) - 1) & 7) + 1); +} + + +void m68k_op_addq_16_ai(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_AI_16(); + uint dst = m68ki_read_16(ea); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_addq_16_pi(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_PI_16(); + uint dst = m68ki_read_16(ea); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_addq_16_pd(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_PD_16(); + uint dst = m68ki_read_16(ea); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_addq_16_di(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_DI_16(); + uint dst = m68ki_read_16(ea); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_addq_16_ix(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_IX_16(); + uint dst = m68ki_read_16(ea); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_addq_16_aw(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AW_16(); + uint dst = m68ki_read_16(ea); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_addq_16_al(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AL_16(); + uint dst = m68ki_read_16(ea); + uint res = src + dst; + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_addq_32_d(void) +{ + uint* r_dst = &DY; + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint dst = *r_dst; + uint res = src + dst; + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_addq_32_a(void) +{ + uint* r_dst = &AY; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + (((REG_IR >> 9) - 1) & 7) + 1); +} + + +void m68k_op_addq_32_ai(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_AI_32(); + uint dst = m68ki_read_32(ea); + uint res = src + dst; + + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_addq_32_pi(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_PI_32(); + uint dst = m68ki_read_32(ea); + uint res = src + dst; + + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_addq_32_pd(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_PD_32(); + uint dst = m68ki_read_32(ea); + uint res = src + dst; + + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_addq_32_di(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_DI_32(); + uint dst = m68ki_read_32(ea); + uint res = src + dst; + + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_addq_32_ix(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_IX_32(); + uint dst = m68ki_read_32(ea); + uint res = src + dst; + + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_addq_32_aw(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AW_32(); + uint dst = m68ki_read_32(ea); + uint res = src + dst; + + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_addq_32_al(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AL_32(); + uint dst = m68ki_read_32(ea); + uint res = src + dst; + + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_addx_8_rr(void) +{ + uint* r_dst = &DX; + uint src = MASK_OUT_ABOVE_8(DY); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = src + dst + XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; +} + + +void m68k_op_addx_16_rr(void) +{ + uint* r_dst = &DX; + uint src = MASK_OUT_ABOVE_16(DY); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = src + dst + XFLAG_AS_1(); + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + + res = MASK_OUT_ABOVE_16(res); + FLAG_Z |= res; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; +} + + +void m68k_op_addx_32_rr(void) +{ + uint* r_dst = &DX; + uint src = DY; + uint dst = *r_dst; + uint res = src + dst + XFLAG_AS_1(); + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + + res = MASK_OUT_ABOVE_32(res); + FLAG_Z |= res; + + *r_dst = res; +} + + +void m68k_op_addx_8_mm_ax7(void) +{ + uint src = OPER_AY_PD_8(); + uint ea = EA_A7_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst + XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_addx_8_mm_ay7(void) +{ + uint src = OPER_A7_PD_8(); + uint ea = EA_AX_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst + XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_addx_8_mm_axy7(void) +{ + uint src = OPER_A7_PD_8(); + uint ea = EA_A7_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst + XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_addx_8_mm(void) +{ + uint src = OPER_AY_PD_8(); + uint ea = EA_AX_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = src + dst + XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_V = VFLAG_ADD_8(src, dst, res); + FLAG_X = FLAG_C = CFLAG_8(res); + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_addx_16_mm(void) +{ + uint src = OPER_AY_PD_16(); + uint ea = EA_AX_PD_16(); + uint dst = m68ki_read_16(ea); + uint res = src + dst + XFLAG_AS_1(); + + FLAG_N = NFLAG_16(res); + FLAG_V = VFLAG_ADD_16(src, dst, res); + FLAG_X = FLAG_C = CFLAG_16(res); + + res = MASK_OUT_ABOVE_16(res); + FLAG_Z |= res; + + m68ki_write_16(ea, res); +} + + +void m68k_op_addx_32_mm(void) +{ + uint src = OPER_AY_PD_32(); + uint ea = EA_AX_PD_32(); + uint dst = m68ki_read_32(ea); + uint res = src + dst + XFLAG_AS_1(); + + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_ADD_32(src, dst, res); + FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); + + res = MASK_OUT_ABOVE_32(res); + FLAG_Z |= res; + + m68ki_write_32(ea, res); +} + + +void m68k_op_and_8_er_d(void) +{ + FLAG_Z = MASK_OUT_ABOVE_8(DX &= (DY | 0xffffff00)); + + FLAG_N = NFLAG_8(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_8_er_ai(void) +{ + FLAG_Z = MASK_OUT_ABOVE_8(DX &= (OPER_AY_AI_8() | 0xffffff00)); + + FLAG_N = NFLAG_8(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_8_er_pi(void) +{ + FLAG_Z = MASK_OUT_ABOVE_8(DX &= (OPER_AY_PI_8() | 0xffffff00)); + + FLAG_N = NFLAG_8(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_8_er_pi7(void) +{ + FLAG_Z = MASK_OUT_ABOVE_8(DX &= (OPER_A7_PI_8() | 0xffffff00)); + + FLAG_N = NFLAG_8(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_8_er_pd(void) +{ + FLAG_Z = MASK_OUT_ABOVE_8(DX &= (OPER_AY_PD_8() | 0xffffff00)); + + FLAG_N = NFLAG_8(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_8_er_pd7(void) +{ + FLAG_Z = MASK_OUT_ABOVE_8(DX &= (OPER_A7_PD_8() | 0xffffff00)); + + FLAG_N = NFLAG_8(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_8_er_di(void) +{ + FLAG_Z = MASK_OUT_ABOVE_8(DX &= (OPER_AY_DI_8() | 0xffffff00)); + + FLAG_N = NFLAG_8(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_8_er_ix(void) +{ + FLAG_Z = MASK_OUT_ABOVE_8(DX &= (OPER_AY_IX_8() | 0xffffff00)); + + FLAG_N = NFLAG_8(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_8_er_aw(void) +{ + FLAG_Z = MASK_OUT_ABOVE_8(DX &= (OPER_AW_8() | 0xffffff00)); + + FLAG_N = NFLAG_8(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_8_er_al(void) +{ + FLAG_Z = MASK_OUT_ABOVE_8(DX &= (OPER_AL_8() | 0xffffff00)); + + FLAG_N = NFLAG_8(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_8_er_pcdi(void) +{ + FLAG_Z = MASK_OUT_ABOVE_8(DX &= (OPER_PCDI_8() | 0xffffff00)); + + FLAG_N = NFLAG_8(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_8_er_pcix(void) +{ + FLAG_Z = MASK_OUT_ABOVE_8(DX &= (OPER_PCIX_8() | 0xffffff00)); + + FLAG_N = NFLAG_8(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_8_er_i(void) +{ + FLAG_Z = MASK_OUT_ABOVE_8(DX &= (OPER_I_8() | 0xffffff00)); + + FLAG_N = NFLAG_8(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_16_er_d(void) +{ + FLAG_Z = MASK_OUT_ABOVE_16(DX &= (DY | 0xffff0000)); + + FLAG_N = NFLAG_16(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_16_er_ai(void) +{ + FLAG_Z = MASK_OUT_ABOVE_16(DX &= (OPER_AY_AI_16() | 0xffff0000)); + + FLAG_N = NFLAG_16(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_16_er_pi(void) +{ + FLAG_Z = MASK_OUT_ABOVE_16(DX &= (OPER_AY_PI_16() | 0xffff0000)); + + FLAG_N = NFLAG_16(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_16_er_pd(void) +{ + FLAG_Z = MASK_OUT_ABOVE_16(DX &= (OPER_AY_PD_16() | 0xffff0000)); + + FLAG_N = NFLAG_16(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_16_er_di(void) +{ + FLAG_Z = MASK_OUT_ABOVE_16(DX &= (OPER_AY_DI_16() | 0xffff0000)); + + FLAG_N = NFLAG_16(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_16_er_ix(void) +{ + FLAG_Z = MASK_OUT_ABOVE_16(DX &= (OPER_AY_IX_16() | 0xffff0000)); + + FLAG_N = NFLAG_16(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_16_er_aw(void) +{ + FLAG_Z = MASK_OUT_ABOVE_16(DX &= (OPER_AW_16() | 0xffff0000)); + + FLAG_N = NFLAG_16(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_16_er_al(void) +{ + FLAG_Z = MASK_OUT_ABOVE_16(DX &= (OPER_AL_16() | 0xffff0000)); + + FLAG_N = NFLAG_16(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_16_er_pcdi(void) +{ + FLAG_Z = MASK_OUT_ABOVE_16(DX &= (OPER_PCDI_16() | 0xffff0000)); + + FLAG_N = NFLAG_16(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_16_er_pcix(void) +{ + FLAG_Z = MASK_OUT_ABOVE_16(DX &= (OPER_PCIX_16() | 0xffff0000)); + + FLAG_N = NFLAG_16(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_16_er_i(void) +{ + FLAG_Z = MASK_OUT_ABOVE_16(DX &= (OPER_I_16() | 0xffff0000)); + + FLAG_N = NFLAG_16(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_32_er_d(void) +{ + FLAG_Z = DX &= DY; + + FLAG_N = NFLAG_32(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_32_er_ai(void) +{ + FLAG_Z = DX &= OPER_AY_AI_32(); + + FLAG_N = NFLAG_32(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_32_er_pi(void) +{ + FLAG_Z = DX &= OPER_AY_PI_32(); + + FLAG_N = NFLAG_32(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_32_er_pd(void) +{ + FLAG_Z = DX &= OPER_AY_PD_32(); + + FLAG_N = NFLAG_32(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_32_er_di(void) +{ + FLAG_Z = DX &= OPER_AY_DI_32(); + + FLAG_N = NFLAG_32(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_32_er_ix(void) +{ + FLAG_Z = DX &= OPER_AY_IX_32(); + + FLAG_N = NFLAG_32(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_32_er_aw(void) +{ + FLAG_Z = DX &= OPER_AW_32(); + + FLAG_N = NFLAG_32(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_32_er_al(void) +{ + FLAG_Z = DX &= OPER_AL_32(); + + FLAG_N = NFLAG_32(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_32_er_pcdi(void) +{ + FLAG_Z = DX &= OPER_PCDI_32(); + + FLAG_N = NFLAG_32(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_32_er_pcix(void) +{ + FLAG_Z = DX &= OPER_PCIX_32(); + + FLAG_N = NFLAG_32(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_32_er_i(void) +{ + FLAG_Z = DX &= OPER_I_32(); + + FLAG_N = NFLAG_32(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_and_8_re_ai(void) +{ + uint ea = EA_AY_AI_8(); + uint res = DX & m68ki_read_8(ea); + + FLAG_N = NFLAG_8(res); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_and_8_re_pi(void) +{ + uint ea = EA_AY_PI_8(); + uint res = DX & m68ki_read_8(ea); + + FLAG_N = NFLAG_8(res); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_and_8_re_pi7(void) +{ + uint ea = EA_A7_PI_8(); + uint res = DX & m68ki_read_8(ea); + + FLAG_N = NFLAG_8(res); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_and_8_re_pd(void) +{ + uint ea = EA_AY_PD_8(); + uint res = DX & m68ki_read_8(ea); + + FLAG_N = NFLAG_8(res); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_and_8_re_pd7(void) +{ + uint ea = EA_A7_PD_8(); + uint res = DX & m68ki_read_8(ea); + + FLAG_N = NFLAG_8(res); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_and_8_re_di(void) +{ + uint ea = EA_AY_DI_8(); + uint res = DX & m68ki_read_8(ea); + + FLAG_N = NFLAG_8(res); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_and_8_re_ix(void) +{ + uint ea = EA_AY_IX_8(); + uint res = DX & m68ki_read_8(ea); + + FLAG_N = NFLAG_8(res); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_and_8_re_aw(void) +{ + uint ea = EA_AW_8(); + uint res = DX & m68ki_read_8(ea); + + FLAG_N = NFLAG_8(res); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_and_8_re_al(void) +{ + uint ea = EA_AL_8(); + uint res = DX & m68ki_read_8(ea); + + FLAG_N = NFLAG_8(res); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_and_16_re_ai(void) +{ + uint ea = EA_AY_AI_16(); + uint res = DX & m68ki_read_16(ea); + + FLAG_N = NFLAG_16(res); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_and_16_re_pi(void) +{ + uint ea = EA_AY_PI_16(); + uint res = DX & m68ki_read_16(ea); + + FLAG_N = NFLAG_16(res); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_and_16_re_pd(void) +{ + uint ea = EA_AY_PD_16(); + uint res = DX & m68ki_read_16(ea); + + FLAG_N = NFLAG_16(res); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_and_16_re_di(void) +{ + uint ea = EA_AY_DI_16(); + uint res = DX & m68ki_read_16(ea); + + FLAG_N = NFLAG_16(res); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_and_16_re_ix(void) +{ + uint ea = EA_AY_IX_16(); + uint res = DX & m68ki_read_16(ea); + + FLAG_N = NFLAG_16(res); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_and_16_re_aw(void) +{ + uint ea = EA_AW_16(); + uint res = DX & m68ki_read_16(ea); + + FLAG_N = NFLAG_16(res); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_and_16_re_al(void) +{ + uint ea = EA_AL_16(); + uint res = DX & m68ki_read_16(ea); + + FLAG_N = NFLAG_16(res); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_and_32_re_ai(void) +{ + uint ea = EA_AY_AI_32(); + uint res = DX & m68ki_read_32(ea); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_32(ea, res); +} + + +void m68k_op_and_32_re_pi(void) +{ + uint ea = EA_AY_PI_32(); + uint res = DX & m68ki_read_32(ea); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_32(ea, res); +} + + +void m68k_op_and_32_re_pd(void) +{ + uint ea = EA_AY_PD_32(); + uint res = DX & m68ki_read_32(ea); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_32(ea, res); +} + + +void m68k_op_and_32_re_di(void) +{ + uint ea = EA_AY_DI_32(); + uint res = DX & m68ki_read_32(ea); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_32(ea, res); +} + + +void m68k_op_and_32_re_ix(void) +{ + uint ea = EA_AY_IX_32(); + uint res = DX & m68ki_read_32(ea); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_32(ea, res); +} + + +void m68k_op_and_32_re_aw(void) +{ + uint ea = EA_AW_32(); + uint res = DX & m68ki_read_32(ea); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_32(ea, res); +} + + +void m68k_op_and_32_re_al(void) +{ + uint ea = EA_AL_32(); + uint res = DX & m68ki_read_32(ea); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_32(ea, res); +} + + +void m68k_op_andi_8_d(void) +{ + FLAG_Z = MASK_OUT_ABOVE_8(DY &= (OPER_I_8() | 0xffffff00)); + + FLAG_N = NFLAG_8(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_andi_8_ai(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_AI_8(); + uint res = src & m68ki_read_8(ea); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_8(ea, res); +} + + +void m68k_op_andi_8_pi(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_PI_8(); + uint res = src & m68ki_read_8(ea); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_8(ea, res); +} + + +void m68k_op_andi_8_pi7(void) +{ + uint src = OPER_I_8(); + uint ea = EA_A7_PI_8(); + uint res = src & m68ki_read_8(ea); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_8(ea, res); +} + + +void m68k_op_andi_8_pd(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_PD_8(); + uint res = src & m68ki_read_8(ea); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_8(ea, res); +} + + +void m68k_op_andi_8_pd7(void) +{ + uint src = OPER_I_8(); + uint ea = EA_A7_PD_8(); + uint res = src & m68ki_read_8(ea); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_8(ea, res); +} + + +void m68k_op_andi_8_di(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_DI_8(); + uint res = src & m68ki_read_8(ea); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_8(ea, res); +} + + +void m68k_op_andi_8_ix(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_IX_8(); + uint res = src & m68ki_read_8(ea); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_8(ea, res); +} + + +void m68k_op_andi_8_aw(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AW_8(); + uint res = src & m68ki_read_8(ea); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_8(ea, res); +} + + +void m68k_op_andi_8_al(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AL_8(); + uint res = src & m68ki_read_8(ea); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_8(ea, res); +} + + +void m68k_op_andi_16_d(void) +{ + FLAG_Z = MASK_OUT_ABOVE_16(DY &= (OPER_I_16() | 0xffff0000)); + + FLAG_N = NFLAG_16(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_andi_16_ai(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_AI_16(); + uint res = src & m68ki_read_16(ea); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_16(ea, res); +} + + +void m68k_op_andi_16_pi(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_PI_16(); + uint res = src & m68ki_read_16(ea); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_16(ea, res); +} + + +void m68k_op_andi_16_pd(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_PD_16(); + uint res = src & m68ki_read_16(ea); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_16(ea, res); +} + + +void m68k_op_andi_16_di(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_DI_16(); + uint res = src & m68ki_read_16(ea); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_16(ea, res); +} + + +void m68k_op_andi_16_ix(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_IX_16(); + uint res = src & m68ki_read_16(ea); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_16(ea, res); +} + + +void m68k_op_andi_16_aw(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AW_16(); + uint res = src & m68ki_read_16(ea); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_16(ea, res); +} + + +void m68k_op_andi_16_al(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AL_16(); + uint res = src & m68ki_read_16(ea); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_16(ea, res); +} + + +void m68k_op_andi_32_d(void) +{ + FLAG_Z = DY &= (OPER_I_32()); + + FLAG_N = NFLAG_32(FLAG_Z); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_andi_32_ai(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_AI_32(); + uint res = src & m68ki_read_32(ea); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_32(ea, res); +} + + +void m68k_op_andi_32_pi(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_PI_32(); + uint res = src & m68ki_read_32(ea); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_32(ea, res); +} + + +void m68k_op_andi_32_pd(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_PD_32(); + uint res = src & m68ki_read_32(ea); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_32(ea, res); +} + + +void m68k_op_andi_32_di(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_DI_32(); + uint res = src & m68ki_read_32(ea); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_32(ea, res); +} + + +void m68k_op_andi_32_ix(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_IX_32(); + uint res = src & m68ki_read_32(ea); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_32(ea, res); +} + + +void m68k_op_andi_32_aw(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AW_32(); + uint res = src & m68ki_read_32(ea); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_32(ea, res); +} + + +void m68k_op_andi_32_al(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AL_32(); + uint res = src & m68ki_read_32(ea); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + + m68ki_write_32(ea, res); +} + + +void m68k_op_andi_16_toc(void) +{ + m68ki_set_ccr(m68ki_get_ccr() & OPER_I_16()); +} + + +void m68k_op_andi_16_tos(void) +{ + if(FLAG_S) + { + uint src = OPER_I_16(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr(m68ki_get_sr() & src); + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_asr_8_s(void) +{ + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_8(*r_dst); + uint res = src >> shift; + + if(shift != 0) + USE_CYCLES(shift<> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_16(*r_dst); + uint res = src >> shift; + + if(shift != 0) + USE_CYCLES(shift<> 9) - 1) & 7) + 1; + uint src = *r_dst; + uint res = src >> shift; + + if(shift != 0) + USE_CYCLES(shift<> shift; + + if(shift != 0) + { + USE_CYCLES(shift<> shift; + + if(shift != 0) + { + USE_CYCLES(shift<> (shift - 1))<<8; + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + if(GET_MSB_16(src)) + { + *r_dst |= 0xffff; + FLAG_C = CFLAG_SET; + FLAG_X = XFLAG_SET; + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + return; + } + + *r_dst &= 0xffff0000; + FLAG_C = CFLAG_CLEAR; + FLAG_X = XFLAG_CLEAR; + FLAG_N = NFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_16(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_asr_32_r(void) +{ + uint* r_dst = &DY; + uint shift = DX & 0x3f; + uint src = *r_dst; + uint res = src >> shift; + + if(shift != 0) + { + USE_CYCLES(shift<> (shift - 1))<<8; + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + if(GET_MSB_32(src)) + { + *r_dst = 0xffffffff; + FLAG_C = CFLAG_SET; + FLAG_X = XFLAG_SET; + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + return; + } + + *r_dst = 0; + FLAG_C = CFLAG_CLEAR; + FLAG_X = XFLAG_CLEAR; + FLAG_N = NFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_32(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_asr_16_ai(void) +{ + uint ea = EA_AY_AI_16(); + uint src = m68ki_read_16(ea); + uint res = src >> 1; + + if(GET_MSB_16(src)) + res |= 0x8000; + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = FLAG_X = src << 8; +} + + +void m68k_op_asr_16_pi(void) +{ + uint ea = EA_AY_PI_16(); + uint src = m68ki_read_16(ea); + uint res = src >> 1; + + if(GET_MSB_16(src)) + res |= 0x8000; + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = FLAG_X = src << 8; +} + + +void m68k_op_asr_16_pd(void) +{ + uint ea = EA_AY_PD_16(); + uint src = m68ki_read_16(ea); + uint res = src >> 1; + + if(GET_MSB_16(src)) + res |= 0x8000; + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = FLAG_X = src << 8; +} + + +void m68k_op_asr_16_di(void) +{ + uint ea = EA_AY_DI_16(); + uint src = m68ki_read_16(ea); + uint res = src >> 1; + + if(GET_MSB_16(src)) + res |= 0x8000; + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = FLAG_X = src << 8; +} + + +void m68k_op_asr_16_ix(void) +{ + uint ea = EA_AY_IX_16(); + uint src = m68ki_read_16(ea); + uint res = src >> 1; + + if(GET_MSB_16(src)) + res |= 0x8000; + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = FLAG_X = src << 8; +} + + +void m68k_op_asr_16_aw(void) +{ + uint ea = EA_AW_16(); + uint src = m68ki_read_16(ea); + uint res = src >> 1; + + if(GET_MSB_16(src)) + res |= 0x8000; + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = FLAG_X = src << 8; +} + + +void m68k_op_asr_16_al(void) +{ + uint ea = EA_AL_16(); + uint src = m68ki_read_16(ea); + uint res = src >> 1; + + if(GET_MSB_16(src)) + res |= 0x8000; + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = FLAG_X = src << 8; +} + + +void m68k_op_asl_8_s(void) +{ + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_8(*r_dst); + uint res = MASK_OUT_ABOVE_8(src << shift); + + if(shift != 0) + USE_CYCLES(shift<> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_16(*r_dst); + uint res = MASK_OUT_ABOVE_16(src << shift); + + if(shift != 0) + USE_CYCLES(shift<> (8-shift); + src &= m68ki_shift_16_table[shift + 1]; + FLAG_V = (!(src == 0 || src == m68ki_shift_16_table[shift + 1]))<<7; +} + + +void m68k_op_asl_32_s(void) +{ + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint src = *r_dst; + uint res = MASK_OUT_ABOVE_32(src << shift); + + if(shift != 0) + USE_CYCLES(shift<> (24-shift); + src &= m68ki_shift_32_table[shift + 1]; + FLAG_V = (!(src == 0 || src == m68ki_shift_32_table[shift + 1]))<<7; +} + + +void m68k_op_asl_8_r(void) +{ + uint* r_dst = &DY; + uint shift = DX & 0x3f; + uint src = MASK_OUT_ABOVE_8(*r_dst); + uint res = MASK_OUT_ABOVE_8(src << shift); + + if(shift != 0) + { + USE_CYCLES(shift<> 8; + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + src &= m68ki_shift_16_table[shift + 1]; + FLAG_V = (!(src == 0 || src == m68ki_shift_16_table[shift + 1]))<<7; + return; + } + + *r_dst &= 0xffff0000; + FLAG_X = FLAG_C = ((shift == 16 ? src & 1 : 0))<<8; + FLAG_N = NFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; + FLAG_V = (!(src == 0))<<7; + return; + } + + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_16(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_asl_32_r(void) +{ + uint* r_dst = &DY; + uint shift = DX & 0x3f; + uint src = *r_dst; + uint res = MASK_OUT_ABOVE_32(src << shift); + + if(shift != 0) + { + USE_CYCLES(shift<> (32 - shift)) << 8; + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + src &= m68ki_shift_32_table[shift + 1]; + FLAG_V = (!(src == 0 || src == m68ki_shift_32_table[shift + 1]))<<7; + return; + } + + *r_dst = 0; + FLAG_X = FLAG_C = ((shift == 32 ? src & 1 : 0))<<8; + FLAG_N = NFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; + FLAG_V = (!(src == 0))<<7; + return; + } + + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_32(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_asl_16_ai(void) +{ + uint ea = EA_AY_AI_16(); + uint src = m68ki_read_16(ea); + uint res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_X = FLAG_C = src >> 7; + src &= 0xc000; + FLAG_V = (!(src == 0 || src == 0xc000))<<7; +} + + +void m68k_op_asl_16_pi(void) +{ + uint ea = EA_AY_PI_16(); + uint src = m68ki_read_16(ea); + uint res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_X = FLAG_C = src >> 7; + src &= 0xc000; + FLAG_V = (!(src == 0 || src == 0xc000))<<7; +} + + +void m68k_op_asl_16_pd(void) +{ + uint ea = EA_AY_PD_16(); + uint src = m68ki_read_16(ea); + uint res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_X = FLAG_C = src >> 7; + src &= 0xc000; + FLAG_V = (!(src == 0 || src == 0xc000))<<7; +} + + +void m68k_op_asl_16_di(void) +{ + uint ea = EA_AY_DI_16(); + uint src = m68ki_read_16(ea); + uint res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_X = FLAG_C = src >> 7; + src &= 0xc000; + FLAG_V = (!(src == 0 || src == 0xc000))<<7; +} + + +void m68k_op_asl_16_ix(void) +{ + uint ea = EA_AY_IX_16(); + uint src = m68ki_read_16(ea); + uint res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_X = FLAG_C = src >> 7; + src &= 0xc000; + FLAG_V = (!(src == 0 || src == 0xc000))<<7; +} + + +void m68k_op_asl_16_aw(void) +{ + uint ea = EA_AW_16(); + uint src = m68ki_read_16(ea); + uint res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_X = FLAG_C = src >> 7; + src &= 0xc000; + FLAG_V = (!(src == 0 || src == 0xc000))<<7; +} + + +void m68k_op_asl_16_al(void) +{ + uint ea = EA_AL_16(); + uint src = m68ki_read_16(ea); + uint res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_X = FLAG_C = src >> 7; + src &= 0xc000; + FLAG_V = (!(src == 0 || src == 0xc000))<<7; +} + + +void m68k_op_bhi_8(void) +{ + if(COND_HI()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); +} + + +void m68k_op_bls_8(void) +{ + if(COND_LS()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); +} + + +void m68k_op_bcc_8(void) +{ + if(COND_CC()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); +} + + +void m68k_op_bcs_8(void) +{ + if(COND_CS()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); +} + + +void m68k_op_bne_8(void) +{ + if(COND_NE()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); +} + + +void m68k_op_beq_8(void) +{ + if(COND_EQ()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); +} + + +void m68k_op_bvc_8(void) +{ + if(COND_VC()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); +} + + +void m68k_op_bvs_8(void) +{ + if(COND_VS()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); +} + + +void m68k_op_bpl_8(void) +{ + if(COND_PL()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); +} + + +void m68k_op_bmi_8(void) +{ + if(COND_MI()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); +} + + +void m68k_op_bge_8(void) +{ + if(COND_GE()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); +} + + +void m68k_op_blt_8(void) +{ + if(COND_LT()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); +} + + +void m68k_op_bgt_8(void) +{ + if(COND_GT()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); +} + + +void m68k_op_ble_8(void) +{ + if(COND_LE()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); +} + + +void m68k_op_bhi_16(void) +{ + if(COND_HI()) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_BCC_NOTAKE_W); +} + + +void m68k_op_bls_16(void) +{ + if(COND_LS()) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_BCC_NOTAKE_W); +} + + +void m68k_op_bcc_16(void) +{ + if(COND_CC()) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_BCC_NOTAKE_W); +} + + +void m68k_op_bcs_16(void) +{ + if(COND_CS()) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_BCC_NOTAKE_W); +} + + +void m68k_op_bne_16(void) +{ + if(COND_NE()) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_BCC_NOTAKE_W); +} + + +void m68k_op_beq_16(void) +{ + if(COND_EQ()) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_BCC_NOTAKE_W); +} + + +void m68k_op_bvc_16(void) +{ + if(COND_VC()) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_BCC_NOTAKE_W); +} + + +void m68k_op_bvs_16(void) +{ + if(COND_VS()) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_BCC_NOTAKE_W); +} + + +void m68k_op_bpl_16(void) +{ + if(COND_PL()) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_BCC_NOTAKE_W); +} + + +void m68k_op_bmi_16(void) +{ + if(COND_MI()) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_BCC_NOTAKE_W); +} + + +void m68k_op_bge_16(void) +{ + if(COND_GE()) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_BCC_NOTAKE_W); +} + + +void m68k_op_blt_16(void) +{ + if(COND_LT()) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_BCC_NOTAKE_W); +} + + +void m68k_op_bgt_16(void) +{ + if(COND_GT()) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_BCC_NOTAKE_W); +} + + +void m68k_op_ble_16(void) +{ + if(COND_LE()) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_BCC_NOTAKE_W); +} + + +void m68k_op_bhi_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_HI()) + { + uint offset = OPER_I_32(); + REG_PC -= 4; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32(offset); + return; + } + REG_PC += 4; + return; + } + else + { + if(COND_HI()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); + } +} + + +void m68k_op_bls_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_LS()) + { + uint offset = OPER_I_32(); + REG_PC -= 4; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32(offset); + return; + } + REG_PC += 4; + return; + } + else + { + if(COND_LS()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); + } +} + + +void m68k_op_bcc_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_CC()) + { + uint offset = OPER_I_32(); + REG_PC -= 4; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32(offset); + return; + } + REG_PC += 4; + return; + } + else + { + if(COND_CC()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); + } +} + + +void m68k_op_bcs_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_CS()) + { + uint offset = OPER_I_32(); + REG_PC -= 4; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32(offset); + return; + } + REG_PC += 4; + return; + } + else + { + if(COND_CS()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); + } +} + + +void m68k_op_bne_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_NE()) + { + uint offset = OPER_I_32(); + REG_PC -= 4; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32(offset); + return; + } + REG_PC += 4; + return; + } + else + { + if(COND_NE()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); + } +} + + +void m68k_op_beq_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_EQ()) + { + uint offset = OPER_I_32(); + REG_PC -= 4; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32(offset); + return; + } + REG_PC += 4; + return; + } + else + { + if(COND_EQ()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); + } +} + + +void m68k_op_bvc_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_VC()) + { + uint offset = OPER_I_32(); + REG_PC -= 4; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32(offset); + return; + } + REG_PC += 4; + return; + } + else + { + if(COND_VC()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); + } +} + + +void m68k_op_bvs_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_VS()) + { + uint offset = OPER_I_32(); + REG_PC -= 4; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32(offset); + return; + } + REG_PC += 4; + return; + } + else + { + if(COND_VS()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); + } +} + + +void m68k_op_bpl_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_PL()) + { + uint offset = OPER_I_32(); + REG_PC -= 4; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32(offset); + return; + } + REG_PC += 4; + return; + } + else + { + if(COND_PL()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); + } +} + + +void m68k_op_bmi_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_MI()) + { + uint offset = OPER_I_32(); + REG_PC -= 4; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32(offset); + return; + } + REG_PC += 4; + return; + } + else + { + if(COND_MI()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); + } +} + + +void m68k_op_bge_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_GE()) + { + uint offset = OPER_I_32(); + REG_PC -= 4; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32(offset); + return; + } + REG_PC += 4; + return; + } + else + { + if(COND_GE()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); + } +} + + +void m68k_op_blt_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_LT()) + { + uint offset = OPER_I_32(); + REG_PC -= 4; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32(offset); + return; + } + REG_PC += 4; + return; + } + else + { + if(COND_LT()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); + } +} + + +void m68k_op_bgt_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_GT()) + { + uint offset = OPER_I_32(); + REG_PC -= 4; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32(offset); + return; + } + REG_PC += 4; + return; + } + else + { + if(COND_GT()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); + } +} + + +void m68k_op_ble_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_LE()) + { + uint offset = OPER_I_32(); + REG_PC -= 4; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32(offset); + return; + } + REG_PC += 4; + return; + } + else + { + if(COND_LE()) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + return; + } + USE_CYCLES(CYC_BCC_NOTAKE_B); + } +} + + +void m68k_op_bchg_32_r_d(void) +{ + uint* r_dst = &DY; + uint mask = 1 << (DX & 0x1f); + + FLAG_Z = *r_dst & mask; + *r_dst ^= mask; +} + + +void m68k_op_bchg_8_r_ai(void) +{ + uint ea = EA_AY_AI_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src ^ mask); +} + + +void m68k_op_bchg_8_r_pi(void) +{ + uint ea = EA_AY_PI_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src ^ mask); +} + + +void m68k_op_bchg_8_r_pi7(void) +{ + uint ea = EA_A7_PI_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src ^ mask); +} + + +void m68k_op_bchg_8_r_pd(void) +{ + uint ea = EA_AY_PD_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src ^ mask); +} + + +void m68k_op_bchg_8_r_pd7(void) +{ + uint ea = EA_A7_PD_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src ^ mask); +} + + +void m68k_op_bchg_8_r_di(void) +{ + uint ea = EA_AY_DI_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src ^ mask); +} + + +void m68k_op_bchg_8_r_ix(void) +{ + uint ea = EA_AY_IX_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src ^ mask); +} + + +void m68k_op_bchg_8_r_aw(void) +{ + uint ea = EA_AW_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src ^ mask); +} + + +void m68k_op_bchg_8_r_al(void) +{ + uint ea = EA_AL_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src ^ mask); +} + + +void m68k_op_bchg_32_s_d(void) +{ + uint* r_dst = &DY; + uint mask = 1 << (OPER_I_8() & 0x1f); + + FLAG_Z = *r_dst & mask; + *r_dst ^= mask; +} + + +void m68k_op_bchg_8_s_ai(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_AY_AI_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src ^ mask); +} + + +void m68k_op_bchg_8_s_pi(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_AY_PI_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src ^ mask); +} + + +void m68k_op_bchg_8_s_pi7(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_A7_PI_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src ^ mask); +} + + +void m68k_op_bchg_8_s_pd(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_AY_PD_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src ^ mask); +} + + +void m68k_op_bchg_8_s_pd7(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_A7_PD_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src ^ mask); +} + + +void m68k_op_bchg_8_s_di(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_AY_DI_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src ^ mask); +} + + +void m68k_op_bchg_8_s_ix(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_AY_IX_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src ^ mask); +} + + +void m68k_op_bchg_8_s_aw(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_AW_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src ^ mask); +} + + +void m68k_op_bchg_8_s_al(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_AL_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src ^ mask); +} + + +void m68k_op_bclr_32_r_d(void) +{ + uint* r_dst = &DY; + uint mask = 1 << (DX & 0x1f); + + FLAG_Z = *r_dst & mask; + *r_dst &= ~mask; +} + + +void m68k_op_bclr_8_r_ai(void) +{ + uint ea = EA_AY_AI_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src & ~mask); +} + + +void m68k_op_bclr_8_r_pi(void) +{ + uint ea = EA_AY_PI_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src & ~mask); +} + + +void m68k_op_bclr_8_r_pi7(void) +{ + uint ea = EA_A7_PI_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src & ~mask); +} + + +void m68k_op_bclr_8_r_pd(void) +{ + uint ea = EA_AY_PD_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src & ~mask); +} + + +void m68k_op_bclr_8_r_pd7(void) +{ + uint ea = EA_A7_PD_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src & ~mask); +} + + +void m68k_op_bclr_8_r_di(void) +{ + uint ea = EA_AY_DI_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src & ~mask); +} + + +void m68k_op_bclr_8_r_ix(void) +{ + uint ea = EA_AY_IX_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src & ~mask); +} + + +void m68k_op_bclr_8_r_aw(void) +{ + uint ea = EA_AW_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src & ~mask); +} + + +void m68k_op_bclr_8_r_al(void) +{ + uint ea = EA_AL_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src & ~mask); +} + + +void m68k_op_bclr_32_s_d(void) +{ + uint* r_dst = &DY; + uint mask = 1 << (OPER_I_8() & 0x1f); + + FLAG_Z = *r_dst & mask; + *r_dst &= ~mask; +} + + +void m68k_op_bclr_8_s_ai(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_AY_AI_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src & ~mask); +} + + +void m68k_op_bclr_8_s_pi(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_AY_PI_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src & ~mask); +} + + +void m68k_op_bclr_8_s_pi7(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_A7_PI_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src & ~mask); +} + + +void m68k_op_bclr_8_s_pd(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_AY_PD_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src & ~mask); +} + + +void m68k_op_bclr_8_s_pd7(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_A7_PD_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src & ~mask); +} + + +void m68k_op_bclr_8_s_di(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_AY_DI_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src & ~mask); +} + + +void m68k_op_bclr_8_s_ix(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_AY_IX_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src & ~mask); +} + + +void m68k_op_bclr_8_s_aw(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_AW_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src & ~mask); +} + + +void m68k_op_bclr_8_s_al(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_AL_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src & ~mask); +} + + +void m68k_op_bfchg_32_d(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint offset = (word2>>6)&31; + uint width = word2; + uint* data = &DY; + uint64 mask; + + + if(BIT_B(word2)) + offset = REG_D[offset&7]; + if(BIT_5(word2)) + width = REG_D[width&7]; + + offset &= 31; + width = ((width-1) & 31) + 1; + + mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask = ROR_32(mask, offset); + + FLAG_N = NFLAG_32(*data<>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AY_AI_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = NFLAG_32(data_long << offset); + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + m68ki_write_32(ea, data_long ^ mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + m68ki_write_8(ea+4, data_byte ^ mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfchg_32_di(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AY_DI_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = NFLAG_32(data_long << offset); + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + m68ki_write_32(ea, data_long ^ mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + m68ki_write_8(ea+4, data_byte ^ mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfchg_32_ix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AY_IX_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = NFLAG_32(data_long << offset); + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + m68ki_write_32(ea, data_long ^ mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + m68ki_write_8(ea+4, data_byte ^ mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfchg_32_aw(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AW_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = NFLAG_32(data_long << offset); + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + m68ki_write_32(ea, data_long ^ mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + m68ki_write_8(ea+4, data_byte ^ mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfchg_32_al(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AL_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = NFLAG_32(data_long << offset); + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + m68ki_write_32(ea, data_long ^ mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + m68ki_write_8(ea+4, data_byte ^ mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfclr_32_d(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint offset = (word2>>6)&31; + uint width = word2; + uint* data = &DY; + uint64 mask; + + + if(BIT_B(word2)) + offset = REG_D[offset&7]; + if(BIT_5(word2)) + width = REG_D[width&7]; + + + offset &= 31; + width = ((width-1) & 31) + 1; + + + mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask = ROR_32(mask, offset); + + FLAG_N = NFLAG_32(*data<>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AY_AI_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = NFLAG_32(data_long << offset); + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + m68ki_write_32(ea, data_long & ~mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + m68ki_write_8(ea+4, data_byte & ~mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfclr_32_di(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AY_DI_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = NFLAG_32(data_long << offset); + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + m68ki_write_32(ea, data_long & ~mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + m68ki_write_8(ea+4, data_byte & ~mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfclr_32_ix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AY_IX_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = NFLAG_32(data_long << offset); + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + m68ki_write_32(ea, data_long & ~mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + m68ki_write_8(ea+4, data_byte & ~mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfclr_32_aw(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AW_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = NFLAG_32(data_long << offset); + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + m68ki_write_32(ea, data_long & ~mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + m68ki_write_8(ea+4, data_byte & ~mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfclr_32_al(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AL_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = NFLAG_32(data_long << offset); + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + m68ki_write_32(ea, data_long & ~mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + m68ki_write_8(ea+4, data_byte & ~mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfexts_32_d(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint offset = (word2>>6)&31; + uint width = word2; + uint64 data = DY; + + + if(BIT_B(word2)) + offset = REG_D[offset&7]; + if(BIT_5(word2)) + width = REG_D[width&7]; + + offset &= 31; + width = ((width-1) & 31) + 1; + + data = ROL_32(data, offset); + FLAG_N = NFLAG_32(data); + data = MAKE_INT_32(data) >> (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + REG_D[(word2>>12)&7] = data; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfexts_32_ai(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint data; + uint ea = EA_AY_AI_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = m68ki_read_32(ea); + + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8(ea+4) << offset) >> 8; + + FLAG_N = NFLAG_32(data); + data = MAKE_INT_32(data) >> (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + REG_D[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfexts_32_di(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint data; + uint ea = EA_AY_DI_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = m68ki_read_32(ea); + + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8(ea+4) << offset) >> 8; + + FLAG_N = NFLAG_32(data); + data = MAKE_INT_32(data) >> (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + REG_D[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfexts_32_ix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint data; + uint ea = EA_AY_IX_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = m68ki_read_32(ea); + + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8(ea+4) << offset) >> 8; + + FLAG_N = NFLAG_32(data); + data = MAKE_INT_32(data) >> (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + REG_D[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfexts_32_aw(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint data; + uint ea = EA_AW_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = m68ki_read_32(ea); + + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8(ea+4) << offset) >> 8; + + FLAG_N = NFLAG_32(data); + data = MAKE_INT_32(data) >> (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + REG_D[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfexts_32_al(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint data; + uint ea = EA_AL_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = m68ki_read_32(ea); + + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8(ea+4) << offset) >> 8; + + FLAG_N = NFLAG_32(data); + data = MAKE_INT_32(data) >> (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + REG_D[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfexts_32_pcdi(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint data; + uint ea = EA_PCDI_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = m68ki_read_32(ea); + + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8(ea+4) << offset) >> 8; + + FLAG_N = NFLAG_32(data); + data = MAKE_INT_32(data) >> (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + REG_D[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfexts_32_pcix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint data; + uint ea = EA_PCIX_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = m68ki_read_32(ea); + + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8(ea+4) << offset) >> 8; + + FLAG_N = NFLAG_32(data); + data = MAKE_INT_32(data) >> (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + REG_D[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfextu_32_d(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint offset = (word2>>6)&31; + uint width = word2; + uint64 data = DY; + + + if(BIT_B(word2)) + offset = REG_D[offset&7]; + if(BIT_5(word2)) + width = REG_D[width&7]; + + offset &= 31; + width = ((width-1) & 31) + 1; + + data = ROL_32(data, offset); + FLAG_N = NFLAG_32(data); + data >>= 32 - width; + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + REG_D[(word2>>12)&7] = data; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfextu_32_ai(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint data; + uint ea = EA_AY_AI_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = m68ki_read_32(ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8(ea+4) << offset) >> 8; + + FLAG_N = NFLAG_32(data); + data >>= (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + REG_D[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfextu_32_di(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint data; + uint ea = EA_AY_DI_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = m68ki_read_32(ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8(ea+4) << offset) >> 8; + + FLAG_N = NFLAG_32(data); + data >>= (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + REG_D[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfextu_32_ix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint data; + uint ea = EA_AY_IX_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = m68ki_read_32(ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8(ea+4) << offset) >> 8; + + FLAG_N = NFLAG_32(data); + data >>= (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + REG_D[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfextu_32_aw(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint data; + uint ea = EA_AW_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = m68ki_read_32(ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8(ea+4) << offset) >> 8; + + FLAG_N = NFLAG_32(data); + data >>= (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + REG_D[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfextu_32_al(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint data; + uint ea = EA_AL_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = m68ki_read_32(ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8(ea+4) << offset) >> 8; + + FLAG_N = NFLAG_32(data); + data >>= (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + REG_D[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfextu_32_pcdi(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint data; + uint ea = EA_PCDI_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = m68ki_read_32(ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8(ea+4) << offset) >> 8; + + FLAG_N = NFLAG_32(data); + data >>= (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + REG_D[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfextu_32_pcix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint data; + uint ea = EA_PCIX_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = m68ki_read_32(ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8(ea+4) << offset) >> 8; + + FLAG_N = NFLAG_32(data); + data >>= (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + REG_D[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfffo_32_d(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint offset = (word2>>6)&31; + uint width = word2; + uint64 data = DY; + uint bit; + + + if(BIT_B(word2)) + offset = REG_D[offset&7]; + if(BIT_5(word2)) + width = REG_D[width&7]; + + offset &= 31; + width = ((width-1) & 31) + 1; + + data = ROL_32(data, offset); + FLAG_N = NFLAG_32(data); + data >>= 32 - width; + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + for(bit = 1<<(width-1);bit && !(data & bit);bit>>= 1) + offset++; + + REG_D[(word2>>12)&7] = offset; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfffo_32_ai(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + sint local_offset; + uint width = word2; + uint data; + uint bit; + uint ea = EA_AY_AI_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + local_offset = offset % 8; + if(local_offset < 0) + { + local_offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = m68ki_read_32(ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8(ea+4) << local_offset) >> 8; + + FLAG_N = NFLAG_32(data); + data >>= (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + for(bit = 1<<(width-1);bit && !(data & bit);bit>>= 1) + offset++; + + REG_D[(word2>>12)&7] = offset; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfffo_32_di(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + sint local_offset; + uint width = word2; + uint data; + uint bit; + uint ea = EA_AY_DI_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + local_offset = offset % 8; + if(local_offset < 0) + { + local_offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = m68ki_read_32(ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8(ea+4) << local_offset) >> 8; + + FLAG_N = NFLAG_32(data); + data >>= (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + for(bit = 1<<(width-1);bit && !(data & bit);bit>>= 1) + offset++; + + REG_D[(word2>>12)&7] = offset; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfffo_32_ix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + sint local_offset; + uint width = word2; + uint data; + uint bit; + uint ea = EA_AY_IX_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + local_offset = offset % 8; + if(local_offset < 0) + { + local_offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = m68ki_read_32(ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8(ea+4) << local_offset) >> 8; + + FLAG_N = NFLAG_32(data); + data >>= (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + for(bit = 1<<(width-1);bit && !(data & bit);bit>>= 1) + offset++; + + REG_D[(word2>>12)&7] = offset; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfffo_32_aw(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + sint local_offset; + uint width = word2; + uint data; + uint bit; + uint ea = EA_AW_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + local_offset = offset % 8; + if(local_offset < 0) + { + local_offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = m68ki_read_32(ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8(ea+4) << local_offset) >> 8; + + FLAG_N = NFLAG_32(data); + data >>= (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + for(bit = 1<<(width-1);bit && !(data & bit);bit>>= 1) + offset++; + + REG_D[(word2>>12)&7] = offset; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfffo_32_al(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + sint local_offset; + uint width = word2; + uint data; + uint bit; + uint ea = EA_AL_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + local_offset = offset % 8; + if(local_offset < 0) + { + local_offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = m68ki_read_32(ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8(ea+4) << local_offset) >> 8; + + FLAG_N = NFLAG_32(data); + data >>= (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + for(bit = 1<<(width-1);bit && !(data & bit);bit>>= 1) + offset++; + + REG_D[(word2>>12)&7] = offset; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfffo_32_pcdi(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + sint local_offset; + uint width = word2; + uint data; + uint bit; + uint ea = EA_PCDI_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + local_offset = offset % 8; + if(local_offset < 0) + { + local_offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = m68ki_read_32(ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8(ea+4) << local_offset) >> 8; + + FLAG_N = NFLAG_32(data); + data >>= (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + for(bit = 1<<(width-1);bit && !(data & bit);bit>>= 1) + offset++; + + REG_D[(word2>>12)&7] = offset; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfffo_32_pcix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + sint local_offset; + uint width = word2; + uint data; + uint bit; + uint ea = EA_PCIX_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + local_offset = offset % 8; + if(local_offset < 0) + { + local_offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = m68ki_read_32(ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8(ea+4) << local_offset) >> 8; + + FLAG_N = NFLAG_32(data); + data >>= (32 - width); + + FLAG_Z = data; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + for(bit = 1<<(width-1);bit && !(data & bit);bit>>= 1) + offset++; + + REG_D[(word2>>12)&7] = offset; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfins_32_d(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint offset = (word2>>6)&31; + uint width = word2; + uint* data = &DY; + uint64 mask; + uint64 insert = REG_D[(word2>>12)&7]; + + + if(BIT_B(word2)) + offset = REG_D[offset&7]; + if(BIT_5(word2)) + width = REG_D[width&7]; + + + offset &= 31; + width = ((width-1) & 31) + 1; + + + mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask = ROR_32(mask, offset); + + insert = MASK_OUT_ABOVE_32(insert << (32 - width)); + FLAG_N = NFLAG_32(insert); + FLAG_Z = insert; + insert = ROR_32(insert, offset); + + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + *data &= ~mask; + *data |= insert; + + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfins_32_ai(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint insert_base = REG_D[(word2>>12)&7]; + uint insert_long; + uint insert_byte; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AY_AI_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + insert_base = MASK_OUT_ABOVE_32(insert_base << (32 - width)); + FLAG_N = NFLAG_32(insert_base); + FLAG_Z = insert_base; + insert_long = insert_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + m68ki_write_32(ea, (data_long & ~mask_long) | insert_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + insert_byte = MASK_OUT_ABOVE_8(insert_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + m68ki_write_8(ea+4, (data_byte & ~mask_byte) | insert_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfins_32_di(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint insert_base = REG_D[(word2>>12)&7]; + uint insert_long; + uint insert_byte; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AY_DI_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + insert_base = MASK_OUT_ABOVE_32(insert_base << (32 - width)); + FLAG_N = NFLAG_32(insert_base); + FLAG_Z = insert_base; + insert_long = insert_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + m68ki_write_32(ea, (data_long & ~mask_long) | insert_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + insert_byte = MASK_OUT_ABOVE_8(insert_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + m68ki_write_8(ea+4, (data_byte & ~mask_byte) | insert_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfins_32_ix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint insert_base = REG_D[(word2>>12)&7]; + uint insert_long; + uint insert_byte; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AY_IX_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + insert_base = MASK_OUT_ABOVE_32(insert_base << (32 - width)); + FLAG_N = NFLAG_32(insert_base); + FLAG_Z = insert_base; + insert_long = insert_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + m68ki_write_32(ea, (data_long & ~mask_long) | insert_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + insert_byte = MASK_OUT_ABOVE_8(insert_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + m68ki_write_8(ea+4, (data_byte & ~mask_byte) | insert_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfins_32_aw(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint insert_base = REG_D[(word2>>12)&7]; + uint insert_long; + uint insert_byte; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AW_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + insert_base = MASK_OUT_ABOVE_32(insert_base << (32 - width)); + FLAG_N = NFLAG_32(insert_base); + FLAG_Z = insert_base; + insert_long = insert_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + m68ki_write_32(ea, (data_long & ~mask_long) | insert_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + insert_byte = MASK_OUT_ABOVE_8(insert_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + m68ki_write_8(ea+4, (data_byte & ~mask_byte) | insert_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfins_32_al(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint insert_base = REG_D[(word2>>12)&7]; + uint insert_long; + uint insert_byte; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AL_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + insert_base = MASK_OUT_ABOVE_32(insert_base << (32 - width)); + FLAG_N = NFLAG_32(insert_base); + FLAG_Z = insert_base; + insert_long = insert_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + m68ki_write_32(ea, (data_long & ~mask_long) | insert_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + insert_byte = MASK_OUT_ABOVE_8(insert_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + m68ki_write_8(ea+4, (data_byte & ~mask_byte) | insert_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfset_32_d(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint offset = (word2>>6)&31; + uint width = word2; + uint* data = &DY; + uint64 mask; + + + if(BIT_B(word2)) + offset = REG_D[offset&7]; + if(BIT_5(word2)) + width = REG_D[width&7]; + + + offset &= 31; + width = ((width-1) & 31) + 1; + + + mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask = ROR_32(mask, offset); + + FLAG_N = NFLAG_32(*data<>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AY_AI_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = NFLAG_32(data_long << offset); + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + m68ki_write_32(ea, data_long | mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + m68ki_write_8(ea+4, data_byte | mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfset_32_di(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AY_DI_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = NFLAG_32(data_long << offset); + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + m68ki_write_32(ea, data_long | mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + m68ki_write_8(ea+4, data_byte | mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfset_32_ix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AY_IX_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = NFLAG_32(data_long << offset); + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + m68ki_write_32(ea, data_long | mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + m68ki_write_8(ea+4, data_byte | mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfset_32_aw(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AW_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = NFLAG_32(data_long << offset); + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + m68ki_write_32(ea, data_long | mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + m68ki_write_8(ea+4, data_byte | mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bfset_32_al(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AL_8(); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = NFLAG_32(data_long << offset); + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + m68ki_write_32(ea, data_long | mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + m68ki_write_8(ea+4, data_byte | mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bftst_32_d(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint offset = (word2>>6)&31; + uint width = word2; + uint* data = &DY; + uint64 mask; + + + if(BIT_B(word2)) + offset = REG_D[offset&7]; + if(BIT_5(word2)) + width = REG_D[width&7]; + + + offset &= 31; + width = ((width-1) & 31) + 1; + + + mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask = ROR_32(mask, offset); + + FLAG_N = NFLAG_32(*data<>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AY_AI_8(); + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = ((data_long & (0x80000000 >> offset))<>24; + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bftst_32_di(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AY_DI_8(); + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = ((data_long & (0x80000000 >> offset))<>24; + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bftst_32_ix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AY_IX_8(); + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = ((data_long & (0x80000000 >> offset))<>24; + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bftst_32_aw(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AW_8(); + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = ((data_long & (0x80000000 >> offset))<>24; + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bftst_32_al(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_AL_8(); + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = ((data_long & (0x80000000 >> offset))<>24; + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bftst_32_pcdi(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_PCDI_8(); + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = ((data_long & (0x80000000 >> offset))<>24; + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bftst_32_pcix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + sint offset = (word2>>6)&31; + uint width = word2; + uint mask_base; + uint data_long; + uint mask_long; + uint data_byte = 0; + uint mask_byte = 0; + uint ea = EA_PCIX_8(); + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D[offset&7]); + if(BIT_5(word2)) + width = REG_D[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32(ea); + FLAG_N = ((data_long & (0x80000000 >> offset))<>24; + FLAG_Z = data_long & mask_long; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8(ea+4); + FLAG_Z |= (data_byte & mask_byte); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_bkpt(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + m68ki_bkpt_ack(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE) ? REG_IR & 7 : 0); /* auto-disable (see m68kcpu.h) */ + } + m68ki_exception_illegal(); +} + + +void m68k_op_bra_8(void) +{ + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); +// if(REG_PC == REG_PPC) +// USE_ALL_CYCLES(); +} + + +void m68k_op_bra_16(void) +{ + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); +// if(REG_PC == REG_PPC) +// USE_ALL_CYCLES(); +} + + +void m68k_op_bra_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint offset = OPER_I_32(); + REG_PC -= 4; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32(offset); + if(REG_PC == REG_PPC) + USE_ALL_CYCLES(); + return; + } + else + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); +// if(REG_PC == REG_PPC) +// USE_ALL_CYCLES(); + } +} + + +void m68k_op_bset_32_r_d(void) +{ + uint* r_dst = &DY; + uint mask = 1 << (DX & 0x1f); + + FLAG_Z = *r_dst & mask; + *r_dst |= mask; +} + + +void m68k_op_bset_8_r_ai(void) +{ + uint ea = EA_AY_AI_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src | mask); +} + + +void m68k_op_bset_8_r_pi(void) +{ + uint ea = EA_AY_PI_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src | mask); +} + + +void m68k_op_bset_8_r_pi7(void) +{ + uint ea = EA_A7_PI_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src | mask); +} + + +void m68k_op_bset_8_r_pd(void) +{ + uint ea = EA_AY_PD_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src | mask); +} + + +void m68k_op_bset_8_r_pd7(void) +{ + uint ea = EA_A7_PD_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src | mask); +} + + +void m68k_op_bset_8_r_di(void) +{ + uint ea = EA_AY_DI_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src | mask); +} + + +void m68k_op_bset_8_r_ix(void) +{ + uint ea = EA_AY_IX_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src | mask); +} + + +void m68k_op_bset_8_r_aw(void) +{ + uint ea = EA_AW_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src | mask); +} + + +void m68k_op_bset_8_r_al(void) +{ + uint ea = EA_AL_8(); + uint src = m68ki_read_8(ea); + uint mask = 1 << (DX & 7); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src | mask); +} + + +void m68k_op_bset_32_s_d(void) +{ + uint* r_dst = &DY; + uint mask = 1 << (OPER_I_8() & 0x1f); + + FLAG_Z = *r_dst & mask; + *r_dst |= mask; +} + + +void m68k_op_bset_8_s_ai(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_AY_AI_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src | mask); +} + + +void m68k_op_bset_8_s_pi(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_AY_PI_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src | mask); +} + + +void m68k_op_bset_8_s_pi7(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_A7_PI_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src | mask); +} + + +void m68k_op_bset_8_s_pd(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_AY_PD_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src | mask); +} + + +void m68k_op_bset_8_s_pd7(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_A7_PD_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src | mask); +} + + +void m68k_op_bset_8_s_di(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_AY_DI_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src | mask); +} + + +void m68k_op_bset_8_s_ix(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_AY_IX_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src | mask); +} + + +void m68k_op_bset_8_s_aw(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_AW_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src | mask); +} + + +void m68k_op_bset_8_s_al(void) +{ + uint mask = 1 << (OPER_I_8() & 7); + uint ea = EA_AL_8(); + uint src = m68ki_read_8(ea); + + FLAG_Z = src & mask; + m68ki_write_8(ea, src | mask); +} + + +void m68k_op_bsr_8(void) +{ + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32(REG_PC); + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); +} + + +void m68k_op_bsr_16(void) +{ + uint offset = OPER_I_16(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32(REG_PC); + REG_PC -= 2; + m68ki_branch_16(offset); +} + + +void m68k_op_bsr_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint offset = OPER_I_32(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32(REG_PC); + REG_PC -= 4; + m68ki_branch_32(offset); + return; + } + else + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32(REG_PC); + m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); + } +} + + +void m68k_op_btst_32_r_d(void) +{ + FLAG_Z = DY & (1 << (DX & 0x1f)); +} + + +void m68k_op_btst_8_r_ai(void) +{ + FLAG_Z = OPER_AY_AI_8() & (1 << (DX & 7)); +} + + +void m68k_op_btst_8_r_pi(void) +{ + FLAG_Z = OPER_AY_PI_8() & (1 << (DX & 7)); +} + + +void m68k_op_btst_8_r_pi7(void) +{ + FLAG_Z = OPER_A7_PI_8() & (1 << (DX & 7)); +} + + +void m68k_op_btst_8_r_pd(void) +{ + FLAG_Z = OPER_AY_PD_8() & (1 << (DX & 7)); +} + + +void m68k_op_btst_8_r_pd7(void) +{ + FLAG_Z = OPER_A7_PD_8() & (1 << (DX & 7)); +} + + +void m68k_op_btst_8_r_di(void) +{ + FLAG_Z = OPER_AY_DI_8() & (1 << (DX & 7)); +} + + +void m68k_op_btst_8_r_ix(void) +{ + FLAG_Z = OPER_AY_IX_8() & (1 << (DX & 7)); +} + + +void m68k_op_btst_8_r_aw(void) +{ + FLAG_Z = OPER_AW_8() & (1 << (DX & 7)); +} + + +void m68k_op_btst_8_r_al(void) +{ + FLAG_Z = OPER_AL_8() & (1 << (DX & 7)); +} + + +void m68k_op_btst_8_r_pcdi(void) +{ + FLAG_Z = OPER_PCDI_8() & (1 << (DX & 7)); +} + + +void m68k_op_btst_8_r_pcix(void) +{ + FLAG_Z = OPER_PCIX_8() & (1 << (DX & 7)); +} + + +void m68k_op_btst_8_r_i(void) +{ + FLAG_Z = OPER_I_8() & (1 << (DX & 7)); +} + + +void m68k_op_btst_32_s_d(void) +{ + FLAG_Z = DY & (1 << (OPER_I_8() & 0x1f)); +} + + +void m68k_op_btst_8_s_ai(void) +{ + uint bit = OPER_I_8() & 7; + + FLAG_Z = OPER_AY_AI_8() & (1 << bit); +} + + +void m68k_op_btst_8_s_pi(void) +{ + uint bit = OPER_I_8() & 7; + + FLAG_Z = OPER_AY_PI_8() & (1 << bit); +} + + +void m68k_op_btst_8_s_pi7(void) +{ + uint bit = OPER_I_8() & 7; + + FLAG_Z = OPER_A7_PI_8() & (1 << bit); +} + + +void m68k_op_btst_8_s_pd(void) +{ + uint bit = OPER_I_8() & 7; + + FLAG_Z = OPER_AY_PD_8() & (1 << bit); +} + + +void m68k_op_btst_8_s_pd7(void) +{ + uint bit = OPER_I_8() & 7; + + FLAG_Z = OPER_A7_PD_8() & (1 << bit); +} + + +void m68k_op_btst_8_s_di(void) +{ + uint bit = OPER_I_8() & 7; + + FLAG_Z = OPER_AY_DI_8() & (1 << bit); +} + + +void m68k_op_btst_8_s_ix(void) +{ + uint bit = OPER_I_8() & 7; + + FLAG_Z = OPER_AY_IX_8() & (1 << bit); +} + + +void m68k_op_btst_8_s_aw(void) +{ + uint bit = OPER_I_8() & 7; + + FLAG_Z = OPER_AW_8() & (1 << bit); +} + + +void m68k_op_btst_8_s_al(void) +{ + uint bit = OPER_I_8() & 7; + + FLAG_Z = OPER_AL_8() & (1 << bit); +} + + +void m68k_op_btst_8_s_pcdi(void) +{ + uint bit = OPER_I_8() & 7; + + FLAG_Z = OPER_PCDI_8() & (1 << bit); +} + + +void m68k_op_btst_8_s_pcix(void) +{ + uint bit = OPER_I_8() & 7; + + FLAG_Z = OPER_PCIX_8() & (1 << bit); +} + + +void m68k_op_callm_32_ai(void) +{ + /* note: watch out for pcrelative modes */ + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + { + uint ea = EA_AY_AI_32(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + REG_PC += 2; +(void)ea; /* just to avoid an 'unused variable' warning */ + M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", + m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, + m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_callm_32_di(void) +{ + /* note: watch out for pcrelative modes */ + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + { + uint ea = EA_AY_DI_32(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + REG_PC += 2; +(void)ea; /* just to avoid an 'unused variable' warning */ + M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", + m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, + m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_callm_32_ix(void) +{ + /* note: watch out for pcrelative modes */ + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + { + uint ea = EA_AY_IX_32(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + REG_PC += 2; +(void)ea; /* just to avoid an 'unused variable' warning */ + M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", + m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, + m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_callm_32_aw(void) +{ + /* note: watch out for pcrelative modes */ + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + { + uint ea = EA_AW_32(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + REG_PC += 2; +(void)ea; /* just to avoid an 'unused variable' warning */ + M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", + m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, + m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_callm_32_al(void) +{ + /* note: watch out for pcrelative modes */ + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + { + uint ea = EA_AL_32(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + REG_PC += 2; +(void)ea; /* just to avoid an 'unused variable' warning */ + M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", + m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, + m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_callm_32_pcdi(void) +{ + /* note: watch out for pcrelative modes */ + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + { + uint ea = EA_PCDI_32(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + REG_PC += 2; +(void)ea; /* just to avoid an 'unused variable' warning */ + M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", + m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, + m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_callm_32_pcix(void) +{ + /* note: watch out for pcrelative modes */ + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + { + uint ea = EA_PCIX_32(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + REG_PC += 2; +(void)ea; /* just to avoid an 'unused variable' warning */ + M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", + m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, + m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas_8_ai(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_AI_8(); + uint dest = m68ki_read_8(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - MASK_OUT_ABOVE_8(*compare); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(*compare, dest, res); + FLAG_C = CFLAG_8(res); + + if(COND_NE()) + *compare = MASK_OUT_BELOW_8(*compare) | dest; + else + { + USE_CYCLES(3); + m68ki_write_8(ea, MASK_OUT_ABOVE_8(REG_D[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas_8_pi(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_PI_8(); + uint dest = m68ki_read_8(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - MASK_OUT_ABOVE_8(*compare); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(*compare, dest, res); + FLAG_C = CFLAG_8(res); + + if(COND_NE()) + *compare = MASK_OUT_BELOW_8(*compare) | dest; + else + { + USE_CYCLES(3); + m68ki_write_8(ea, MASK_OUT_ABOVE_8(REG_D[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas_8_pi7(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = EA_A7_PI_8(); + uint dest = m68ki_read_8(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - MASK_OUT_ABOVE_8(*compare); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(*compare, dest, res); + FLAG_C = CFLAG_8(res); + + if(COND_NE()) + *compare = MASK_OUT_BELOW_8(*compare) | dest; + else + { + USE_CYCLES(3); + m68ki_write_8(ea, MASK_OUT_ABOVE_8(REG_D[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas_8_pd(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_PD_8(); + uint dest = m68ki_read_8(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - MASK_OUT_ABOVE_8(*compare); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(*compare, dest, res); + FLAG_C = CFLAG_8(res); + + if(COND_NE()) + *compare = MASK_OUT_BELOW_8(*compare) | dest; + else + { + USE_CYCLES(3); + m68ki_write_8(ea, MASK_OUT_ABOVE_8(REG_D[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas_8_pd7(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = EA_A7_PD_8(); + uint dest = m68ki_read_8(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - MASK_OUT_ABOVE_8(*compare); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(*compare, dest, res); + FLAG_C = CFLAG_8(res); + + if(COND_NE()) + *compare = MASK_OUT_BELOW_8(*compare) | dest; + else + { + USE_CYCLES(3); + m68ki_write_8(ea, MASK_OUT_ABOVE_8(REG_D[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas_8_di(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_DI_8(); + uint dest = m68ki_read_8(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - MASK_OUT_ABOVE_8(*compare); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(*compare, dest, res); + FLAG_C = CFLAG_8(res); + + if(COND_NE()) + *compare = MASK_OUT_BELOW_8(*compare) | dest; + else + { + USE_CYCLES(3); + m68ki_write_8(ea, MASK_OUT_ABOVE_8(REG_D[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas_8_ix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_IX_8(); + uint dest = m68ki_read_8(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - MASK_OUT_ABOVE_8(*compare); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(*compare, dest, res); + FLAG_C = CFLAG_8(res); + + if(COND_NE()) + *compare = MASK_OUT_BELOW_8(*compare) | dest; + else + { + USE_CYCLES(3); + m68ki_write_8(ea, MASK_OUT_ABOVE_8(REG_D[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas_8_aw(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = EA_AW_8(); + uint dest = m68ki_read_8(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - MASK_OUT_ABOVE_8(*compare); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(*compare, dest, res); + FLAG_C = CFLAG_8(res); + + if(COND_NE()) + *compare = MASK_OUT_BELOW_8(*compare) | dest; + else + { + USE_CYCLES(3); + m68ki_write_8(ea, MASK_OUT_ABOVE_8(REG_D[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas_8_al(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = EA_AL_8(); + uint dest = m68ki_read_8(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - MASK_OUT_ABOVE_8(*compare); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(*compare, dest, res); + FLAG_C = CFLAG_8(res); + + if(COND_NE()) + *compare = MASK_OUT_BELOW_8(*compare) | dest; + else + { + USE_CYCLES(3); + m68ki_write_8(ea, MASK_OUT_ABOVE_8(REG_D[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas_16_ai(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_AI_16(); + uint dest = m68ki_read_16(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - MASK_OUT_ABOVE_16(*compare); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(*compare, dest, res); + FLAG_C = CFLAG_16(res); + + if(COND_NE()) + *compare = MASK_OUT_BELOW_16(*compare) | dest; + else + { + USE_CYCLES(3); + m68ki_write_16(ea, MASK_OUT_ABOVE_16(REG_D[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas_16_pi(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_PI_16(); + uint dest = m68ki_read_16(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - MASK_OUT_ABOVE_16(*compare); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(*compare, dest, res); + FLAG_C = CFLAG_16(res); + + if(COND_NE()) + *compare = MASK_OUT_BELOW_16(*compare) | dest; + else + { + USE_CYCLES(3); + m68ki_write_16(ea, MASK_OUT_ABOVE_16(REG_D[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas_16_pd(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_PD_16(); + uint dest = m68ki_read_16(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - MASK_OUT_ABOVE_16(*compare); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(*compare, dest, res); + FLAG_C = CFLAG_16(res); + + if(COND_NE()) + *compare = MASK_OUT_BELOW_16(*compare) | dest; + else + { + USE_CYCLES(3); + m68ki_write_16(ea, MASK_OUT_ABOVE_16(REG_D[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas_16_di(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_DI_16(); + uint dest = m68ki_read_16(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - MASK_OUT_ABOVE_16(*compare); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(*compare, dest, res); + FLAG_C = CFLAG_16(res); + + if(COND_NE()) + *compare = MASK_OUT_BELOW_16(*compare) | dest; + else + { + USE_CYCLES(3); + m68ki_write_16(ea, MASK_OUT_ABOVE_16(REG_D[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas_16_ix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_IX_16(); + uint dest = m68ki_read_16(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - MASK_OUT_ABOVE_16(*compare); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(*compare, dest, res); + FLAG_C = CFLAG_16(res); + + if(COND_NE()) + *compare = MASK_OUT_BELOW_16(*compare) | dest; + else + { + USE_CYCLES(3); + m68ki_write_16(ea, MASK_OUT_ABOVE_16(REG_D[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas_16_aw(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = EA_AW_16(); + uint dest = m68ki_read_16(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - MASK_OUT_ABOVE_16(*compare); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(*compare, dest, res); + FLAG_C = CFLAG_16(res); + + if(COND_NE()) + *compare = MASK_OUT_BELOW_16(*compare) | dest; + else + { + USE_CYCLES(3); + m68ki_write_16(ea, MASK_OUT_ABOVE_16(REG_D[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas_16_al(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = EA_AL_16(); + uint dest = m68ki_read_16(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - MASK_OUT_ABOVE_16(*compare); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(*compare, dest, res); + FLAG_C = CFLAG_16(res); + + if(COND_NE()) + *compare = MASK_OUT_BELOW_16(*compare) | dest; + else + { + USE_CYCLES(3); + m68ki_write_16(ea, MASK_OUT_ABOVE_16(REG_D[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas_32_ai(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_AI_32(); + uint dest = m68ki_read_32(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - *compare; + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(*compare, dest, res); + FLAG_C = CFLAG_SUB_32(*compare, dest, res); + + if(COND_NE()) + *compare = dest; + else + { + USE_CYCLES(3); + m68ki_write_32(ea, REG_D[(word2 >> 6) & 7]); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas_32_pi(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_PI_32(); + uint dest = m68ki_read_32(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - *compare; + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(*compare, dest, res); + FLAG_C = CFLAG_SUB_32(*compare, dest, res); + + if(COND_NE()) + *compare = dest; + else + { + USE_CYCLES(3); + m68ki_write_32(ea, REG_D[(word2 >> 6) & 7]); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas_32_pd(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_PD_32(); + uint dest = m68ki_read_32(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - *compare; + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(*compare, dest, res); + FLAG_C = CFLAG_SUB_32(*compare, dest, res); + + if(COND_NE()) + *compare = dest; + else + { + USE_CYCLES(3); + m68ki_write_32(ea, REG_D[(word2 >> 6) & 7]); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas_32_di(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_DI_32(); + uint dest = m68ki_read_32(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - *compare; + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(*compare, dest, res); + FLAG_C = CFLAG_SUB_32(*compare, dest, res); + + if(COND_NE()) + *compare = dest; + else + { + USE_CYCLES(3); + m68ki_write_32(ea, REG_D[(word2 >> 6) & 7]); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas_32_ix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_IX_32(); + uint dest = m68ki_read_32(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - *compare; + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(*compare, dest, res); + FLAG_C = CFLAG_SUB_32(*compare, dest, res); + + if(COND_NE()) + *compare = dest; + else + { + USE_CYCLES(3); + m68ki_write_32(ea, REG_D[(word2 >> 6) & 7]); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas_32_aw(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = EA_AW_32(); + uint dest = m68ki_read_32(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - *compare; + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(*compare, dest, res); + FLAG_C = CFLAG_SUB_32(*compare, dest, res); + + if(COND_NE()) + *compare = dest; + else + { + USE_CYCLES(3); + m68ki_write_32(ea, REG_D[(word2 >> 6) & 7]); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas_32_al(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint ea = EA_AL_32(); + uint dest = m68ki_read_32(ea); + uint* compare = ®_D[word2 & 7]; + uint res = dest - *compare; + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(*compare, dest, res); + FLAG_C = CFLAG_SUB_32(*compare, dest, res); + + if(COND_NE()) + *compare = dest; + else + { + USE_CYCLES(3); + m68ki_write_32(ea, REG_D[(word2 >> 6) & 7]); + } + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas2_16(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_32(); + uint* compare1 = ®_D[(word2 >> 16) & 7]; + uint ea1 = REG_DA[(word2 >> 28) & 15]; + uint dest1 = m68ki_read_16(ea1); + uint res1 = dest1 - MASK_OUT_ABOVE_16(*compare1); + uint* compare2 = ®_D[word2 & 7]; + uint ea2 = REG_DA[(word2 >> 12) & 15]; + uint dest2 = m68ki_read_16(ea2); + uint res2; + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_16(res1); + FLAG_Z = MASK_OUT_ABOVE_16(res1); + FLAG_V = VFLAG_SUB_16(*compare1, dest1, res1); + FLAG_C = CFLAG_16(res1); + + if(COND_EQ()) + { + res2 = dest2 - MASK_OUT_ABOVE_16(*compare2); + + FLAG_N = NFLAG_16(res2); + FLAG_Z = MASK_OUT_ABOVE_16(res2); + FLAG_V = VFLAG_SUB_16(*compare2, dest2, res2); + FLAG_C = CFLAG_16(res2); + + if(COND_EQ()) + { + USE_CYCLES(3); + m68ki_write_16(ea1, REG_D[(word2 >> 22) & 7]); + m68ki_write_16(ea2, REG_D[(word2 >> 6) & 7]); + return; + } + } + *compare1 = BIT_1F(word2) ? MAKE_INT_16(dest1) : MASK_OUT_BELOW_16(*compare1) | dest1; + *compare2 = BIT_F(word2) ? MAKE_INT_16(dest2) : MASK_OUT_BELOW_16(*compare2) | dest2; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cas2_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_32(); + uint* compare1 = ®_D[(word2 >> 16) & 7]; + uint ea1 = REG_DA[(word2 >> 28) & 15]; + uint dest1 = m68ki_read_32(ea1); + uint res1 = dest1 - *compare1; + uint* compare2 = ®_D[word2 & 7]; + uint ea2 = REG_DA[(word2 >> 12) & 15]; + uint dest2 = m68ki_read_32(ea2); + uint res2; + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + FLAG_N = NFLAG_32(res1); + FLAG_Z = MASK_OUT_ABOVE_32(res1); + FLAG_V = VFLAG_SUB_32(*compare1, dest1, res1); + FLAG_C = CFLAG_SUB_32(*compare1, dest1, res1); + + if(COND_EQ()) + { + res2 = dest2 - *compare2; + + FLAG_N = NFLAG_32(res2); + FLAG_Z = MASK_OUT_ABOVE_32(res2); + FLAG_V = VFLAG_SUB_32(*compare2, dest2, res2); + FLAG_C = CFLAG_SUB_32(*compare2, dest2, res2); + + if(COND_EQ()) + { + USE_CYCLES(3); + m68ki_write_32(ea1, REG_D[(word2 >> 22) & 7]); + m68ki_write_32(ea2, REG_D[(word2 >> 6) & 7]); + return; + } + } + *compare1 = dest1; + *compare2 = dest2; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk_16_d(void) +{ + sint src = MAKE_INT_16(DX); + sint bound = MAKE_INT_16(DY); + + FLAG_Z = ZFLAG_16(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); +} + + +void m68k_op_chk_16_ai(void) +{ + sint src = MAKE_INT_16(DX); + sint bound = MAKE_INT_16(OPER_AY_AI_16()); + + FLAG_Z = ZFLAG_16(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); +} + + +void m68k_op_chk_16_pi(void) +{ + sint src = MAKE_INT_16(DX); + sint bound = MAKE_INT_16(OPER_AY_PI_16()); + + FLAG_Z = ZFLAG_16(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); +} + + +void m68k_op_chk_16_pd(void) +{ + sint src = MAKE_INT_16(DX); + sint bound = MAKE_INT_16(OPER_AY_PD_16()); + + FLAG_Z = ZFLAG_16(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); +} + + +void m68k_op_chk_16_di(void) +{ + sint src = MAKE_INT_16(DX); + sint bound = MAKE_INT_16(OPER_AY_DI_16()); + + FLAG_Z = ZFLAG_16(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); +} + + +void m68k_op_chk_16_ix(void) +{ + sint src = MAKE_INT_16(DX); + sint bound = MAKE_INT_16(OPER_AY_IX_16()); + + FLAG_Z = ZFLAG_16(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); +} + + +void m68k_op_chk_16_aw(void) +{ + sint src = MAKE_INT_16(DX); + sint bound = MAKE_INT_16(OPER_AW_16()); + + FLAG_Z = ZFLAG_16(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); +} + + +void m68k_op_chk_16_al(void) +{ + sint src = MAKE_INT_16(DX); + sint bound = MAKE_INT_16(OPER_AL_16()); + + FLAG_Z = ZFLAG_16(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); +} + + +void m68k_op_chk_16_pcdi(void) +{ + sint src = MAKE_INT_16(DX); + sint bound = MAKE_INT_16(OPER_PCDI_16()); + + FLAG_Z = ZFLAG_16(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); +} + + +void m68k_op_chk_16_pcix(void) +{ + sint src = MAKE_INT_16(DX); + sint bound = MAKE_INT_16(OPER_PCIX_16()); + + FLAG_Z = ZFLAG_16(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); +} + + +void m68k_op_chk_16_i(void) +{ + sint src = MAKE_INT_16(DX); + sint bound = MAKE_INT_16(OPER_I_16()); + + FLAG_Z = ZFLAG_16(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); +} + + +void m68k_op_chk_32_d(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + sint src = MAKE_INT_32(DX); + sint bound = MAKE_INT_32(DY); + + FLAG_Z = ZFLAG_32(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk_32_ai(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + sint src = MAKE_INT_32(DX); + sint bound = MAKE_INT_32(OPER_AY_AI_32()); + + FLAG_Z = ZFLAG_32(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk_32_pi(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + sint src = MAKE_INT_32(DX); + sint bound = MAKE_INT_32(OPER_AY_PI_32()); + + FLAG_Z = ZFLAG_32(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk_32_pd(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + sint src = MAKE_INT_32(DX); + sint bound = MAKE_INT_32(OPER_AY_PD_32()); + + FLAG_Z = ZFLAG_32(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk_32_di(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + sint src = MAKE_INT_32(DX); + sint bound = MAKE_INT_32(OPER_AY_DI_32()); + + FLAG_Z = ZFLAG_32(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk_32_ix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + sint src = MAKE_INT_32(DX); + sint bound = MAKE_INT_32(OPER_AY_IX_32()); + + FLAG_Z = ZFLAG_32(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk_32_aw(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + sint src = MAKE_INT_32(DX); + sint bound = MAKE_INT_32(OPER_AW_32()); + + FLAG_Z = ZFLAG_32(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk_32_al(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + sint src = MAKE_INT_32(DX); + sint bound = MAKE_INT_32(OPER_AL_32()); + + FLAG_Z = ZFLAG_32(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk_32_pcdi(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + sint src = MAKE_INT_32(DX); + sint bound = MAKE_INT_32(OPER_PCDI_32()); + + FLAG_Z = ZFLAG_32(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk_32_pcix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + sint src = MAKE_INT_32(DX); + sint bound = MAKE_INT_32(OPER_PCIX_32()); + + FLAG_Z = ZFLAG_32(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk_32_i(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + sint src = MAKE_INT_32(DX); + sint bound = MAKE_INT_32(OPER_I_32()); + + FLAG_Z = ZFLAG_32(src); /* Undocumented */ + FLAG_V = VFLAG_CLEAR; /* Undocumented */ + FLAG_C = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + FLAG_N = (src < 0)<<7; + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk2cmp2_8_pcdi(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]&0xff; + uint ea = EA_PCDI_8(); + uint lower_bound = m68ki_read_pcrel_8(ea); + uint upper_bound = m68ki_read_pcrel_8(ea + 1); + + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound); + else + FLAG_C = compare - lower_bound; + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + + FLAG_C = upper_bound - compare; + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk2cmp2_8_pcix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]&0xff; + uint ea = EA_PCIX_8(); + uint lower_bound = m68ki_read_pcrel_8(ea); + uint upper_bound = m68ki_read_pcrel_8(ea + 1); + + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound); + else + FLAG_C = compare - lower_bound; + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + + FLAG_C = upper_bound - compare; + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk2cmp2_8_ai(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]&0xff; + uint ea = EA_AY_AI_8(); + uint lower_bound = m68ki_read_8(ea); + uint upper_bound = m68ki_read_8(ea + 1); + + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound); + else + FLAG_C = compare - lower_bound; + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + + FLAG_C = upper_bound - compare; + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk2cmp2_8_di(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]&0xff; + uint ea = EA_AY_DI_8(); + uint lower_bound = m68ki_read_8(ea); + uint upper_bound = m68ki_read_8(ea + 1); + + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound); + else + FLAG_C = compare - lower_bound; + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + + FLAG_C = upper_bound - compare; + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk2cmp2_8_ix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]&0xff; + uint ea = EA_AY_IX_8(); + uint lower_bound = m68ki_read_8(ea); + uint upper_bound = m68ki_read_8(ea + 1); + + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound); + else + FLAG_C = compare - lower_bound; + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + + FLAG_C = upper_bound - compare; + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk2cmp2_8_aw(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]&0xff; + uint ea = EA_AW_8(); + uint lower_bound = m68ki_read_8(ea); + uint upper_bound = m68ki_read_8(ea + 1); + + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound); + else + FLAG_C = compare - lower_bound; + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + + FLAG_C = upper_bound - compare; + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk2cmp2_8_al(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]&0xff; + uint ea = EA_AL_8(); + uint lower_bound = m68ki_read_8(ea); + uint upper_bound = m68ki_read_8(ea + 1); + + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound); + else + FLAG_C = compare - lower_bound; + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + + FLAG_C = upper_bound - compare; + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk2cmp2_16_pcdi(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]&0xffff; + uint ea = EA_PCDI_16(); + uint lower_bound = m68ki_read_pcrel_16(ea); + uint upper_bound = m68ki_read_pcrel_16(ea + 2); + + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound); + else + FLAG_C = compare - lower_bound; + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + FLAG_C = CFLAG_16(FLAG_C); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare); + else + FLAG_C = upper_bound - compare; + FLAG_C = CFLAG_16(FLAG_C); + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk2cmp2_16_pcix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]&0xffff; + uint ea = EA_PCIX_16(); + uint lower_bound = m68ki_read_pcrel_16(ea); + uint upper_bound = m68ki_read_pcrel_16(ea + 2); + + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound); + else + FLAG_C = compare - lower_bound; + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + FLAG_C = CFLAG_16(FLAG_C); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare); + else + FLAG_C = upper_bound - compare; + FLAG_C = CFLAG_16(FLAG_C); + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk2cmp2_16_ai(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]&0xffff; + uint ea = EA_AY_AI_16(); + uint lower_bound = m68ki_read_16(ea); + uint upper_bound = m68ki_read_16(ea + 2); + + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound); + else + FLAG_C = compare - lower_bound; + + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + FLAG_C = CFLAG_16(FLAG_C); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare); + else + FLAG_C = upper_bound - compare; + + FLAG_C = CFLAG_16(FLAG_C); + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk2cmp2_16_di(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]&0xffff; + uint ea = EA_AY_DI_16(); + uint lower_bound = m68ki_read_16(ea); + uint upper_bound = m68ki_read_16(ea + 2); + + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound); + else + FLAG_C = compare - lower_bound; + + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + FLAG_C = CFLAG_16(FLAG_C); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare); + else + FLAG_C = upper_bound - compare; + + FLAG_C = CFLAG_16(FLAG_C); + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk2cmp2_16_ix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]&0xffff; + uint ea = EA_AY_IX_16(); + uint lower_bound = m68ki_read_16(ea); + uint upper_bound = m68ki_read_16(ea + 2); + + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound); + else + FLAG_C = compare - lower_bound; + + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + FLAG_C = CFLAG_16(FLAG_C); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare); + else + FLAG_C = upper_bound - compare; + + FLAG_C = CFLAG_16(FLAG_C); + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk2cmp2_16_aw(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]&0xffff; + uint ea = EA_AW_16(); + uint lower_bound = m68ki_read_16(ea); + uint upper_bound = m68ki_read_16(ea + 2); + + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound); + else + FLAG_C = compare - lower_bound; + + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + FLAG_C = CFLAG_16(FLAG_C); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare); + else + FLAG_C = upper_bound - compare; + + FLAG_C = CFLAG_16(FLAG_C); + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk2cmp2_16_al(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]&0xffff; + uint ea = EA_AL_16(); + uint lower_bound = m68ki_read_16(ea); + uint upper_bound = m68ki_read_16(ea + 2); + + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound); + else + FLAG_C = compare - lower_bound; + + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + FLAG_C = CFLAG_16(FLAG_C); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + if(!BIT_F(word2)) + FLAG_C = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare); + else + FLAG_C = upper_bound - compare; + + FLAG_C = CFLAG_16(FLAG_C); + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk2cmp2_32_pcdi(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]; + uint ea = EA_PCDI_32(); + uint lower_bound = m68ki_read_pcrel_32(ea); + uint upper_bound = m68ki_read_pcrel_32(ea + 4); + + FLAG_C = compare - lower_bound; + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + FLAG_C = CFLAG_SUB_32(lower_bound, compare, FLAG_C); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + + FLAG_C = upper_bound - compare; + FLAG_C = CFLAG_SUB_32(compare, upper_bound, FLAG_C); + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk2cmp2_32_pcix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]; + uint ea = EA_PCIX_32(); + uint lower_bound = m68ki_read_pcrel_32(ea); + uint upper_bound = m68ki_read_pcrel_32(ea + 4); + + FLAG_C = compare - lower_bound; + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + FLAG_C = CFLAG_SUB_32(lower_bound, compare, FLAG_C); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + + FLAG_C = upper_bound - compare; + FLAG_C = CFLAG_SUB_32(compare, upper_bound, FLAG_C); + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk2cmp2_32_ai(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]; + uint ea = EA_AY_AI_32(); + uint lower_bound = m68ki_read_32(ea); + uint upper_bound = m68ki_read_32(ea + 4); + + FLAG_C = compare - lower_bound; + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + FLAG_C = CFLAG_SUB_32(lower_bound, compare, FLAG_C); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + + FLAG_C = upper_bound - compare; + FLAG_C = CFLAG_SUB_32(compare, upper_bound, FLAG_C); + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk2cmp2_32_di(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]; + uint ea = EA_AY_DI_32(); + uint lower_bound = m68ki_read_32(ea); + uint upper_bound = m68ki_read_32(ea + 4); + + FLAG_C = compare - lower_bound; + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + FLAG_C = CFLAG_SUB_32(lower_bound, compare, FLAG_C); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + + FLAG_C = upper_bound - compare; + FLAG_C = CFLAG_SUB_32(compare, upper_bound, FLAG_C); + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk2cmp2_32_ix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]; + uint ea = EA_AY_IX_32(); + uint lower_bound = m68ki_read_32(ea); + uint upper_bound = m68ki_read_32(ea + 4); + + FLAG_C = compare - lower_bound; + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + FLAG_C = CFLAG_SUB_32(lower_bound, compare, FLAG_C); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + + FLAG_C = upper_bound - compare; + FLAG_C = CFLAG_SUB_32(compare, upper_bound, FLAG_C); + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk2cmp2_32_aw(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]; + uint ea = EA_AW_32(); + uint lower_bound = m68ki_read_32(ea); + uint upper_bound = m68ki_read_32(ea + 4); + + FLAG_C = compare - lower_bound; + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + FLAG_C = CFLAG_SUB_32(lower_bound, compare, FLAG_C); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + + FLAG_C = upper_bound - compare; + FLAG_C = CFLAG_SUB_32(compare, upper_bound, FLAG_C); + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_chk2cmp2_32_al(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint compare = REG_DA[(word2 >> 12) & 15]; + uint ea = EA_AL_32(); + uint lower_bound = m68ki_read_32(ea); + uint upper_bound = m68ki_read_32(ea + 4); + + FLAG_C = compare - lower_bound; + FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); + FLAG_C = CFLAG_SUB_32(lower_bound, compare, FLAG_C); + if(COND_CS()) + { + if(BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + + FLAG_C = upper_bound - compare; + FLAG_C = CFLAG_SUB_32(compare, upper_bound, FLAG_C); + if(COND_CS() && BIT_B(word2)) + m68ki_exception_trap(EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_clr_8_d(void) +{ + DY &= 0xffffff00; + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_8_ai(void) +{ + m68ki_write_8(EA_AY_AI_8(), 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_8_pi(void) +{ + m68ki_write_8(EA_AY_PI_8(), 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_8_pi7(void) +{ + m68ki_write_8(EA_A7_PI_8(), 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_8_pd(void) +{ + m68ki_write_8(EA_AY_PD_8(), 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_8_pd7(void) +{ + m68ki_write_8(EA_A7_PD_8(), 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_8_di(void) +{ + m68ki_write_8(EA_AY_DI_8(), 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_8_ix(void) +{ + m68ki_write_8(EA_AY_IX_8(), 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_8_aw(void) +{ + m68ki_write_8(EA_AW_8(), 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_8_al(void) +{ + m68ki_write_8(EA_AL_8(), 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_16_d(void) +{ + DY &= 0xffff0000; + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_16_ai(void) +{ + m68ki_write_16(EA_AY_AI_16(), 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_16_pi(void) +{ + m68ki_write_16(EA_AY_PI_16(), 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_16_pd(void) +{ + m68ki_write_16(EA_AY_PD_16(), 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_16_di(void) +{ + m68ki_write_16(EA_AY_DI_16(), 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_16_ix(void) +{ + m68ki_write_16(EA_AY_IX_16(), 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_16_aw(void) +{ + m68ki_write_16(EA_AW_16(), 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_16_al(void) +{ + m68ki_write_16(EA_AL_16(), 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_32_d(void) +{ + DY = 0; + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_32_ai(void) +{ + m68ki_write_32(EA_AY_AI_32(), 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_32_pi(void) +{ + m68ki_write_32(EA_AY_PI_32(), 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_32_pd(void) +{ + m68ki_write_32(EA_AY_PD_32(), 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_32_di(void) +{ + m68ki_write_32(EA_AY_DI_32(), 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_32_ix(void) +{ + m68ki_write_32(EA_AY_IX_32(), 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_32_aw(void) +{ + m68ki_write_32(EA_AW_32(), 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_clr_32_al(void) +{ + m68ki_write_32(EA_AL_32(), 0); + + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; +} + + +void m68k_op_cmp_8_d(void) +{ + uint src = MASK_OUT_ABOVE_8(DY); + uint dst = MASK_OUT_ABOVE_8(DX); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmp_8_ai(void) +{ + uint src = OPER_AY_AI_8(); + uint dst = MASK_OUT_ABOVE_8(DX); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmp_8_pi(void) +{ + uint src = OPER_AY_PI_8(); + uint dst = MASK_OUT_ABOVE_8(DX); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmp_8_pi7(void) +{ + uint src = OPER_A7_PI_8(); + uint dst = MASK_OUT_ABOVE_8(DX); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmp_8_pd(void) +{ + uint src = OPER_AY_PD_8(); + uint dst = MASK_OUT_ABOVE_8(DX); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmp_8_pd7(void) +{ + uint src = OPER_A7_PD_8(); + uint dst = MASK_OUT_ABOVE_8(DX); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmp_8_di(void) +{ + uint src = OPER_AY_DI_8(); + uint dst = MASK_OUT_ABOVE_8(DX); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmp_8_ix(void) +{ + uint src = OPER_AY_IX_8(); + uint dst = MASK_OUT_ABOVE_8(DX); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmp_8_aw(void) +{ + uint src = OPER_AW_8(); + uint dst = MASK_OUT_ABOVE_8(DX); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmp_8_al(void) +{ + uint src = OPER_AL_8(); + uint dst = MASK_OUT_ABOVE_8(DX); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmp_8_pcdi(void) +{ + uint src = OPER_PCDI_8(); + uint dst = MASK_OUT_ABOVE_8(DX); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmp_8_pcix(void) +{ + uint src = OPER_PCIX_8(); + uint dst = MASK_OUT_ABOVE_8(DX); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmp_8_i(void) +{ + uint src = OPER_I_8(); + uint dst = MASK_OUT_ABOVE_8(DX); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmp_16_d(void) +{ + uint src = MASK_OUT_ABOVE_16(DY); + uint dst = MASK_OUT_ABOVE_16(DX); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +void m68k_op_cmp_16_a(void) +{ + uint src = MASK_OUT_ABOVE_16(AY); + uint dst = MASK_OUT_ABOVE_16(DX); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +void m68k_op_cmp_16_ai(void) +{ + uint src = OPER_AY_AI_16(); + uint dst = MASK_OUT_ABOVE_16(DX); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +void m68k_op_cmp_16_pi(void) +{ + uint src = OPER_AY_PI_16(); + uint dst = MASK_OUT_ABOVE_16(DX); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +void m68k_op_cmp_16_pd(void) +{ + uint src = OPER_AY_PD_16(); + uint dst = MASK_OUT_ABOVE_16(DX); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +void m68k_op_cmp_16_di(void) +{ + uint src = OPER_AY_DI_16(); + uint dst = MASK_OUT_ABOVE_16(DX); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +void m68k_op_cmp_16_ix(void) +{ + uint src = OPER_AY_IX_16(); + uint dst = MASK_OUT_ABOVE_16(DX); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +void m68k_op_cmp_16_aw(void) +{ + uint src = OPER_AW_16(); + uint dst = MASK_OUT_ABOVE_16(DX); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +void m68k_op_cmp_16_al(void) +{ + uint src = OPER_AL_16(); + uint dst = MASK_OUT_ABOVE_16(DX); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +void m68k_op_cmp_16_pcdi(void) +{ + uint src = OPER_PCDI_16(); + uint dst = MASK_OUT_ABOVE_16(DX); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +void m68k_op_cmp_16_pcix(void) +{ + uint src = OPER_PCIX_16(); + uint dst = MASK_OUT_ABOVE_16(DX); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +void m68k_op_cmp_16_i(void) +{ + uint src = OPER_I_16(); + uint dst = MASK_OUT_ABOVE_16(DX); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +void m68k_op_cmp_32_d(void) +{ + uint src = DY; + uint dst = DX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmp_32_a(void) +{ + uint src = AY; + uint dst = DX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmp_32_ai(void) +{ + uint src = OPER_AY_AI_32(); + uint dst = DX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmp_32_pi(void) +{ + uint src = OPER_AY_PI_32(); + uint dst = DX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmp_32_pd(void) +{ + uint src = OPER_AY_PD_32(); + uint dst = DX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmp_32_di(void) +{ + uint src = OPER_AY_DI_32(); + uint dst = DX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmp_32_ix(void) +{ + uint src = OPER_AY_IX_32(); + uint dst = DX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmp_32_aw(void) +{ + uint src = OPER_AW_32(); + uint dst = DX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmp_32_al(void) +{ + uint src = OPER_AL_32(); + uint dst = DX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmp_32_pcdi(void) +{ + uint src = OPER_PCDI_32(); + uint dst = DX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmp_32_pcix(void) +{ + uint src = OPER_PCIX_32(); + uint dst = DX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmp_32_i(void) +{ + uint src = OPER_I_32(); + uint dst = DX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpa_16_d(void) +{ + uint src = MAKE_INT_16(DY); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpa_16_a(void) +{ + uint src = MAKE_INT_16(AY); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpa_16_ai(void) +{ + uint src = MAKE_INT_16(OPER_AY_AI_16()); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpa_16_pi(void) +{ + uint src = MAKE_INT_16(OPER_AY_PI_16()); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpa_16_pd(void) +{ + uint src = MAKE_INT_16(OPER_AY_PD_16()); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpa_16_di(void) +{ + uint src = MAKE_INT_16(OPER_AY_DI_16()); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpa_16_ix(void) +{ + uint src = MAKE_INT_16(OPER_AY_IX_16()); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpa_16_aw(void) +{ + uint src = MAKE_INT_16(OPER_AW_16()); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpa_16_al(void) +{ + uint src = MAKE_INT_16(OPER_AL_16()); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpa_16_pcdi(void) +{ + uint src = MAKE_INT_16(OPER_PCDI_16()); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpa_16_pcix(void) +{ + uint src = MAKE_INT_16(OPER_PCIX_16()); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpa_16_i(void) +{ + uint src = MAKE_INT_16(OPER_I_16()); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpa_32_d(void) +{ + uint src = DY; + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpa_32_a(void) +{ + uint src = AY; + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpa_32_ai(void) +{ + uint src = OPER_AY_AI_32(); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpa_32_pi(void) +{ + uint src = OPER_AY_PI_32(); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpa_32_pd(void) +{ + uint src = OPER_AY_PD_32(); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpa_32_di(void) +{ + uint src = OPER_AY_DI_32(); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpa_32_ix(void) +{ + uint src = OPER_AY_IX_32(); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpa_32_aw(void) +{ + uint src = OPER_AW_32(); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpa_32_al(void) +{ + uint src = OPER_AL_32(); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpa_32_pcdi(void) +{ + uint src = OPER_PCDI_32(); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpa_32_pcix(void) +{ + uint src = OPER_PCIX_32(); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpa_32_i(void) +{ + uint src = OPER_I_32(); + uint dst = AX; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpi_8_d(void) +{ + uint src = OPER_I_8(); + uint dst = MASK_OUT_ABOVE_8(DY); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmpi_8_ai(void) +{ + uint src = OPER_I_8(); + uint dst = OPER_AY_AI_8(); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmpi_8_pi(void) +{ + uint src = OPER_I_8(); + uint dst = OPER_AY_PI_8(); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmpi_8_pi7(void) +{ + uint src = OPER_I_8(); + uint dst = OPER_A7_PI_8(); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmpi_8_pd(void) +{ + uint src = OPER_I_8(); + uint dst = OPER_AY_PD_8(); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmpi_8_pd7(void) +{ + uint src = OPER_I_8(); + uint dst = OPER_A7_PD_8(); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmpi_8_di(void) +{ + uint src = OPER_I_8(); + uint dst = OPER_AY_DI_8(); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmpi_8_ix(void) +{ + uint src = OPER_I_8(); + uint dst = OPER_AY_IX_8(); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmpi_8_aw(void) +{ + uint src = OPER_I_8(); + uint dst = OPER_AW_8(); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmpi_8_al(void) +{ + uint src = OPER_I_8(); + uint dst = OPER_AL_8(); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmpi_8_pcdi(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint src = OPER_I_8(); + uint dst = OPER_PCDI_8(); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cmpi_8_pcix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint src = OPER_I_8(); + uint dst = OPER_PCIX_8(); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cmpi_16_d(void) +{ + uint src = OPER_I_16(); + uint dst = MASK_OUT_ABOVE_16(DY); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +void m68k_op_cmpi_16_ai(void) +{ + uint src = OPER_I_16(); + uint dst = OPER_AY_AI_16(); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +void m68k_op_cmpi_16_pi(void) +{ + uint src = OPER_I_16(); + uint dst = OPER_AY_PI_16(); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +void m68k_op_cmpi_16_pd(void) +{ + uint src = OPER_I_16(); + uint dst = OPER_AY_PD_16(); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +void m68k_op_cmpi_16_di(void) +{ + uint src = OPER_I_16(); + uint dst = OPER_AY_DI_16(); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +void m68k_op_cmpi_16_ix(void) +{ + uint src = OPER_I_16(); + uint dst = OPER_AY_IX_16(); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +void m68k_op_cmpi_16_aw(void) +{ + uint src = OPER_I_16(); + uint dst = OPER_AW_16(); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +void m68k_op_cmpi_16_al(void) +{ + uint src = OPER_I_16(); + uint dst = OPER_AL_16(); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +void m68k_op_cmpi_16_pcdi(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint src = OPER_I_16(); + uint dst = OPER_PCDI_16(); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cmpi_16_pcix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint src = OPER_I_16(); + uint dst = OPER_PCIX_16(); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cmpi_32_d(void) +{ + uint src = OPER_I_32(); + uint dst = DY; + uint res = dst - src; + + m68ki_cmpild_callback(src, REG_IR & 7); /* auto-disable (see m68kcpu.h) */ + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpi_32_ai(void) +{ + uint src = OPER_I_32(); + uint dst = OPER_AY_AI_32(); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpi_32_pi(void) +{ + uint src = OPER_I_32(); + uint dst = OPER_AY_PI_32(); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpi_32_pd(void) +{ + uint src = OPER_I_32(); + uint dst = OPER_AY_PD_32(); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpi_32_di(void) +{ + uint src = OPER_I_32(); + uint dst = OPER_AY_DI_32(); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpi_32_ix(void) +{ + uint src = OPER_I_32(); + uint dst = OPER_AY_IX_32(); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpi_32_aw(void) +{ + uint src = OPER_I_32(); + uint dst = OPER_AW_32(); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpi_32_al(void) +{ + uint src = OPER_I_32(); + uint dst = OPER_AL_32(); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cmpi_32_pcdi(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint src = OPER_I_32(); + uint dst = OPER_PCDI_32(); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cmpi_32_pcix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint src = OPER_I_32(); + uint dst = OPER_PCIX_32(); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_cmpm_8_ax7(void) +{ + uint src = OPER_AY_PI_8(); + uint dst = OPER_A7_PI_8(); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmpm_8_ay7(void) +{ + uint src = OPER_A7_PI_8(); + uint dst = OPER_AX_PI_8(); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmpm_8_axy7(void) +{ + uint src = OPER_A7_PI_8(); + uint dst = OPER_A7_PI_8(); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmpm_8(void) +{ + uint src = OPER_AY_PI_8(); + uint dst = OPER_AX_PI_8(); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_C = CFLAG_8(res); +} + + +void m68k_op_cmpm_16(void) +{ + uint src = OPER_AY_PI_16(); + uint dst = OPER_AX_PI_16(); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_C = CFLAG_16(res); +} + + +void m68k_op_cmpm_32(void) +{ + uint src = OPER_AY_PI_32(); + uint dst = OPER_AX_PI_32(); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_C = CFLAG_SUB_32(src, dst, res); +} + + +void m68k_op_cpbcc_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", + m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, + m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); + return; + } + m68ki_exception_1111(); +} + + +void m68k_op_cpdbcc_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", + m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, + m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); + return; + } + m68ki_exception_1111(); +} + + +void m68k_op_cpgen_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", + m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, + m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); + return; + } + m68ki_exception_1111(); +} + + +void m68k_op_cpscc_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", + m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, + m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); + return; + } + m68ki_exception_1111(); +} + + +void m68k_op_cptrapcc_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", + m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, + m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); + return; + } + m68ki_exception_1111(); +} + + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ + + diff --git a/cpu/musashi/m68kopdm.c b/cpu/musashi/m68kopdm.c new file mode 100644 index 00000000..82de8c5b --- /dev/null +++ b/cpu/musashi/m68kopdm.c @@ -0,0 +1,13385 @@ +#include "m68kcpu.h" + +/* ======================================================================== */ +/* ========================= INSTRUCTION HANDLERS ========================= */ +/* ======================================================================== */ + + +void m68k_op_dbt_16(void) +{ + REG_PC += 2; +} + + +void m68k_op_dbf_16(void) +{ + uint* r_dst = &DY; + uint res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + USE_CYCLES(CYC_DBCC_F_NOEXP); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_DBCC_F_EXP); +} + + +void m68k_op_dbhi_16(void) +{ + if(COND_NOT_HI()) + { + uint* r_dst = &DY; + uint res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + USE_CYCLES(CYC_DBCC_F_NOEXP); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_DBCC_F_EXP); + return; + } + REG_PC += 2; +} + + +void m68k_op_dbls_16(void) +{ + if(COND_NOT_LS()) + { + uint* r_dst = &DY; + uint res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + USE_CYCLES(CYC_DBCC_F_NOEXP); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_DBCC_F_EXP); + return; + } + REG_PC += 2; +} + + +void m68k_op_dbcc_16(void) +{ + if(COND_NOT_CC()) + { + uint* r_dst = &DY; + uint res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + USE_CYCLES(CYC_DBCC_F_NOEXP); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_DBCC_F_EXP); + return; + } + REG_PC += 2; +} + + +void m68k_op_dbcs_16(void) +{ + if(COND_NOT_CS()) + { + uint* r_dst = &DY; + uint res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + USE_CYCLES(CYC_DBCC_F_NOEXP); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_DBCC_F_EXP); + return; + } + REG_PC += 2; +} + + +void m68k_op_dbne_16(void) +{ + if(COND_NOT_NE()) + { + uint* r_dst = &DY; + uint res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + USE_CYCLES(CYC_DBCC_F_NOEXP); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_DBCC_F_EXP); + return; + } + REG_PC += 2; +} + + +void m68k_op_dbeq_16(void) +{ + if(COND_NOT_EQ()) + { + uint* r_dst = &DY; + uint res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + USE_CYCLES(CYC_DBCC_F_NOEXP); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_DBCC_F_EXP); + return; + } + REG_PC += 2; +} + + +void m68k_op_dbvc_16(void) +{ + if(COND_NOT_VC()) + { + uint* r_dst = &DY; + uint res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + USE_CYCLES(CYC_DBCC_F_NOEXP); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_DBCC_F_EXP); + return; + } + REG_PC += 2; +} + + +void m68k_op_dbvs_16(void) +{ + if(COND_NOT_VS()) + { + uint* r_dst = &DY; + uint res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + USE_CYCLES(CYC_DBCC_F_NOEXP); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_DBCC_F_EXP); + return; + } + REG_PC += 2; +} + + +void m68k_op_dbpl_16(void) +{ + if(COND_NOT_PL()) + { + uint* r_dst = &DY; + uint res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + USE_CYCLES(CYC_DBCC_F_NOEXP); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_DBCC_F_EXP); + return; + } + REG_PC += 2; +} + + +void m68k_op_dbmi_16(void) +{ + if(COND_NOT_MI()) + { + uint* r_dst = &DY; + uint res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + USE_CYCLES(CYC_DBCC_F_NOEXP); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_DBCC_F_EXP); + return; + } + REG_PC += 2; +} + + +void m68k_op_dbge_16(void) +{ + if(COND_NOT_GE()) + { + uint* r_dst = &DY; + uint res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + USE_CYCLES(CYC_DBCC_F_NOEXP); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_DBCC_F_EXP); + return; + } + REG_PC += 2; +} + + +void m68k_op_dblt_16(void) +{ + if(COND_NOT_LT()) + { + uint* r_dst = &DY; + uint res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + USE_CYCLES(CYC_DBCC_F_NOEXP); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_DBCC_F_EXP); + return; + } + REG_PC += 2; +} + + +void m68k_op_dbgt_16(void) +{ + if(COND_NOT_GT()) + { + uint* r_dst = &DY; + uint res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + USE_CYCLES(CYC_DBCC_F_NOEXP); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_DBCC_F_EXP); + return; + } + REG_PC += 2; +} + + +void m68k_op_dble_16(void) +{ + if(COND_NOT_LE()) + { + uint* r_dst = &DY; + uint res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + uint offset = OPER_I_16(); + REG_PC -= 2; + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(offset); + USE_CYCLES(CYC_DBCC_F_NOEXP); + return; + } + REG_PC += 2; + USE_CYCLES(CYC_DBCC_F_EXP); + return; + } + REG_PC += 2; +} + + +void m68k_op_divs_16_d(void) +{ + uint* r_dst = &DX; + sint src = MAKE_INT_16(DY); + sint quotient; + sint remainder; + + if(src != 0) + { + if((uint32)*r_dst == 0x80000000 && src == -1) + { + FLAG_Z = 0; + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +void m68k_op_divs_16_ai(void) +{ + uint* r_dst = &DX; + sint src = MAKE_INT_16(OPER_AY_AI_16()); + sint quotient; + sint remainder; + + if(src != 0) + { + if((uint32)*r_dst == 0x80000000 && src == -1) + { + FLAG_Z = 0; + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +void m68k_op_divs_16_pi(void) +{ + uint* r_dst = &DX; + sint src = MAKE_INT_16(OPER_AY_PI_16()); + sint quotient; + sint remainder; + + if(src != 0) + { + if((uint32)*r_dst == 0x80000000 && src == -1) + { + FLAG_Z = 0; + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +void m68k_op_divs_16_pd(void) +{ + uint* r_dst = &DX; + sint src = MAKE_INT_16(OPER_AY_PD_16()); + sint quotient; + sint remainder; + + if(src != 0) + { + if((uint32)*r_dst == 0x80000000 && src == -1) + { + FLAG_Z = 0; + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +void m68k_op_divs_16_di(void) +{ + uint* r_dst = &DX; + sint src = MAKE_INT_16(OPER_AY_DI_16()); + sint quotient; + sint remainder; + + if(src != 0) + { + if((uint32)*r_dst == 0x80000000 && src == -1) + { + FLAG_Z = 0; + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +void m68k_op_divs_16_ix(void) +{ + uint* r_dst = &DX; + sint src = MAKE_INT_16(OPER_AY_IX_16()); + sint quotient; + sint remainder; + + if(src != 0) + { + if((uint32)*r_dst == 0x80000000 && src == -1) + { + FLAG_Z = 0; + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +void m68k_op_divs_16_aw(void) +{ + uint* r_dst = &DX; + sint src = MAKE_INT_16(OPER_AW_16()); + sint quotient; + sint remainder; + + if(src != 0) + { + if((uint32)*r_dst == 0x80000000 && src == -1) + { + FLAG_Z = 0; + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +void m68k_op_divs_16_al(void) +{ + uint* r_dst = &DX; + sint src = MAKE_INT_16(OPER_AL_16()); + sint quotient; + sint remainder; + + if(src != 0) + { + if((uint32)*r_dst == 0x80000000 && src == -1) + { + FLAG_Z = 0; + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +void m68k_op_divs_16_pcdi(void) +{ + uint* r_dst = &DX; + sint src = MAKE_INT_16(OPER_PCDI_16()); + sint quotient; + sint remainder; + + if(src != 0) + { + if((uint32)*r_dst == 0x80000000 && src == -1) + { + FLAG_Z = 0; + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +void m68k_op_divs_16_pcix(void) +{ + uint* r_dst = &DX; + sint src = MAKE_INT_16(OPER_PCIX_16()); + sint quotient; + sint remainder; + + if(src != 0) + { + if((uint32)*r_dst == 0x80000000 && src == -1) + { + FLAG_Z = 0; + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +void m68k_op_divs_16_i(void) +{ + uint* r_dst = &DX; + sint src = MAKE_INT_16(OPER_I_16()); + sint quotient; + sint remainder; + + if(src != 0) + { + if((uint32)*r_dst == 0x80000000 && src == -1) + { + FLAG_Z = 0; + FLAG_N = NFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +void m68k_op_divu_16_d(void) +{ + uint* r_dst = &DX; + uint src = MASK_OUT_ABOVE_16(DY); + + if(src != 0) + { + uint quotient = *r_dst / src; + uint remainder = *r_dst % src; + + if(quotient < 0x10000) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +void m68k_op_divu_16_ai(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_AI_16(); + + if(src != 0) + { + uint quotient = *r_dst / src; + uint remainder = *r_dst % src; + + if(quotient < 0x10000) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +void m68k_op_divu_16_pi(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_PI_16(); + + if(src != 0) + { + uint quotient = *r_dst / src; + uint remainder = *r_dst % src; + + if(quotient < 0x10000) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +void m68k_op_divu_16_pd(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_PD_16(); + + if(src != 0) + { + uint quotient = *r_dst / src; + uint remainder = *r_dst % src; + + if(quotient < 0x10000) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +void m68k_op_divu_16_di(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_DI_16(); + + if(src != 0) + { + uint quotient = *r_dst / src; + uint remainder = *r_dst % src; + + if(quotient < 0x10000) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +void m68k_op_divu_16_ix(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_IX_16(); + + if(src != 0) + { + uint quotient = *r_dst / src; + uint remainder = *r_dst % src; + + if(quotient < 0x10000) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +void m68k_op_divu_16_aw(void) +{ + uint* r_dst = &DX; + uint src = OPER_AW_16(); + + if(src != 0) + { + uint quotient = *r_dst / src; + uint remainder = *r_dst % src; + + if(quotient < 0x10000) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +void m68k_op_divu_16_al(void) +{ + uint* r_dst = &DX; + uint src = OPER_AL_16(); + + if(src != 0) + { + uint quotient = *r_dst / src; + uint remainder = *r_dst % src; + + if(quotient < 0x10000) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +void m68k_op_divu_16_pcdi(void) +{ + uint* r_dst = &DX; + uint src = OPER_PCDI_16(); + + if(src != 0) + { + uint quotient = *r_dst / src; + uint remainder = *r_dst % src; + + if(quotient < 0x10000) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +void m68k_op_divu_16_pcix(void) +{ + uint* r_dst = &DX; + uint src = OPER_PCIX_16(); + + if(src != 0) + { + uint quotient = *r_dst / src; + uint remainder = *r_dst % src; + + if(quotient < 0x10000) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +void m68k_op_divu_16_i(void) +{ + uint* r_dst = &DX; + uint src = OPER_I_16(); + + if(src != 0) + { + uint quotient = *r_dst / src; + uint remainder = *r_dst % src; + + if(quotient < 0x10000) + { + FLAG_Z = quotient; + FLAG_N = NFLAG_16(quotient); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + FLAG_V = VFLAG_SET; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); +} + + +void m68k_op_divl_32_d(void) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 divisor = DY; + uint64 dividend = 0; + uint64 quotient = 0; + uint64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D[word2 & 7]; + dividend <<= 32; + dividend |= REG_D[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)dividend / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)dividend % (sint64)((sint32)divisor)); + if((sint64)quotient != (sint64)((sint32)quotient)) + { + FLAG_V = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + FLAG_V = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)((sint32)dividend) / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)((sint32)dividend) % (sint64)((sint32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint divisor = DY; + uint dividend_hi = REG_D[word2 & 7]; + uint dividend_lo = REG_D[(word2 >> 12) & 7]; + uint quotient = 0; + uint remainder = 0; + uint dividend_neg = 0; + uint divisor_neg = 0; + sint i; + uint overflow; + + if(divisor != 0) + { + /* quad / long : long quotient, long remainder */ + if(BIT_A(word2)) + { + if(BIT_B(word2)) /* signed */ + { + /* special case in signed divide */ + if(dividend_hi == 0 && dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + REG_D[word2 & 7] = 0; + REG_D[(word2 >> 12) & 7] = 0x80000000; + + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + if(GET_MSB_32(dividend_hi)) + { + dividend_neg = 1; + dividend_hi = (uint)MASK_OUT_ABOVE_32((-(sint)dividend_hi) - (dividend_lo != 0)); + dividend_lo = (uint)MASK_OUT_ABOVE_32(-(sint)dividend_lo); + } + if(GET_MSB_32(divisor)) + { + divisor_neg = 1; + divisor = (uint)MASK_OUT_ABOVE_32(-(sint)divisor); + + } + } + + /* if the upper long is greater than the divisor, we're overflowing. */ + if(dividend_hi >= divisor) + { + FLAG_V = VFLAG_SET; + return; + } + + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + remainder = (remainder << 1) + ((dividend_hi >> i) & 1); + if(remainder >= divisor) + { + remainder -= divisor; + quotient++; + } + } + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + overflow = GET_MSB_32(remainder); + remainder = (remainder << 1) + ((dividend_lo >> i) & 1); + if(remainder >= divisor || overflow) + { + remainder -= divisor; + quotient++; + } + } + + if(BIT_B(word2)) /* signed */ + { + if(quotient > 0x7fffffff) + { + FLAG_V = VFLAG_SET; + return; + } + if(dividend_neg) + { + remainder = (uint)MASK_OUT_ABOVE_32(-(sint)remainder); + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + if(divisor_neg) + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + + /* long / long: long quotient, maybe long remainder */ + if(BIT_B(word2)) /* signed */ + { + /* Special case in divide */ + if(dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + REG_D[(word2 >> 12) & 7] = 0x80000000; + REG_D[word2 & 7] = 0; + return; + } + REG_D[word2 & 7] = MAKE_INT_32(dividend_lo) % MAKE_INT_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MAKE_INT_32(dividend_lo) / MAKE_INT_32(divisor); + } + else + { + REG_D[word2 & 7] = MASK_OUT_ABOVE_32(dividend_lo) % MASK_OUT_ABOVE_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(dividend_lo) / MASK_OUT_ABOVE_32(divisor); + } + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#endif +} + + +void m68k_op_divl_32_ai(void) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 divisor = OPER_AY_AI_32(); + uint64 dividend = 0; + uint64 quotient = 0; + uint64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D[word2 & 7]; + dividend <<= 32; + dividend |= REG_D[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)dividend / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)dividend % (sint64)((sint32)divisor)); + if((sint64)quotient != (sint64)((sint32)quotient)) + { + FLAG_V = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + FLAG_V = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)((sint32)dividend) / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)((sint32)dividend) % (sint64)((sint32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint divisor = OPER_AY_AI_32(); + uint dividend_hi = REG_D[word2 & 7]; + uint dividend_lo = REG_D[(word2 >> 12) & 7]; + uint quotient = 0; + uint remainder = 0; + uint dividend_neg = 0; + uint divisor_neg = 0; + sint i; + uint overflow; + + if(divisor != 0) + { + /* quad / long : long quotient, long remainder */ + if(BIT_A(word2)) + { + if(BIT_B(word2)) /* signed */ + { + /* special case in signed divide */ + if(dividend_hi == 0 && dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + REG_D[word2 & 7] = 0; + REG_D[(word2 >> 12) & 7] = 0x80000000; + + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + if(GET_MSB_32(dividend_hi)) + { + dividend_neg = 1; + dividend_hi = (uint)MASK_OUT_ABOVE_32((-(sint)dividend_hi) - (dividend_lo != 0)); + dividend_lo = (uint)MASK_OUT_ABOVE_32(-(sint)dividend_lo); + } + if(GET_MSB_32(divisor)) + { + divisor_neg = 1; + divisor = (uint)MASK_OUT_ABOVE_32(-(sint)divisor); + + } + } + + /* if the upper long is greater than the divisor, we're overflowing. */ + if(dividend_hi >= divisor) + { + FLAG_V = VFLAG_SET; + return; + } + + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + remainder = (remainder << 1) + ((dividend_hi >> i) & 1); + if(remainder >= divisor) + { + remainder -= divisor; + quotient++; + } + } + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + overflow = GET_MSB_32(remainder); + remainder = (remainder << 1) + ((dividend_lo >> i) & 1); + if(remainder >= divisor || overflow) + { + remainder -= divisor; + quotient++; + } + } + + if(BIT_B(word2)) /* signed */ + { + if(quotient > 0x7fffffff) + { + FLAG_V = VFLAG_SET; + return; + } + if(dividend_neg) + { + remainder = (uint)MASK_OUT_ABOVE_32(-(sint)remainder); + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + if(divisor_neg) + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + + /* long / long: long quotient, maybe long remainder */ + if(BIT_B(word2)) /* signed */ + { + /* Special case in divide */ + if(dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + REG_D[(word2 >> 12) & 7] = 0x80000000; + REG_D[word2 & 7] = 0; + return; + } + REG_D[word2 & 7] = MAKE_INT_32(dividend_lo) % MAKE_INT_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MAKE_INT_32(dividend_lo) / MAKE_INT_32(divisor); + } + else + { + REG_D[word2 & 7] = MASK_OUT_ABOVE_32(dividend_lo) % MASK_OUT_ABOVE_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(dividend_lo) / MASK_OUT_ABOVE_32(divisor); + } + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#endif +} + + +void m68k_op_divl_32_pi(void) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 divisor = OPER_AY_PI_32(); + uint64 dividend = 0; + uint64 quotient = 0; + uint64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D[word2 & 7]; + dividend <<= 32; + dividend |= REG_D[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)dividend / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)dividend % (sint64)((sint32)divisor)); + if((sint64)quotient != (sint64)((sint32)quotient)) + { + FLAG_V = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + FLAG_V = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)((sint32)dividend) / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)((sint32)dividend) % (sint64)((sint32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint divisor = OPER_AY_PI_32(); + uint dividend_hi = REG_D[word2 & 7]; + uint dividend_lo = REG_D[(word2 >> 12) & 7]; + uint quotient = 0; + uint remainder = 0; + uint dividend_neg = 0; + uint divisor_neg = 0; + sint i; + uint overflow; + + if(divisor != 0) + { + /* quad / long : long quotient, long remainder */ + if(BIT_A(word2)) + { + if(BIT_B(word2)) /* signed */ + { + /* special case in signed divide */ + if(dividend_hi == 0 && dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + REG_D[word2 & 7] = 0; + REG_D[(word2 >> 12) & 7] = 0x80000000; + + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + if(GET_MSB_32(dividend_hi)) + { + dividend_neg = 1; + dividend_hi = (uint)MASK_OUT_ABOVE_32((-(sint)dividend_hi) - (dividend_lo != 0)); + dividend_lo = (uint)MASK_OUT_ABOVE_32(-(sint)dividend_lo); + } + if(GET_MSB_32(divisor)) + { + divisor_neg = 1; + divisor = (uint)MASK_OUT_ABOVE_32(-(sint)divisor); + + } + } + + /* if the upper long is greater than the divisor, we're overflowing. */ + if(dividend_hi >= divisor) + { + FLAG_V = VFLAG_SET; + return; + } + + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + remainder = (remainder << 1) + ((dividend_hi >> i) & 1); + if(remainder >= divisor) + { + remainder -= divisor; + quotient++; + } + } + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + overflow = GET_MSB_32(remainder); + remainder = (remainder << 1) + ((dividend_lo >> i) & 1); + if(remainder >= divisor || overflow) + { + remainder -= divisor; + quotient++; + } + } + + if(BIT_B(word2)) /* signed */ + { + if(quotient > 0x7fffffff) + { + FLAG_V = VFLAG_SET; + return; + } + if(dividend_neg) + { + remainder = (uint)MASK_OUT_ABOVE_32(-(sint)remainder); + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + if(divisor_neg) + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + + /* long / long: long quotient, maybe long remainder */ + if(BIT_B(word2)) /* signed */ + { + /* Special case in divide */ + if(dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + REG_D[(word2 >> 12) & 7] = 0x80000000; + REG_D[word2 & 7] = 0; + return; + } + REG_D[word2 & 7] = MAKE_INT_32(dividend_lo) % MAKE_INT_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MAKE_INT_32(dividend_lo) / MAKE_INT_32(divisor); + } + else + { + REG_D[word2 & 7] = MASK_OUT_ABOVE_32(dividend_lo) % MASK_OUT_ABOVE_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(dividend_lo) / MASK_OUT_ABOVE_32(divisor); + } + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#endif +} + + +void m68k_op_divl_32_pd(void) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 divisor = OPER_AY_PD_32(); + uint64 dividend = 0; + uint64 quotient = 0; + uint64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D[word2 & 7]; + dividend <<= 32; + dividend |= REG_D[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)dividend / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)dividend % (sint64)((sint32)divisor)); + if((sint64)quotient != (sint64)((sint32)quotient)) + { + FLAG_V = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + FLAG_V = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)((sint32)dividend) / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)((sint32)dividend) % (sint64)((sint32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint divisor = OPER_AY_PD_32(); + uint dividend_hi = REG_D[word2 & 7]; + uint dividend_lo = REG_D[(word2 >> 12) & 7]; + uint quotient = 0; + uint remainder = 0; + uint dividend_neg = 0; + uint divisor_neg = 0; + sint i; + uint overflow; + + if(divisor != 0) + { + /* quad / long : long quotient, long remainder */ + if(BIT_A(word2)) + { + if(BIT_B(word2)) /* signed */ + { + /* special case in signed divide */ + if(dividend_hi == 0 && dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + REG_D[word2 & 7] = 0; + REG_D[(word2 >> 12) & 7] = 0x80000000; + + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + if(GET_MSB_32(dividend_hi)) + { + dividend_neg = 1; + dividend_hi = (uint)MASK_OUT_ABOVE_32((-(sint)dividend_hi) - (dividend_lo != 0)); + dividend_lo = (uint)MASK_OUT_ABOVE_32(-(sint)dividend_lo); + } + if(GET_MSB_32(divisor)) + { + divisor_neg = 1; + divisor = (uint)MASK_OUT_ABOVE_32(-(sint)divisor); + + } + } + + /* if the upper long is greater than the divisor, we're overflowing. */ + if(dividend_hi >= divisor) + { + FLAG_V = VFLAG_SET; + return; + } + + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + remainder = (remainder << 1) + ((dividend_hi >> i) & 1); + if(remainder >= divisor) + { + remainder -= divisor; + quotient++; + } + } + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + overflow = GET_MSB_32(remainder); + remainder = (remainder << 1) + ((dividend_lo >> i) & 1); + if(remainder >= divisor || overflow) + { + remainder -= divisor; + quotient++; + } + } + + if(BIT_B(word2)) /* signed */ + { + if(quotient > 0x7fffffff) + { + FLAG_V = VFLAG_SET; + return; + } + if(dividend_neg) + { + remainder = (uint)MASK_OUT_ABOVE_32(-(sint)remainder); + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + if(divisor_neg) + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + + /* long / long: long quotient, maybe long remainder */ + if(BIT_B(word2)) /* signed */ + { + /* Special case in divide */ + if(dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + REG_D[(word2 >> 12) & 7] = 0x80000000; + REG_D[word2 & 7] = 0; + return; + } + REG_D[word2 & 7] = MAKE_INT_32(dividend_lo) % MAKE_INT_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MAKE_INT_32(dividend_lo) / MAKE_INT_32(divisor); + } + else + { + REG_D[word2 & 7] = MASK_OUT_ABOVE_32(dividend_lo) % MASK_OUT_ABOVE_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(dividend_lo) / MASK_OUT_ABOVE_32(divisor); + } + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#endif +} + + +void m68k_op_divl_32_di(void) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 divisor = OPER_AY_DI_32(); + uint64 dividend = 0; + uint64 quotient = 0; + uint64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D[word2 & 7]; + dividend <<= 32; + dividend |= REG_D[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)dividend / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)dividend % (sint64)((sint32)divisor)); + if((sint64)quotient != (sint64)((sint32)quotient)) + { + FLAG_V = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + FLAG_V = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)((sint32)dividend) / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)((sint32)dividend) % (sint64)((sint32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint divisor = OPER_AY_DI_32(); + uint dividend_hi = REG_D[word2 & 7]; + uint dividend_lo = REG_D[(word2 >> 12) & 7]; + uint quotient = 0; + uint remainder = 0; + uint dividend_neg = 0; + uint divisor_neg = 0; + sint i; + uint overflow; + + if(divisor != 0) + { + /* quad / long : long quotient, long remainder */ + if(BIT_A(word2)) + { + if(BIT_B(word2)) /* signed */ + { + /* special case in signed divide */ + if(dividend_hi == 0 && dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + REG_D[word2 & 7] = 0; + REG_D[(word2 >> 12) & 7] = 0x80000000; + + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + if(GET_MSB_32(dividend_hi)) + { + dividend_neg = 1; + dividend_hi = (uint)MASK_OUT_ABOVE_32((-(sint)dividend_hi) - (dividend_lo != 0)); + dividend_lo = (uint)MASK_OUT_ABOVE_32(-(sint)dividend_lo); + } + if(GET_MSB_32(divisor)) + { + divisor_neg = 1; + divisor = (uint)MASK_OUT_ABOVE_32(-(sint)divisor); + + } + } + + /* if the upper long is greater than the divisor, we're overflowing. */ + if(dividend_hi >= divisor) + { + FLAG_V = VFLAG_SET; + return; + } + + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + remainder = (remainder << 1) + ((dividend_hi >> i) & 1); + if(remainder >= divisor) + { + remainder -= divisor; + quotient++; + } + } + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + overflow = GET_MSB_32(remainder); + remainder = (remainder << 1) + ((dividend_lo >> i) & 1); + if(remainder >= divisor || overflow) + { + remainder -= divisor; + quotient++; + } + } + + if(BIT_B(word2)) /* signed */ + { + if(quotient > 0x7fffffff) + { + FLAG_V = VFLAG_SET; + return; + } + if(dividend_neg) + { + remainder = (uint)MASK_OUT_ABOVE_32(-(sint)remainder); + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + if(divisor_neg) + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + + /* long / long: long quotient, maybe long remainder */ + if(BIT_B(word2)) /* signed */ + { + /* Special case in divide */ + if(dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + REG_D[(word2 >> 12) & 7] = 0x80000000; + REG_D[word2 & 7] = 0; + return; + } + REG_D[word2 & 7] = MAKE_INT_32(dividend_lo) % MAKE_INT_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MAKE_INT_32(dividend_lo) / MAKE_INT_32(divisor); + } + else + { + REG_D[word2 & 7] = MASK_OUT_ABOVE_32(dividend_lo) % MASK_OUT_ABOVE_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(dividend_lo) / MASK_OUT_ABOVE_32(divisor); + } + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#endif +} + + +void m68k_op_divl_32_ix(void) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 divisor = OPER_AY_IX_32(); + uint64 dividend = 0; + uint64 quotient = 0; + uint64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D[word2 & 7]; + dividend <<= 32; + dividend |= REG_D[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)dividend / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)dividend % (sint64)((sint32)divisor)); + if((sint64)quotient != (sint64)((sint32)quotient)) + { + FLAG_V = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + FLAG_V = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)((sint32)dividend) / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)((sint32)dividend) % (sint64)((sint32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint divisor = OPER_AY_IX_32(); + uint dividend_hi = REG_D[word2 & 7]; + uint dividend_lo = REG_D[(word2 >> 12) & 7]; + uint quotient = 0; + uint remainder = 0; + uint dividend_neg = 0; + uint divisor_neg = 0; + sint i; + uint overflow; + + if(divisor != 0) + { + /* quad / long : long quotient, long remainder */ + if(BIT_A(word2)) + { + if(BIT_B(word2)) /* signed */ + { + /* special case in signed divide */ + if(dividend_hi == 0 && dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + REG_D[word2 & 7] = 0; + REG_D[(word2 >> 12) & 7] = 0x80000000; + + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + if(GET_MSB_32(dividend_hi)) + { + dividend_neg = 1; + dividend_hi = (uint)MASK_OUT_ABOVE_32((-(sint)dividend_hi) - (dividend_lo != 0)); + dividend_lo = (uint)MASK_OUT_ABOVE_32(-(sint)dividend_lo); + } + if(GET_MSB_32(divisor)) + { + divisor_neg = 1; + divisor = (uint)MASK_OUT_ABOVE_32(-(sint)divisor); + + } + } + + /* if the upper long is greater than the divisor, we're overflowing. */ + if(dividend_hi >= divisor) + { + FLAG_V = VFLAG_SET; + return; + } + + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + remainder = (remainder << 1) + ((dividend_hi >> i) & 1); + if(remainder >= divisor) + { + remainder -= divisor; + quotient++; + } + } + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + overflow = GET_MSB_32(remainder); + remainder = (remainder << 1) + ((dividend_lo >> i) & 1); + if(remainder >= divisor || overflow) + { + remainder -= divisor; + quotient++; + } + } + + if(BIT_B(word2)) /* signed */ + { + if(quotient > 0x7fffffff) + { + FLAG_V = VFLAG_SET; + return; + } + if(dividend_neg) + { + remainder = (uint)MASK_OUT_ABOVE_32(-(sint)remainder); + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + if(divisor_neg) + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + + /* long / long: long quotient, maybe long remainder */ + if(BIT_B(word2)) /* signed */ + { + /* Special case in divide */ + if(dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + REG_D[(word2 >> 12) & 7] = 0x80000000; + REG_D[word2 & 7] = 0; + return; + } + REG_D[word2 & 7] = MAKE_INT_32(dividend_lo) % MAKE_INT_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MAKE_INT_32(dividend_lo) / MAKE_INT_32(divisor); + } + else + { + REG_D[word2 & 7] = MASK_OUT_ABOVE_32(dividend_lo) % MASK_OUT_ABOVE_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(dividend_lo) / MASK_OUT_ABOVE_32(divisor); + } + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#endif +} + + +void m68k_op_divl_32_aw(void) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 divisor = OPER_AW_32(); + uint64 dividend = 0; + uint64 quotient = 0; + uint64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D[word2 & 7]; + dividend <<= 32; + dividend |= REG_D[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)dividend / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)dividend % (sint64)((sint32)divisor)); + if((sint64)quotient != (sint64)((sint32)quotient)) + { + FLAG_V = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + FLAG_V = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)((sint32)dividend) / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)((sint32)dividend) % (sint64)((sint32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint divisor = OPER_AW_32(); + uint dividend_hi = REG_D[word2 & 7]; + uint dividend_lo = REG_D[(word2 >> 12) & 7]; + uint quotient = 0; + uint remainder = 0; + uint dividend_neg = 0; + uint divisor_neg = 0; + sint i; + uint overflow; + + if(divisor != 0) + { + /* quad / long : long quotient, long remainder */ + if(BIT_A(word2)) + { + if(BIT_B(word2)) /* signed */ + { + /* special case in signed divide */ + if(dividend_hi == 0 && dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + REG_D[word2 & 7] = 0; + REG_D[(word2 >> 12) & 7] = 0x80000000; + + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + if(GET_MSB_32(dividend_hi)) + { + dividend_neg = 1; + dividend_hi = (uint)MASK_OUT_ABOVE_32((-(sint)dividend_hi) - (dividend_lo != 0)); + dividend_lo = (uint)MASK_OUT_ABOVE_32(-(sint)dividend_lo); + } + if(GET_MSB_32(divisor)) + { + divisor_neg = 1; + divisor = (uint)MASK_OUT_ABOVE_32(-(sint)divisor); + + } + } + + /* if the upper long is greater than the divisor, we're overflowing. */ + if(dividend_hi >= divisor) + { + FLAG_V = VFLAG_SET; + return; + } + + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + remainder = (remainder << 1) + ((dividend_hi >> i) & 1); + if(remainder >= divisor) + { + remainder -= divisor; + quotient++; + } + } + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + overflow = GET_MSB_32(remainder); + remainder = (remainder << 1) + ((dividend_lo >> i) & 1); + if(remainder >= divisor || overflow) + { + remainder -= divisor; + quotient++; + } + } + + if(BIT_B(word2)) /* signed */ + { + if(quotient > 0x7fffffff) + { + FLAG_V = VFLAG_SET; + return; + } + if(dividend_neg) + { + remainder = (uint)MASK_OUT_ABOVE_32(-(sint)remainder); + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + if(divisor_neg) + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + + /* long / long: long quotient, maybe long remainder */ + if(BIT_B(word2)) /* signed */ + { + /* Special case in divide */ + if(dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + REG_D[(word2 >> 12) & 7] = 0x80000000; + REG_D[word2 & 7] = 0; + return; + } + REG_D[word2 & 7] = MAKE_INT_32(dividend_lo) % MAKE_INT_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MAKE_INT_32(dividend_lo) / MAKE_INT_32(divisor); + } + else + { + REG_D[word2 & 7] = MASK_OUT_ABOVE_32(dividend_lo) % MASK_OUT_ABOVE_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(dividend_lo) / MASK_OUT_ABOVE_32(divisor); + } + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#endif +} + + +void m68k_op_divl_32_al(void) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 divisor = OPER_AL_32(); + uint64 dividend = 0; + uint64 quotient = 0; + uint64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D[word2 & 7]; + dividend <<= 32; + dividend |= REG_D[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)dividend / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)dividend % (sint64)((sint32)divisor)); + if((sint64)quotient != (sint64)((sint32)quotient)) + { + FLAG_V = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + FLAG_V = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)((sint32)dividend) / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)((sint32)dividend) % (sint64)((sint32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint divisor = OPER_AL_32(); + uint dividend_hi = REG_D[word2 & 7]; + uint dividend_lo = REG_D[(word2 >> 12) & 7]; + uint quotient = 0; + uint remainder = 0; + uint dividend_neg = 0; + uint divisor_neg = 0; + sint i; + uint overflow; + + if(divisor != 0) + { + /* quad / long : long quotient, long remainder */ + if(BIT_A(word2)) + { + if(BIT_B(word2)) /* signed */ + { + /* special case in signed divide */ + if(dividend_hi == 0 && dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + REG_D[word2 & 7] = 0; + REG_D[(word2 >> 12) & 7] = 0x80000000; + + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + if(GET_MSB_32(dividend_hi)) + { + dividend_neg = 1; + dividend_hi = (uint)MASK_OUT_ABOVE_32((-(sint)dividend_hi) - (dividend_lo != 0)); + dividend_lo = (uint)MASK_OUT_ABOVE_32(-(sint)dividend_lo); + } + if(GET_MSB_32(divisor)) + { + divisor_neg = 1; + divisor = (uint)MASK_OUT_ABOVE_32(-(sint)divisor); + + } + } + + /* if the upper long is greater than the divisor, we're overflowing. */ + if(dividend_hi >= divisor) + { + FLAG_V = VFLAG_SET; + return; + } + + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + remainder = (remainder << 1) + ((dividend_hi >> i) & 1); + if(remainder >= divisor) + { + remainder -= divisor; + quotient++; + } + } + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + overflow = GET_MSB_32(remainder); + remainder = (remainder << 1) + ((dividend_lo >> i) & 1); + if(remainder >= divisor || overflow) + { + remainder -= divisor; + quotient++; + } + } + + if(BIT_B(word2)) /* signed */ + { + if(quotient > 0x7fffffff) + { + FLAG_V = VFLAG_SET; + return; + } + if(dividend_neg) + { + remainder = (uint)MASK_OUT_ABOVE_32(-(sint)remainder); + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + if(divisor_neg) + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + + /* long / long: long quotient, maybe long remainder */ + if(BIT_B(word2)) /* signed */ + { + /* Special case in divide */ + if(dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + REG_D[(word2 >> 12) & 7] = 0x80000000; + REG_D[word2 & 7] = 0; + return; + } + REG_D[word2 & 7] = MAKE_INT_32(dividend_lo) % MAKE_INT_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MAKE_INT_32(dividend_lo) / MAKE_INT_32(divisor); + } + else + { + REG_D[word2 & 7] = MASK_OUT_ABOVE_32(dividend_lo) % MASK_OUT_ABOVE_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(dividend_lo) / MASK_OUT_ABOVE_32(divisor); + } + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#endif +} + + +void m68k_op_divl_32_pcdi(void) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 divisor = OPER_PCDI_32(); + uint64 dividend = 0; + uint64 quotient = 0; + uint64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D[word2 & 7]; + dividend <<= 32; + dividend |= REG_D[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)dividend / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)dividend % (sint64)((sint32)divisor)); + if((sint64)quotient != (sint64)((sint32)quotient)) + { + FLAG_V = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + FLAG_V = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)((sint32)dividend) / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)((sint32)dividend) % (sint64)((sint32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint divisor = OPER_PCDI_32(); + uint dividend_hi = REG_D[word2 & 7]; + uint dividend_lo = REG_D[(word2 >> 12) & 7]; + uint quotient = 0; + uint remainder = 0; + uint dividend_neg = 0; + uint divisor_neg = 0; + sint i; + uint overflow; + + if(divisor != 0) + { + /* quad / long : long quotient, long remainder */ + if(BIT_A(word2)) + { + if(BIT_B(word2)) /* signed */ + { + /* special case in signed divide */ + if(dividend_hi == 0 && dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + REG_D[word2 & 7] = 0; + REG_D[(word2 >> 12) & 7] = 0x80000000; + + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + if(GET_MSB_32(dividend_hi)) + { + dividend_neg = 1; + dividend_hi = (uint)MASK_OUT_ABOVE_32((-(sint)dividend_hi) - (dividend_lo != 0)); + dividend_lo = (uint)MASK_OUT_ABOVE_32(-(sint)dividend_lo); + } + if(GET_MSB_32(divisor)) + { + divisor_neg = 1; + divisor = (uint)MASK_OUT_ABOVE_32(-(sint)divisor); + + } + } + + /* if the upper long is greater than the divisor, we're overflowing. */ + if(dividend_hi >= divisor) + { + FLAG_V = VFLAG_SET; + return; + } + + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + remainder = (remainder << 1) + ((dividend_hi >> i) & 1); + if(remainder >= divisor) + { + remainder -= divisor; + quotient++; + } + } + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + overflow = GET_MSB_32(remainder); + remainder = (remainder << 1) + ((dividend_lo >> i) & 1); + if(remainder >= divisor || overflow) + { + remainder -= divisor; + quotient++; + } + } + + if(BIT_B(word2)) /* signed */ + { + if(quotient > 0x7fffffff) + { + FLAG_V = VFLAG_SET; + return; + } + if(dividend_neg) + { + remainder = (uint)MASK_OUT_ABOVE_32(-(sint)remainder); + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + if(divisor_neg) + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + + /* long / long: long quotient, maybe long remainder */ + if(BIT_B(word2)) /* signed */ + { + /* Special case in divide */ + if(dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + REG_D[(word2 >> 12) & 7] = 0x80000000; + REG_D[word2 & 7] = 0; + return; + } + REG_D[word2 & 7] = MAKE_INT_32(dividend_lo) % MAKE_INT_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MAKE_INT_32(dividend_lo) / MAKE_INT_32(divisor); + } + else + { + REG_D[word2 & 7] = MASK_OUT_ABOVE_32(dividend_lo) % MASK_OUT_ABOVE_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(dividend_lo) / MASK_OUT_ABOVE_32(divisor); + } + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#endif +} + + +void m68k_op_divl_32_pcix(void) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 divisor = OPER_PCIX_32(); + uint64 dividend = 0; + uint64 quotient = 0; + uint64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D[word2 & 7]; + dividend <<= 32; + dividend |= REG_D[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)dividend / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)dividend % (sint64)((sint32)divisor)); + if((sint64)quotient != (sint64)((sint32)quotient)) + { + FLAG_V = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + FLAG_V = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)((sint32)dividend) / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)((sint32)dividend) % (sint64)((sint32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint divisor = OPER_PCIX_32(); + uint dividend_hi = REG_D[word2 & 7]; + uint dividend_lo = REG_D[(word2 >> 12) & 7]; + uint quotient = 0; + uint remainder = 0; + uint dividend_neg = 0; + uint divisor_neg = 0; + sint i; + uint overflow; + + if(divisor != 0) + { + /* quad / long : long quotient, long remainder */ + if(BIT_A(word2)) + { + if(BIT_B(word2)) /* signed */ + { + /* special case in signed divide */ + if(dividend_hi == 0 && dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + REG_D[word2 & 7] = 0; + REG_D[(word2 >> 12) & 7] = 0x80000000; + + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + if(GET_MSB_32(dividend_hi)) + { + dividend_neg = 1; + dividend_hi = (uint)MASK_OUT_ABOVE_32((-(sint)dividend_hi) - (dividend_lo != 0)); + dividend_lo = (uint)MASK_OUT_ABOVE_32(-(sint)dividend_lo); + } + if(GET_MSB_32(divisor)) + { + divisor_neg = 1; + divisor = (uint)MASK_OUT_ABOVE_32(-(sint)divisor); + + } + } + + /* if the upper long is greater than the divisor, we're overflowing. */ + if(dividend_hi >= divisor) + { + FLAG_V = VFLAG_SET; + return; + } + + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + remainder = (remainder << 1) + ((dividend_hi >> i) & 1); + if(remainder >= divisor) + { + remainder -= divisor; + quotient++; + } + } + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + overflow = GET_MSB_32(remainder); + remainder = (remainder << 1) + ((dividend_lo >> i) & 1); + if(remainder >= divisor || overflow) + { + remainder -= divisor; + quotient++; + } + } + + if(BIT_B(word2)) /* signed */ + { + if(quotient > 0x7fffffff) + { + FLAG_V = VFLAG_SET; + return; + } + if(dividend_neg) + { + remainder = (uint)MASK_OUT_ABOVE_32(-(sint)remainder); + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + if(divisor_neg) + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + + /* long / long: long quotient, maybe long remainder */ + if(BIT_B(word2)) /* signed */ + { + /* Special case in divide */ + if(dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + REG_D[(word2 >> 12) & 7] = 0x80000000; + REG_D[word2 & 7] = 0; + return; + } + REG_D[word2 & 7] = MAKE_INT_32(dividend_lo) % MAKE_INT_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MAKE_INT_32(dividend_lo) / MAKE_INT_32(divisor); + } + else + { + REG_D[word2 & 7] = MASK_OUT_ABOVE_32(dividend_lo) % MASK_OUT_ABOVE_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(dividend_lo) / MASK_OUT_ABOVE_32(divisor); + } + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#endif +} + + +void m68k_op_divl_32_i(void) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 divisor = OPER_I_32(); + uint64 dividend = 0; + uint64 quotient = 0; + uint64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D[word2 & 7]; + dividend <<= 32; + dividend |= REG_D[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)dividend / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)dividend % (sint64)((sint32)divisor)); + if((sint64)quotient != (sint64)((sint32)quotient)) + { + FLAG_V = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + FLAG_V = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (uint64)((sint64)((sint32)dividend) / (sint64)((sint32)divisor)); + remainder = (uint64)((sint64)((sint32)dividend) % (sint64)((sint32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint divisor = OPER_I_32(); + uint dividend_hi = REG_D[word2 & 7]; + uint dividend_lo = REG_D[(word2 >> 12) & 7]; + uint quotient = 0; + uint remainder = 0; + uint dividend_neg = 0; + uint divisor_neg = 0; + sint i; + uint overflow; + + if(divisor != 0) + { + /* quad / long : long quotient, long remainder */ + if(BIT_A(word2)) + { + if(BIT_B(word2)) /* signed */ + { + /* special case in signed divide */ + if(dividend_hi == 0 && dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + REG_D[word2 & 7] = 0; + REG_D[(word2 >> 12) & 7] = 0x80000000; + + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + if(GET_MSB_32(dividend_hi)) + { + dividend_neg = 1; + dividend_hi = (uint)MASK_OUT_ABOVE_32((-(sint)dividend_hi) - (dividend_lo != 0)); + dividend_lo = (uint)MASK_OUT_ABOVE_32(-(sint)dividend_lo); + } + if(GET_MSB_32(divisor)) + { + divisor_neg = 1; + divisor = (uint)MASK_OUT_ABOVE_32(-(sint)divisor); + + } + } + + /* if the upper long is greater than the divisor, we're overflowing. */ + if(dividend_hi >= divisor) + { + FLAG_V = VFLAG_SET; + return; + } + + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + remainder = (remainder << 1) + ((dividend_hi >> i) & 1); + if(remainder >= divisor) + { + remainder -= divisor; + quotient++; + } + } + for(i = 31; i >= 0; i--) + { + quotient <<= 1; + overflow = GET_MSB_32(remainder); + remainder = (remainder << 1) + ((dividend_lo >> i) & 1); + if(remainder >= divisor || overflow) + { + remainder -= divisor; + quotient++; + } + } + + if(BIT_B(word2)) /* signed */ + { + if(quotient > 0x7fffffff) + { + FLAG_V = VFLAG_SET; + return; + } + if(dividend_neg) + { + remainder = (uint)MASK_OUT_ABOVE_32(-(sint)remainder); + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + if(divisor_neg) + quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); + } + + REG_D[word2 & 7] = remainder; + REG_D[(word2 >> 12) & 7] = quotient; + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + + /* long / long: long quotient, maybe long remainder */ + if(BIT_B(word2)) /* signed */ + { + /* Special case in divide */ + if(dividend_lo == 0x80000000 && divisor == 0xffffffff) + { + FLAG_N = NFLAG_SET; + FLAG_Z = ZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + REG_D[(word2 >> 12) & 7] = 0x80000000; + REG_D[word2 & 7] = 0; + return; + } + REG_D[word2 & 7] = MAKE_INT_32(dividend_lo) % MAKE_INT_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MAKE_INT_32(dividend_lo) / MAKE_INT_32(divisor); + } + else + { + REG_D[word2 & 7] = MASK_OUT_ABOVE_32(dividend_lo) % MASK_OUT_ABOVE_32(divisor); + quotient = REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(dividend_lo) / MASK_OUT_ABOVE_32(divisor); + } + + FLAG_N = NFLAG_32(quotient); + FLAG_Z = quotient; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(); + +#endif +} + + +void m68k_op_eor_8_d(void) +{ + uint res = MASK_OUT_ABOVE_8(DY ^= MASK_OUT_ABOVE_8(DX)); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_8_ai(void) +{ + uint ea = EA_AY_AI_8(); + uint res = MASK_OUT_ABOVE_8(DX ^ m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_8_pi(void) +{ + uint ea = EA_AY_PI_8(); + uint res = MASK_OUT_ABOVE_8(DX ^ m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_8_pi7(void) +{ + uint ea = EA_A7_PI_8(); + uint res = MASK_OUT_ABOVE_8(DX ^ m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_8_pd(void) +{ + uint ea = EA_AY_PD_8(); + uint res = MASK_OUT_ABOVE_8(DX ^ m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_8_pd7(void) +{ + uint ea = EA_A7_PD_8(); + uint res = MASK_OUT_ABOVE_8(DX ^ m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_8_di(void) +{ + uint ea = EA_AY_DI_8(); + uint res = MASK_OUT_ABOVE_8(DX ^ m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_8_ix(void) +{ + uint ea = EA_AY_IX_8(); + uint res = MASK_OUT_ABOVE_8(DX ^ m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_8_aw(void) +{ + uint ea = EA_AW_8(); + uint res = MASK_OUT_ABOVE_8(DX ^ m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_8_al(void) +{ + uint ea = EA_AL_8(); + uint res = MASK_OUT_ABOVE_8(DX ^ m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_16_d(void) +{ + uint res = MASK_OUT_ABOVE_16(DY ^= MASK_OUT_ABOVE_16(DX)); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_16_ai(void) +{ + uint ea = EA_AY_AI_16(); + uint res = MASK_OUT_ABOVE_16(DX ^ m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_16_pi(void) +{ + uint ea = EA_AY_PI_16(); + uint res = MASK_OUT_ABOVE_16(DX ^ m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_16_pd(void) +{ + uint ea = EA_AY_PD_16(); + uint res = MASK_OUT_ABOVE_16(DX ^ m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_16_di(void) +{ + uint ea = EA_AY_DI_16(); + uint res = MASK_OUT_ABOVE_16(DX ^ m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_16_ix(void) +{ + uint ea = EA_AY_IX_16(); + uint res = MASK_OUT_ABOVE_16(DX ^ m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_16_aw(void) +{ + uint ea = EA_AW_16(); + uint res = MASK_OUT_ABOVE_16(DX ^ m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_16_al(void) +{ + uint ea = EA_AL_16(); + uint res = MASK_OUT_ABOVE_16(DX ^ m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_32_d(void) +{ + uint res = DY ^= DX; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_32_ai(void) +{ + uint ea = EA_AY_AI_32(); + uint res = DX ^ m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_32_pi(void) +{ + uint ea = EA_AY_PI_32(); + uint res = DX ^ m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_32_pd(void) +{ + uint ea = EA_AY_PD_32(); + uint res = DX ^ m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_32_di(void) +{ + uint ea = EA_AY_DI_32(); + uint res = DX ^ m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_32_ix(void) +{ + uint ea = EA_AY_IX_32(); + uint res = DX ^ m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_32_aw(void) +{ + uint ea = EA_AW_32(); + uint res = DX ^ m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eor_32_al(void) +{ + uint ea = EA_AL_32(); + uint res = DX ^ m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_8_d(void) +{ + uint res = MASK_OUT_ABOVE_8(DY ^= OPER_I_8()); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_8_ai(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_AI_8(); + uint res = src ^ m68ki_read_8(ea); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_8_pi(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_PI_8(); + uint res = src ^ m68ki_read_8(ea); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_8_pi7(void) +{ + uint src = OPER_I_8(); + uint ea = EA_A7_PI_8(); + uint res = src ^ m68ki_read_8(ea); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_8_pd(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_PD_8(); + uint res = src ^ m68ki_read_8(ea); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_8_pd7(void) +{ + uint src = OPER_I_8(); + uint ea = EA_A7_PD_8(); + uint res = src ^ m68ki_read_8(ea); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_8_di(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_DI_8(); + uint res = src ^ m68ki_read_8(ea); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_8_ix(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_IX_8(); + uint res = src ^ m68ki_read_8(ea); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_8_aw(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AW_8(); + uint res = src ^ m68ki_read_8(ea); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_8_al(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AL_8(); + uint res = src ^ m68ki_read_8(ea); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_16_d(void) +{ + uint res = MASK_OUT_ABOVE_16(DY ^= OPER_I_16()); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_16_ai(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_AI_16(); + uint res = src ^ m68ki_read_16(ea); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_16_pi(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_PI_16(); + uint res = src ^ m68ki_read_16(ea); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_16_pd(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_PD_16(); + uint res = src ^ m68ki_read_16(ea); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_16_di(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_DI_16(); + uint res = src ^ m68ki_read_16(ea); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_16_ix(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_IX_16(); + uint res = src ^ m68ki_read_16(ea); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_16_aw(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AW_16(); + uint res = src ^ m68ki_read_16(ea); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_16_al(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AL_16(); + uint res = src ^ m68ki_read_16(ea); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_32_d(void) +{ + uint res = DY ^= OPER_I_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_32_ai(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_AI_32(); + uint res = src ^ m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_32_pi(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_PI_32(); + uint res = src ^ m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_32_pd(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_PD_32(); + uint res = src ^ m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_32_di(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_DI_32(); + uint res = src ^ m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_32_ix(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_IX_32(); + uint res = src ^ m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_32_aw(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AW_32(); + uint res = src ^ m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_32_al(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AL_32(); + uint res = src ^ m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_eori_16_toc(void) +{ + m68ki_set_ccr(m68ki_get_ccr() ^ OPER_I_16()); +} + + +void m68k_op_eori_16_tos(void) +{ + if(FLAG_S) + { + uint src = OPER_I_16(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr(m68ki_get_sr() ^ src); + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_exg_32_dd(void) +{ + uint* reg_a = &DX; + uint* reg_b = &DY; + uint tmp = *reg_a; + *reg_a = *reg_b; + *reg_b = tmp; +} + + +void m68k_op_exg_32_aa(void) +{ + uint* reg_a = &AX; + uint* reg_b = &AY; + uint tmp = *reg_a; + *reg_a = *reg_b; + *reg_b = tmp; +} + + +void m68k_op_exg_32_da(void) +{ + uint* reg_a = &DX; + uint* reg_b = &AY; + uint tmp = *reg_a; + *reg_a = *reg_b; + *reg_b = tmp; +} + + +void m68k_op_ext_16(void) +{ + uint* r_dst = &DY; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | MASK_OUT_ABOVE_8(*r_dst) | (GET_MSB_8(*r_dst) ? 0xff00 : 0); + + FLAG_N = NFLAG_16(*r_dst); + FLAG_Z = MASK_OUT_ABOVE_16(*r_dst); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_ext_32(void) +{ + uint* r_dst = &DY; + + *r_dst = MASK_OUT_ABOVE_16(*r_dst) | (GET_MSB_16(*r_dst) ? 0xffff0000 : 0); + + FLAG_N = NFLAG_32(*r_dst); + FLAG_Z = *r_dst; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_extb_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint* r_dst = &DY; + + *r_dst = MASK_OUT_ABOVE_8(*r_dst) | (GET_MSB_8(*r_dst) ? 0xffffff00 : 0); + + FLAG_N = NFLAG_32(*r_dst); + FLAG_Z = *r_dst; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_illegal(void) +{ + m68ki_exception_illegal(); +} + + +void m68k_op_jmp_32_ai(void) +{ + m68ki_jump(EA_AY_AI_32()); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(REG_PC == REG_PPC) + USE_ALL_CYCLES(); +} + + +void m68k_op_jmp_32_di(void) +{ + m68ki_jump(EA_AY_DI_32()); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(REG_PC == REG_PPC) + USE_ALL_CYCLES(); +} + + +void m68k_op_jmp_32_ix(void) +{ + m68ki_jump(EA_AY_IX_32()); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(REG_PC == REG_PPC) + USE_ALL_CYCLES(); +} + + +void m68k_op_jmp_32_aw(void) +{ + m68ki_jump(EA_AW_32()); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(REG_PC == REG_PPC) + USE_ALL_CYCLES(); +} + + +void m68k_op_jmp_32_al(void) +{ + m68ki_jump(EA_AL_32()); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(REG_PC == REG_PPC) + USE_ALL_CYCLES(); +} + + +void m68k_op_jmp_32_pcdi(void) +{ + m68ki_jump(EA_PCDI_32()); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(REG_PC == REG_PPC) + USE_ALL_CYCLES(); +} + + +void m68k_op_jmp_32_pcix(void) +{ + m68ki_jump(EA_PCIX_32()); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(REG_PC == REG_PPC) + USE_ALL_CYCLES(); +} + + +void m68k_op_jsr_32_ai(void) +{ + uint ea = EA_AY_AI_32(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32(MAKE_INT_24(REG_PC)); // notaz: Cyclone can't handle 32bit PC and I neet to debug it + m68ki_jump(ea); +} + + +void m68k_op_jsr_32_di(void) +{ + uint ea = EA_AY_DI_32(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32(MAKE_INT_24(REG_PC)); // notaz: Cyclone can't handle 32bit PC and I neet to debug it + m68ki_jump(ea); +} + + +void m68k_op_jsr_32_ix(void) +{ + uint ea = EA_AY_IX_32(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32(MAKE_INT_24(REG_PC)); // notaz: Cyclone can't handle 32bit PC and I neet to debug it + m68ki_jump(ea); +} + + +void m68k_op_jsr_32_aw(void) +{ + uint ea = EA_AW_32(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32(MAKE_INT_24(REG_PC)); // notaz: Cyclone can't handle 32bit PC and I neet to debug it + m68ki_jump(ea); +} + + +void m68k_op_jsr_32_al(void) +{ + uint ea = EA_AL_32(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32(MAKE_INT_24(REG_PC)); // notaz: Cyclone can't handle 32bit PC and I neet to debug it + m68ki_jump(ea); +} + + +void m68k_op_jsr_32_pcdi(void) +{ + uint ea = EA_PCDI_32(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32(MAKE_INT_24(REG_PC)); // notaz: Cyclone can't handle 32bit PC and I neet to debug it + m68ki_jump(ea); +} + + +void m68k_op_jsr_32_pcix(void) +{ + uint ea = EA_PCIX_32(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32(MAKE_INT_24(REG_PC)); // notaz: Cyclone can't handle 32bit PC and I neet to debug it + m68ki_jump(ea); +} + + +void m68k_op_lea_32_ai(void) +{ + AX = EA_AY_AI_32(); +} + + +void m68k_op_lea_32_di(void) +{ + AX = EA_AY_DI_32(); +} + + +void m68k_op_lea_32_ix(void) +{ + AX = EA_AY_IX_32(); +} + + +void m68k_op_lea_32_aw(void) +{ + AX = EA_AW_32(); +} + + +void m68k_op_lea_32_al(void) +{ + AX = EA_AL_32(); +} + + +void m68k_op_lea_32_pcdi(void) +{ + AX = EA_PCDI_32(); +} + + +void m68k_op_lea_32_pcix(void) +{ + AX = EA_PCIX_32(); +} + + +void m68k_op_link_16_a7(void) +{ + REG_A[7] -= 4; + m68ki_write_32(REG_A[7], REG_A[7]); + REG_A[7] = MASK_OUT_ABOVE_32(REG_A[7] + MAKE_INT_16(OPER_I_16())); +} + + +void m68k_op_link_16(void) +{ + uint* r_dst = &AY; + + m68ki_push_32(*r_dst); + *r_dst = REG_A[7]; + REG_A[7] = MASK_OUT_ABOVE_32(REG_A[7] + MAKE_INT_16(OPER_I_16())); +} + + +void m68k_op_link_32_a7(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + REG_A[7] -= 4; + m68ki_write_32(REG_A[7], REG_A[7]); + REG_A[7] = MASK_OUT_ABOVE_32(REG_A[7] + OPER_I_32()); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_link_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint* r_dst = &AY; + + m68ki_push_32(*r_dst); + *r_dst = REG_A[7]; + REG_A[7] = MASK_OUT_ABOVE_32(REG_A[7] + OPER_I_32()); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_lsr_8_s(void) +{ + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_8(*r_dst); + uint res = src >> shift; + + if(shift != 0) + USE_CYCLES(shift<> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_16(*r_dst); + uint res = src >> shift; + + if(shift != 0) + USE_CYCLES(shift<> 9) - 1) & 7) + 1; + uint src = *r_dst; + uint res = src >> shift; + + if(shift != 0) + USE_CYCLES(shift<> shift; + + if(shift != 0) + { + USE_CYCLES(shift<> shift; + + if(shift != 0) + { + USE_CYCLES(shift<> (shift - 1))<<8; + FLAG_N = NFLAG_CLEAR; + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + *r_dst &= 0xffff0000; + FLAG_X = XFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_16(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_lsr_32_r(void) +{ + uint* r_dst = &DY; + uint shift = DX & 0x3f; + uint src = *r_dst; + uint res = src >> shift; + + if(shift != 0) + { + USE_CYCLES(shift<> (shift - 1))<<8; + FLAG_N = NFLAG_CLEAR; + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + *r_dst = 0; + FLAG_X = FLAG_C = (shift == 32 ? GET_MSB_32(src)>>23 : 0); + FLAG_N = NFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_32(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_lsr_16_ai(void) +{ + uint ea = EA_AY_AI_16(); + uint src = m68ki_read_16(ea); + uint res = src >> 1; + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_CLEAR; + FLAG_Z = res; + FLAG_C = FLAG_X = src << 8; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_lsr_16_pi(void) +{ + uint ea = EA_AY_PI_16(); + uint src = m68ki_read_16(ea); + uint res = src >> 1; + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_CLEAR; + FLAG_Z = res; + FLAG_C = FLAG_X = src << 8; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_lsr_16_pd(void) +{ + uint ea = EA_AY_PD_16(); + uint src = m68ki_read_16(ea); + uint res = src >> 1; + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_CLEAR; + FLAG_Z = res; + FLAG_C = FLAG_X = src << 8; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_lsr_16_di(void) +{ + uint ea = EA_AY_DI_16(); + uint src = m68ki_read_16(ea); + uint res = src >> 1; + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_CLEAR; + FLAG_Z = res; + FLAG_C = FLAG_X = src << 8; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_lsr_16_ix(void) +{ + uint ea = EA_AY_IX_16(); + uint src = m68ki_read_16(ea); + uint res = src >> 1; + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_CLEAR; + FLAG_Z = res; + FLAG_C = FLAG_X = src << 8; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_lsr_16_aw(void) +{ + uint ea = EA_AW_16(); + uint src = m68ki_read_16(ea); + uint res = src >> 1; + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_CLEAR; + FLAG_Z = res; + FLAG_C = FLAG_X = src << 8; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_lsr_16_al(void) +{ + uint ea = EA_AL_16(); + uint src = m68ki_read_16(ea); + uint res = src >> 1; + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_CLEAR; + FLAG_Z = res; + FLAG_C = FLAG_X = src << 8; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_lsl_8_s(void) +{ + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_8(*r_dst); + uint res = MASK_OUT_ABOVE_8(src << shift); + + if(shift != 0) + USE_CYCLES(shift<> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_16(*r_dst); + uint res = MASK_OUT_ABOVE_16(src << shift); + + if(shift != 0) + USE_CYCLES(shift<> (8-shift); + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_lsl_32_s(void) +{ + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint src = *r_dst; + uint res = MASK_OUT_ABOVE_32(src << shift); + + if(shift != 0) + USE_CYCLES(shift<> (24-shift); + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_lsl_8_r(void) +{ + uint* r_dst = &DY; + uint shift = DX & 0x3f; + uint src = MASK_OUT_ABOVE_8(*r_dst); + uint res = MASK_OUT_ABOVE_8(src << shift); + + if(shift != 0) + { + USE_CYCLES(shift<> 8; + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + *r_dst &= 0xffff0000; + FLAG_X = XFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_16(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_lsl_32_r(void) +{ + uint* r_dst = &DY; + uint shift = DX & 0x3f; + uint src = *r_dst; + uint res = MASK_OUT_ABOVE_32(src << shift); + + if(shift != 0) + { + USE_CYCLES(shift<> (32 - shift)) << 8; + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + *r_dst = 0; + FLAG_X = FLAG_C = ((shift == 32 ? src & 1 : 0))<<8; + FLAG_N = NFLAG_CLEAR; + FLAG_Z = ZFLAG_SET; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_32(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_lsl_16_ai(void) +{ + uint ea = EA_AY_AI_16(); + uint src = m68ki_read_16(ea); + uint res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_X = FLAG_C = src >> 7; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_lsl_16_pi(void) +{ + uint ea = EA_AY_PI_16(); + uint src = m68ki_read_16(ea); + uint res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_X = FLAG_C = src >> 7; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_lsl_16_pd(void) +{ + uint ea = EA_AY_PD_16(); + uint src = m68ki_read_16(ea); + uint res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_X = FLAG_C = src >> 7; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_lsl_16_di(void) +{ + uint ea = EA_AY_DI_16(); + uint src = m68ki_read_16(ea); + uint res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_X = FLAG_C = src >> 7; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_lsl_16_ix(void) +{ + uint ea = EA_AY_IX_16(); + uint src = m68ki_read_16(ea); + uint res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_X = FLAG_C = src >> 7; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_lsl_16_aw(void) +{ + uint ea = EA_AW_16(); + uint src = m68ki_read_16(ea); + uint res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_X = FLAG_C = src >> 7; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_lsl_16_al(void) +{ + uint ea = EA_AL_16(); + uint src = m68ki_read_16(ea); + uint res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_X = FLAG_C = src >> 7; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_move_8_d_d(void) +{ + uint res = MASK_OUT_ABOVE_8(DY); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_d_ai(void) +{ + uint res = OPER_AY_AI_8(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_d_pi(void) +{ + uint res = OPER_AY_PI_8(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_d_pi7(void) +{ + uint res = OPER_A7_PI_8(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_d_pd(void) +{ + uint res = OPER_AY_PD_8(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_d_pd7(void) +{ + uint res = OPER_A7_PD_8(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_d_di(void) +{ + uint res = OPER_AY_DI_8(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_d_ix(void) +{ + uint res = OPER_AY_IX_8(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_d_aw(void) +{ + uint res = OPER_AW_8(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_d_al(void) +{ + uint res = OPER_AL_8(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_d_pcdi(void) +{ + uint res = OPER_PCDI_8(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_d_pcix(void) +{ + uint res = OPER_PCIX_8(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_d_i(void) +{ + uint res = OPER_I_8(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ai_d(void) +{ + uint res = MASK_OUT_ABOVE_8(DY); + uint ea = EA_AX_AI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ai_ai(void) +{ + uint res = OPER_AY_AI_8(); + uint ea = EA_AX_AI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ai_pi(void) +{ + uint res = OPER_AY_PI_8(); + uint ea = EA_AX_AI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ai_pi7(void) +{ + uint res = OPER_A7_PI_8(); + uint ea = EA_AX_AI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ai_pd(void) +{ + uint res = OPER_AY_PD_8(); + uint ea = EA_AX_AI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ai_pd7(void) +{ + uint res = OPER_A7_PD_8(); + uint ea = EA_AX_AI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ai_di(void) +{ + uint res = OPER_AY_DI_8(); + uint ea = EA_AX_AI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ai_ix(void) +{ + uint res = OPER_AY_IX_8(); + uint ea = EA_AX_AI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ai_aw(void) +{ + uint res = OPER_AW_8(); + uint ea = EA_AX_AI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ai_al(void) +{ + uint res = OPER_AL_8(); + uint ea = EA_AX_AI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ai_pcdi(void) +{ + uint res = OPER_PCDI_8(); + uint ea = EA_AX_AI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ai_pcix(void) +{ + uint res = OPER_PCIX_8(); + uint ea = EA_AX_AI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ai_i(void) +{ + uint res = OPER_I_8(); + uint ea = EA_AX_AI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi7_d(void) +{ + uint res = MASK_OUT_ABOVE_8(DY); + uint ea = EA_A7_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi_d(void) +{ + uint res = MASK_OUT_ABOVE_8(DY); + uint ea = EA_AX_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi7_ai(void) +{ + uint res = OPER_AY_AI_8(); + uint ea = EA_A7_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi7_pi(void) +{ + uint res = OPER_AY_PI_8(); + uint ea = EA_A7_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi7_pi7(void) +{ + uint res = OPER_A7_PI_8(); + uint ea = EA_A7_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi7_pd(void) +{ + uint res = OPER_AY_PD_8(); + uint ea = EA_A7_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi7_pd7(void) +{ + uint res = OPER_A7_PD_8(); + uint ea = EA_A7_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi7_di(void) +{ + uint res = OPER_AY_DI_8(); + uint ea = EA_A7_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi7_ix(void) +{ + uint res = OPER_AY_IX_8(); + uint ea = EA_A7_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi7_aw(void) +{ + uint res = OPER_AW_8(); + uint ea = EA_A7_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi7_al(void) +{ + uint res = OPER_AL_8(); + uint ea = EA_A7_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi7_pcdi(void) +{ + uint res = OPER_PCDI_8(); + uint ea = EA_A7_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi7_pcix(void) +{ + uint res = OPER_PCIX_8(); + uint ea = EA_A7_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi7_i(void) +{ + uint res = OPER_I_8(); + uint ea = EA_A7_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi_ai(void) +{ + uint res = OPER_AY_AI_8(); + uint ea = EA_AX_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi_pi(void) +{ + uint res = OPER_AY_PI_8(); + uint ea = EA_AX_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi_pi7(void) +{ + uint res = OPER_A7_PI_8(); + uint ea = EA_AX_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi_pd(void) +{ + uint res = OPER_AY_PD_8(); + uint ea = EA_AX_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi_pd7(void) +{ + uint res = OPER_A7_PD_8(); + uint ea = EA_AX_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi_di(void) +{ + uint res = OPER_AY_DI_8(); + uint ea = EA_AX_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi_ix(void) +{ + uint res = OPER_AY_IX_8(); + uint ea = EA_AX_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi_aw(void) +{ + uint res = OPER_AW_8(); + uint ea = EA_AX_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi_al(void) +{ + uint res = OPER_AL_8(); + uint ea = EA_AX_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi_pcdi(void) +{ + uint res = OPER_PCDI_8(); + uint ea = EA_AX_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi_pcix(void) +{ + uint res = OPER_PCIX_8(); + uint ea = EA_AX_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pi_i(void) +{ + uint res = OPER_I_8(); + uint ea = EA_AX_PI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd7_d(void) +{ + uint res = MASK_OUT_ABOVE_8(DY); + uint ea = EA_A7_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd_d(void) +{ + uint res = MASK_OUT_ABOVE_8(DY); + uint ea = EA_AX_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd7_ai(void) +{ + uint res = OPER_AY_AI_8(); + uint ea = EA_A7_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd7_pi(void) +{ + uint res = OPER_AY_PI_8(); + uint ea = EA_A7_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd7_pi7(void) +{ + uint res = OPER_A7_PI_8(); + uint ea = EA_A7_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd7_pd(void) +{ + uint res = OPER_AY_PD_8(); + uint ea = EA_A7_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd7_pd7(void) +{ + uint res = OPER_A7_PD_8(); + uint ea = EA_A7_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd7_di(void) +{ + uint res = OPER_AY_DI_8(); + uint ea = EA_A7_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd7_ix(void) +{ + uint res = OPER_AY_IX_8(); + uint ea = EA_A7_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd7_aw(void) +{ + uint res = OPER_AW_8(); + uint ea = EA_A7_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd7_al(void) +{ + uint res = OPER_AL_8(); + uint ea = EA_A7_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd7_pcdi(void) +{ + uint res = OPER_PCDI_8(); + uint ea = EA_A7_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd7_pcix(void) +{ + uint res = OPER_PCIX_8(); + uint ea = EA_A7_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd7_i(void) +{ + uint res = OPER_I_8(); + uint ea = EA_A7_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd_ai(void) +{ + uint res = OPER_AY_AI_8(); + uint ea = EA_AX_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd_pi(void) +{ + uint res = OPER_AY_PI_8(); + uint ea = EA_AX_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd_pi7(void) +{ + uint res = OPER_A7_PI_8(); + uint ea = EA_AX_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd_pd(void) +{ + uint res = OPER_AY_PD_8(); + uint ea = EA_AX_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd_pd7(void) +{ + uint res = OPER_A7_PD_8(); + uint ea = EA_AX_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd_di(void) +{ + uint res = OPER_AY_DI_8(); + uint ea = EA_AX_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd_ix(void) +{ + uint res = OPER_AY_IX_8(); + uint ea = EA_AX_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd_aw(void) +{ + uint res = OPER_AW_8(); + uint ea = EA_AX_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd_al(void) +{ + uint res = OPER_AL_8(); + uint ea = EA_AX_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd_pcdi(void) +{ + uint res = OPER_PCDI_8(); + uint ea = EA_AX_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd_pcix(void) +{ + uint res = OPER_PCIX_8(); + uint ea = EA_AX_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_pd_i(void) +{ + uint res = OPER_I_8(); + uint ea = EA_AX_PD_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_di_d(void) +{ + uint res = MASK_OUT_ABOVE_8(DY); + uint ea = EA_AX_DI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_di_ai(void) +{ + uint res = OPER_AY_AI_8(); + uint ea = EA_AX_DI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_di_pi(void) +{ + uint res = OPER_AY_PI_8(); + uint ea = EA_AX_DI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_di_pi7(void) +{ + uint res = OPER_A7_PI_8(); + uint ea = EA_AX_DI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_di_pd(void) +{ + uint res = OPER_AY_PD_8(); + uint ea = EA_AX_DI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_di_pd7(void) +{ + uint res = OPER_A7_PD_8(); + uint ea = EA_AX_DI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_di_di(void) +{ + uint res = OPER_AY_DI_8(); + uint ea = EA_AX_DI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_di_ix(void) +{ + uint res = OPER_AY_IX_8(); + uint ea = EA_AX_DI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_di_aw(void) +{ + uint res = OPER_AW_8(); + uint ea = EA_AX_DI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_di_al(void) +{ + uint res = OPER_AL_8(); + uint ea = EA_AX_DI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_di_pcdi(void) +{ + uint res = OPER_PCDI_8(); + uint ea = EA_AX_DI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_di_pcix(void) +{ + uint res = OPER_PCIX_8(); + uint ea = EA_AX_DI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_di_i(void) +{ + uint res = OPER_I_8(); + uint ea = EA_AX_DI_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ix_d(void) +{ + uint res = MASK_OUT_ABOVE_8(DY); + uint ea = EA_AX_IX_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ix_ai(void) +{ + uint res = OPER_AY_AI_8(); + uint ea = EA_AX_IX_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ix_pi(void) +{ + uint res = OPER_AY_PI_8(); + uint ea = EA_AX_IX_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ix_pi7(void) +{ + uint res = OPER_A7_PI_8(); + uint ea = EA_AX_IX_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ix_pd(void) +{ + uint res = OPER_AY_PD_8(); + uint ea = EA_AX_IX_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ix_pd7(void) +{ + uint res = OPER_A7_PD_8(); + uint ea = EA_AX_IX_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ix_di(void) +{ + uint res = OPER_AY_DI_8(); + uint ea = EA_AX_IX_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ix_ix(void) +{ + uint res = OPER_AY_IX_8(); + uint ea = EA_AX_IX_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ix_aw(void) +{ + uint res = OPER_AW_8(); + uint ea = EA_AX_IX_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ix_al(void) +{ + uint res = OPER_AL_8(); + uint ea = EA_AX_IX_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ix_pcdi(void) +{ + uint res = OPER_PCDI_8(); + uint ea = EA_AX_IX_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ix_pcix(void) +{ + uint res = OPER_PCIX_8(); + uint ea = EA_AX_IX_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_ix_i(void) +{ + uint res = OPER_I_8(); + uint ea = EA_AX_IX_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_aw_d(void) +{ + uint res = MASK_OUT_ABOVE_8(DY); + uint ea = EA_AW_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_aw_ai(void) +{ + uint res = OPER_AY_AI_8(); + uint ea = EA_AW_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_aw_pi(void) +{ + uint res = OPER_AY_PI_8(); + uint ea = EA_AW_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_aw_pi7(void) +{ + uint res = OPER_A7_PI_8(); + uint ea = EA_AW_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_aw_pd(void) +{ + uint res = OPER_AY_PD_8(); + uint ea = EA_AW_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_aw_pd7(void) +{ + uint res = OPER_A7_PD_8(); + uint ea = EA_AW_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_aw_di(void) +{ + uint res = OPER_AY_DI_8(); + uint ea = EA_AW_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_aw_ix(void) +{ + uint res = OPER_AY_IX_8(); + uint ea = EA_AW_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_aw_aw(void) +{ + uint res = OPER_AW_8(); + uint ea = EA_AW_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_aw_al(void) +{ + uint res = OPER_AL_8(); + uint ea = EA_AW_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_aw_pcdi(void) +{ + uint res = OPER_PCDI_8(); + uint ea = EA_AW_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_aw_pcix(void) +{ + uint res = OPER_PCIX_8(); + uint ea = EA_AW_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_aw_i(void) +{ + uint res = OPER_I_8(); + uint ea = EA_AW_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_al_d(void) +{ + uint res = MASK_OUT_ABOVE_8(DY); + uint ea = EA_AL_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_al_ai(void) +{ + uint res = OPER_AY_AI_8(); + uint ea = EA_AL_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_al_pi(void) +{ + uint res = OPER_AY_PI_8(); + uint ea = EA_AL_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_al_pi7(void) +{ + uint res = OPER_A7_PI_8(); + uint ea = EA_AL_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_al_pd(void) +{ + uint res = OPER_AY_PD_8(); + uint ea = EA_AL_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_al_pd7(void) +{ + uint res = OPER_A7_PD_8(); + uint ea = EA_AL_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_al_di(void) +{ + uint res = OPER_AY_DI_8(); + uint ea = EA_AL_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_al_ix(void) +{ + uint res = OPER_AY_IX_8(); + uint ea = EA_AL_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_al_aw(void) +{ + uint res = OPER_AW_8(); + uint ea = EA_AL_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_al_al(void) +{ + uint res = OPER_AL_8(); + uint ea = EA_AL_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_al_pcdi(void) +{ + uint res = OPER_PCDI_8(); + uint ea = EA_AL_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_al_pcix(void) +{ + uint res = OPER_PCIX_8(); + uint ea = EA_AL_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_8_al_i(void) +{ + uint res = OPER_I_8(); + uint ea = EA_AL_8(); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_d_d(void) +{ + uint res = MASK_OUT_ABOVE_16(DY); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_d_a(void) +{ + uint res = MASK_OUT_ABOVE_16(AY); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_d_ai(void) +{ + uint res = OPER_AY_AI_16(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_d_pi(void) +{ + uint res = OPER_AY_PI_16(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_d_pd(void) +{ + uint res = OPER_AY_PD_16(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_d_di(void) +{ + uint res = OPER_AY_DI_16(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_d_ix(void) +{ + uint res = OPER_AY_IX_16(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_d_aw(void) +{ + uint res = OPER_AW_16(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_d_al(void) +{ + uint res = OPER_AL_16(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_d_pcdi(void) +{ + uint res = OPER_PCDI_16(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_d_pcix(void) +{ + uint res = OPER_PCIX_16(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_d_i(void) +{ + uint res = OPER_I_16(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_ai_d(void) +{ + uint res = MASK_OUT_ABOVE_16(DY); + uint ea = EA_AX_AI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_ai_a(void) +{ + uint res = MASK_OUT_ABOVE_16(AY); + uint ea = EA_AX_AI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_ai_ai(void) +{ + uint res = OPER_AY_AI_16(); + uint ea = EA_AX_AI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_ai_pi(void) +{ + uint res = OPER_AY_PI_16(); + uint ea = EA_AX_AI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_ai_pd(void) +{ + uint res = OPER_AY_PD_16(); + uint ea = EA_AX_AI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_ai_di(void) +{ + uint res = OPER_AY_DI_16(); + uint ea = EA_AX_AI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_ai_ix(void) +{ + uint res = OPER_AY_IX_16(); + uint ea = EA_AX_AI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_ai_aw(void) +{ + uint res = OPER_AW_16(); + uint ea = EA_AX_AI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_ai_al(void) +{ + uint res = OPER_AL_16(); + uint ea = EA_AX_AI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_ai_pcdi(void) +{ + uint res = OPER_PCDI_16(); + uint ea = EA_AX_AI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_ai_pcix(void) +{ + uint res = OPER_PCIX_16(); + uint ea = EA_AX_AI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_ai_i(void) +{ + uint res = OPER_I_16(); + uint ea = EA_AX_AI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_pi_d(void) +{ + uint res = MASK_OUT_ABOVE_16(DY); + uint ea = EA_AX_PI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_pi_a(void) +{ + uint res = MASK_OUT_ABOVE_16(AY); + uint ea = EA_AX_PI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_pi_ai(void) +{ + uint res = OPER_AY_AI_16(); + uint ea = EA_AX_PI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_pi_pi(void) +{ + uint res = OPER_AY_PI_16(); + uint ea = EA_AX_PI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_pi_pd(void) +{ + uint res = OPER_AY_PD_16(); + uint ea = EA_AX_PI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_pi_di(void) +{ + uint res = OPER_AY_DI_16(); + uint ea = EA_AX_PI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_pi_ix(void) +{ + uint res = OPER_AY_IX_16(); + uint ea = EA_AX_PI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_pi_aw(void) +{ + uint res = OPER_AW_16(); + uint ea = EA_AX_PI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_pi_al(void) +{ + uint res = OPER_AL_16(); + uint ea = EA_AX_PI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_pi_pcdi(void) +{ + uint res = OPER_PCDI_16(); + uint ea = EA_AX_PI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_pi_pcix(void) +{ + uint res = OPER_PCIX_16(); + uint ea = EA_AX_PI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_pi_i(void) +{ + uint res = OPER_I_16(); + uint ea = EA_AX_PI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_pd_d(void) +{ + uint res = MASK_OUT_ABOVE_16(DY); + uint ea = EA_AX_PD_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_pd_a(void) +{ + uint res = MASK_OUT_ABOVE_16(AY); + uint ea = EA_AX_PD_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_pd_ai(void) +{ + uint res = OPER_AY_AI_16(); + uint ea = EA_AX_PD_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_pd_pi(void) +{ + uint res = OPER_AY_PI_16(); + uint ea = EA_AX_PD_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_pd_pd(void) +{ + uint res = OPER_AY_PD_16(); + uint ea = EA_AX_PD_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_pd_di(void) +{ + uint res = OPER_AY_DI_16(); + uint ea = EA_AX_PD_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_pd_ix(void) +{ + uint res = OPER_AY_IX_16(); + uint ea = EA_AX_PD_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_pd_aw(void) +{ + uint res = OPER_AW_16(); + uint ea = EA_AX_PD_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_pd_al(void) +{ + uint res = OPER_AL_16(); + uint ea = EA_AX_PD_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_pd_pcdi(void) +{ + uint res = OPER_PCDI_16(); + uint ea = EA_AX_PD_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_pd_pcix(void) +{ + uint res = OPER_PCIX_16(); + uint ea = EA_AX_PD_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_pd_i(void) +{ + uint res = OPER_I_16(); + uint ea = EA_AX_PD_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_di_d(void) +{ + uint res = MASK_OUT_ABOVE_16(DY); + uint ea = EA_AX_DI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_di_a(void) +{ + uint res = MASK_OUT_ABOVE_16(AY); + uint ea = EA_AX_DI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_di_ai(void) +{ + uint res = OPER_AY_AI_16(); + uint ea = EA_AX_DI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_di_pi(void) +{ + uint res = OPER_AY_PI_16(); + uint ea = EA_AX_DI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_di_pd(void) +{ + uint res = OPER_AY_PD_16(); + uint ea = EA_AX_DI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_di_di(void) +{ + uint res = OPER_AY_DI_16(); + uint ea = EA_AX_DI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_di_ix(void) +{ + uint res = OPER_AY_IX_16(); + uint ea = EA_AX_DI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_di_aw(void) +{ + uint res = OPER_AW_16(); + uint ea = EA_AX_DI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_di_al(void) +{ + uint res = OPER_AL_16(); + uint ea = EA_AX_DI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_di_pcdi(void) +{ + uint res = OPER_PCDI_16(); + uint ea = EA_AX_DI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_di_pcix(void) +{ + uint res = OPER_PCIX_16(); + uint ea = EA_AX_DI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_di_i(void) +{ + uint res = OPER_I_16(); + uint ea = EA_AX_DI_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_ix_d(void) +{ + uint res = MASK_OUT_ABOVE_16(DY); + uint ea = EA_AX_IX_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_ix_a(void) +{ + uint res = MASK_OUT_ABOVE_16(AY); + uint ea = EA_AX_IX_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_ix_ai(void) +{ + uint res = OPER_AY_AI_16(); + uint ea = EA_AX_IX_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_ix_pi(void) +{ + uint res = OPER_AY_PI_16(); + uint ea = EA_AX_IX_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_ix_pd(void) +{ + uint res = OPER_AY_PD_16(); + uint ea = EA_AX_IX_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_ix_di(void) +{ + uint res = OPER_AY_DI_16(); + uint ea = EA_AX_IX_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_ix_ix(void) +{ + uint res = OPER_AY_IX_16(); + uint ea = EA_AX_IX_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_ix_aw(void) +{ + uint res = OPER_AW_16(); + uint ea = EA_AX_IX_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_ix_al(void) +{ + uint res = OPER_AL_16(); + uint ea = EA_AX_IX_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_ix_pcdi(void) +{ + uint res = OPER_PCDI_16(); + uint ea = EA_AX_IX_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_ix_pcix(void) +{ + uint res = OPER_PCIX_16(); + uint ea = EA_AX_IX_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_ix_i(void) +{ + uint res = OPER_I_16(); + uint ea = EA_AX_IX_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_aw_d(void) +{ + uint res = MASK_OUT_ABOVE_16(DY); + uint ea = EA_AW_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_aw_a(void) +{ + uint res = MASK_OUT_ABOVE_16(AY); + uint ea = EA_AW_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_aw_ai(void) +{ + uint res = OPER_AY_AI_16(); + uint ea = EA_AW_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_aw_pi(void) +{ + uint res = OPER_AY_PI_16(); + uint ea = EA_AW_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_aw_pd(void) +{ + uint res = OPER_AY_PD_16(); + uint ea = EA_AW_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_aw_di(void) +{ + uint res = OPER_AY_DI_16(); + uint ea = EA_AW_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_aw_ix(void) +{ + uint res = OPER_AY_IX_16(); + uint ea = EA_AW_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_aw_aw(void) +{ + uint res = OPER_AW_16(); + uint ea = EA_AW_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_aw_al(void) +{ + uint res = OPER_AL_16(); + uint ea = EA_AW_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_aw_pcdi(void) +{ + uint res = OPER_PCDI_16(); + uint ea = EA_AW_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_aw_pcix(void) +{ + uint res = OPER_PCIX_16(); + uint ea = EA_AW_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_aw_i(void) +{ + uint res = OPER_I_16(); + uint ea = EA_AW_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_al_d(void) +{ + uint res = MASK_OUT_ABOVE_16(DY); + uint ea = EA_AL_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_al_a(void) +{ + uint res = MASK_OUT_ABOVE_16(AY); + uint ea = EA_AL_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_al_ai(void) +{ + uint res = OPER_AY_AI_16(); + uint ea = EA_AL_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_al_pi(void) +{ + uint res = OPER_AY_PI_16(); + uint ea = EA_AL_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_al_pd(void) +{ + uint res = OPER_AY_PD_16(); + uint ea = EA_AL_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_al_di(void) +{ + uint res = OPER_AY_DI_16(); + uint ea = EA_AL_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_al_ix(void) +{ + uint res = OPER_AY_IX_16(); + uint ea = EA_AL_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_al_aw(void) +{ + uint res = OPER_AW_16(); + uint ea = EA_AL_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_al_al(void) +{ + uint res = OPER_AL_16(); + uint ea = EA_AL_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_al_pcdi(void) +{ + uint res = OPER_PCDI_16(); + uint ea = EA_AL_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_al_pcix(void) +{ + uint res = OPER_PCIX_16(); + uint ea = EA_AL_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_16_al_i(void) +{ + uint res = OPER_I_16(); + uint ea = EA_AL_16(); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_d_d(void) +{ + uint res = DY; + uint* r_dst = &DX; + + *r_dst = res; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_d_a(void) +{ + uint res = AY; + uint* r_dst = &DX; + + *r_dst = res; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_d_ai(void) +{ + uint res = OPER_AY_AI_32(); + uint* r_dst = &DX; + + *r_dst = res; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_d_pi(void) +{ + uint res = OPER_AY_PI_32(); + uint* r_dst = &DX; + + *r_dst = res; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_d_pd(void) +{ + uint res = OPER_AY_PD_32(); + uint* r_dst = &DX; + + *r_dst = res; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_d_di(void) +{ + uint res = OPER_AY_DI_32(); + uint* r_dst = &DX; + + *r_dst = res; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_d_ix(void) +{ + uint res = OPER_AY_IX_32(); + uint* r_dst = &DX; + + *r_dst = res; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_d_aw(void) +{ + uint res = OPER_AW_32(); + uint* r_dst = &DX; + + *r_dst = res; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_d_al(void) +{ + uint res = OPER_AL_32(); + uint* r_dst = &DX; + + *r_dst = res; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_d_pcdi(void) +{ + uint res = OPER_PCDI_32(); + uint* r_dst = &DX; + + *r_dst = res; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_d_pcix(void) +{ + uint res = OPER_PCIX_32(); + uint* r_dst = &DX; + + *r_dst = res; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_d_i(void) +{ + uint res = OPER_I_32(); + uint* r_dst = &DX; + + *r_dst = res; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_ai_d(void) +{ + uint res = DY; + uint ea = EA_AX_AI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_ai_a(void) +{ + uint res = AY; + uint ea = EA_AX_AI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_ai_ai(void) +{ + uint res = OPER_AY_AI_32(); + uint ea = EA_AX_AI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_ai_pi(void) +{ + uint res = OPER_AY_PI_32(); + uint ea = EA_AX_AI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_ai_pd(void) +{ + uint res = OPER_AY_PD_32(); + uint ea = EA_AX_AI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_ai_di(void) +{ + uint res = OPER_AY_DI_32(); + uint ea = EA_AX_AI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_ai_ix(void) +{ + uint res = OPER_AY_IX_32(); + uint ea = EA_AX_AI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_ai_aw(void) +{ + uint res = OPER_AW_32(); + uint ea = EA_AX_AI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_ai_al(void) +{ + uint res = OPER_AL_32(); + uint ea = EA_AX_AI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_ai_pcdi(void) +{ + uint res = OPER_PCDI_32(); + uint ea = EA_AX_AI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_ai_pcix(void) +{ + uint res = OPER_PCIX_32(); + uint ea = EA_AX_AI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_ai_i(void) +{ + uint res = OPER_I_32(); + uint ea = EA_AX_AI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_pi_d(void) +{ + uint res = DY; + uint ea = EA_AX_PI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_pi_a(void) +{ + uint res = AY; + uint ea = EA_AX_PI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_pi_ai(void) +{ + uint res = OPER_AY_AI_32(); + uint ea = EA_AX_PI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_pi_pi(void) +{ + uint res = OPER_AY_PI_32(); + uint ea = EA_AX_PI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_pi_pd(void) +{ + uint res = OPER_AY_PD_32(); + uint ea = EA_AX_PI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_pi_di(void) +{ + uint res = OPER_AY_DI_32(); + uint ea = EA_AX_PI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_pi_ix(void) +{ + uint res = OPER_AY_IX_32(); + uint ea = EA_AX_PI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_pi_aw(void) +{ + uint res = OPER_AW_32(); + uint ea = EA_AX_PI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_pi_al(void) +{ + uint res = OPER_AL_32(); + uint ea = EA_AX_PI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_pi_pcdi(void) +{ + uint res = OPER_PCDI_32(); + uint ea = EA_AX_PI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_pi_pcix(void) +{ + uint res = OPER_PCIX_32(); + uint ea = EA_AX_PI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_pi_i(void) +{ + uint res = OPER_I_32(); + uint ea = EA_AX_PI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_pd_d(void) +{ + uint res = DY; + uint ea = EA_AX_PD_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_pd_a(void) +{ + uint res = AY; + uint ea = EA_AX_PD_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_pd_ai(void) +{ + uint res = OPER_AY_AI_32(); + uint ea = EA_AX_PD_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_pd_pi(void) +{ + uint res = OPER_AY_PI_32(); + uint ea = EA_AX_PD_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_pd_pd(void) +{ + uint res = OPER_AY_PD_32(); + uint ea = EA_AX_PD_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_pd_di(void) +{ + uint res = OPER_AY_DI_32(); + uint ea = EA_AX_PD_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_pd_ix(void) +{ + uint res = OPER_AY_IX_32(); + uint ea = EA_AX_PD_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_pd_aw(void) +{ + uint res = OPER_AW_32(); + uint ea = EA_AX_PD_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_pd_al(void) +{ + uint res = OPER_AL_32(); + uint ea = EA_AX_PD_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_pd_pcdi(void) +{ + uint res = OPER_PCDI_32(); + uint ea = EA_AX_PD_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_pd_pcix(void) +{ + uint res = OPER_PCIX_32(); + uint ea = EA_AX_PD_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_pd_i(void) +{ + uint res = OPER_I_32(); + uint ea = EA_AX_PD_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_di_d(void) +{ + uint res = DY; + uint ea = EA_AX_DI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_di_a(void) +{ + uint res = AY; + uint ea = EA_AX_DI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_di_ai(void) +{ + uint res = OPER_AY_AI_32(); + uint ea = EA_AX_DI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_di_pi(void) +{ + uint res = OPER_AY_PI_32(); + uint ea = EA_AX_DI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_di_pd(void) +{ + uint res = OPER_AY_PD_32(); + uint ea = EA_AX_DI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_di_di(void) +{ + uint res = OPER_AY_DI_32(); + uint ea = EA_AX_DI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_di_ix(void) +{ + uint res = OPER_AY_IX_32(); + uint ea = EA_AX_DI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_di_aw(void) +{ + uint res = OPER_AW_32(); + uint ea = EA_AX_DI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_di_al(void) +{ + uint res = OPER_AL_32(); + uint ea = EA_AX_DI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_di_pcdi(void) +{ + uint res = OPER_PCDI_32(); + uint ea = EA_AX_DI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_di_pcix(void) +{ + uint res = OPER_PCIX_32(); + uint ea = EA_AX_DI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_di_i(void) +{ + uint res = OPER_I_32(); + uint ea = EA_AX_DI_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_ix_d(void) +{ + uint res = DY; + uint ea = EA_AX_IX_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_ix_a(void) +{ + uint res = AY; + uint ea = EA_AX_IX_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_ix_ai(void) +{ + uint res = OPER_AY_AI_32(); + uint ea = EA_AX_IX_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_ix_pi(void) +{ + uint res = OPER_AY_PI_32(); + uint ea = EA_AX_IX_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_ix_pd(void) +{ + uint res = OPER_AY_PD_32(); + uint ea = EA_AX_IX_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_ix_di(void) +{ + uint res = OPER_AY_DI_32(); + uint ea = EA_AX_IX_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_ix_ix(void) +{ + uint res = OPER_AY_IX_32(); + uint ea = EA_AX_IX_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_ix_aw(void) +{ + uint res = OPER_AW_32(); + uint ea = EA_AX_IX_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_ix_al(void) +{ + uint res = OPER_AL_32(); + uint ea = EA_AX_IX_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_ix_pcdi(void) +{ + uint res = OPER_PCDI_32(); + uint ea = EA_AX_IX_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_ix_pcix(void) +{ + uint res = OPER_PCIX_32(); + uint ea = EA_AX_IX_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_ix_i(void) +{ + uint res = OPER_I_32(); + uint ea = EA_AX_IX_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_aw_d(void) +{ + uint res = DY; + uint ea = EA_AW_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_aw_a(void) +{ + uint res = AY; + uint ea = EA_AW_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_aw_ai(void) +{ + uint res = OPER_AY_AI_32(); + uint ea = EA_AW_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_aw_pi(void) +{ + uint res = OPER_AY_PI_32(); + uint ea = EA_AW_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_aw_pd(void) +{ + uint res = OPER_AY_PD_32(); + uint ea = EA_AW_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_aw_di(void) +{ + uint res = OPER_AY_DI_32(); + uint ea = EA_AW_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_aw_ix(void) +{ + uint res = OPER_AY_IX_32(); + uint ea = EA_AW_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_aw_aw(void) +{ + uint res = OPER_AW_32(); + uint ea = EA_AW_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_aw_al(void) +{ + uint res = OPER_AL_32(); + uint ea = EA_AW_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_aw_pcdi(void) +{ + uint res = OPER_PCDI_32(); + uint ea = EA_AW_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_aw_pcix(void) +{ + uint res = OPER_PCIX_32(); + uint ea = EA_AW_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_aw_i(void) +{ + uint res = OPER_I_32(); + uint ea = EA_AW_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_al_d(void) +{ + uint res = DY; + uint ea = EA_AL_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_al_a(void) +{ + uint res = AY; + uint ea = EA_AL_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_al_ai(void) +{ + uint res = OPER_AY_AI_32(); + uint ea = EA_AL_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_al_pi(void) +{ + uint res = OPER_AY_PI_32(); + uint ea = EA_AL_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_al_pd(void) +{ + uint res = OPER_AY_PD_32(); + uint ea = EA_AL_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_al_di(void) +{ + uint res = OPER_AY_DI_32(); + uint ea = EA_AL_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_al_ix(void) +{ + uint res = OPER_AY_IX_32(); + uint ea = EA_AL_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_al_aw(void) +{ + uint res = OPER_AW_32(); + uint ea = EA_AL_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_al_al(void) +{ + uint res = OPER_AL_32(); + uint ea = EA_AL_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_al_pcdi(void) +{ + uint res = OPER_PCDI_32(); + uint ea = EA_AL_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_al_pcix(void) +{ + uint res = OPER_PCIX_32(); + uint ea = EA_AL_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move_32_al_i(void) +{ + uint res = OPER_I_32(); + uint ea = EA_AL_32(); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_movea_16_d(void) +{ + AX = MAKE_INT_16(DY); +} + + +void m68k_op_movea_16_a(void) +{ + AX = MAKE_INT_16(AY); +} + + +void m68k_op_movea_16_ai(void) +{ + AX = MAKE_INT_16(OPER_AY_AI_16()); +} + + +void m68k_op_movea_16_pi(void) +{ + AX = MAKE_INT_16(OPER_AY_PI_16()); +} + + +void m68k_op_movea_16_pd(void) +{ + AX = MAKE_INT_16(OPER_AY_PD_16()); +} + + +void m68k_op_movea_16_di(void) +{ + AX = MAKE_INT_16(OPER_AY_DI_16()); +} + + +void m68k_op_movea_16_ix(void) +{ + AX = MAKE_INT_16(OPER_AY_IX_16()); +} + + +void m68k_op_movea_16_aw(void) +{ + AX = MAKE_INT_16(OPER_AW_16()); +} + + +void m68k_op_movea_16_al(void) +{ + AX = MAKE_INT_16(OPER_AL_16()); +} + + +void m68k_op_movea_16_pcdi(void) +{ + AX = MAKE_INT_16(OPER_PCDI_16()); +} + + +void m68k_op_movea_16_pcix(void) +{ + AX = MAKE_INT_16(OPER_PCIX_16()); +} + + +void m68k_op_movea_16_i(void) +{ + AX = MAKE_INT_16(OPER_I_16()); +} + + +void m68k_op_movea_32_d(void) +{ + AX = DY; +} + + +void m68k_op_movea_32_a(void) +{ + AX = AY; +} + + +void m68k_op_movea_32_ai(void) +{ + AX = OPER_AY_AI_32(); +} + + +void m68k_op_movea_32_pi(void) +{ + AX = OPER_AY_PI_32(); +} + + +void m68k_op_movea_32_pd(void) +{ + AX = OPER_AY_PD_32(); +} + + +void m68k_op_movea_32_di(void) +{ + AX = OPER_AY_DI_32(); +} + + +void m68k_op_movea_32_ix(void) +{ + AX = OPER_AY_IX_32(); +} + + +void m68k_op_movea_32_aw(void) +{ + AX = OPER_AW_32(); +} + + +void m68k_op_movea_32_al(void) +{ + AX = OPER_AL_32(); +} + + +void m68k_op_movea_32_pcdi(void) +{ + AX = OPER_PCDI_32(); +} + + +void m68k_op_movea_32_pcix(void) +{ + AX = OPER_PCIX_32(); +} + + +void m68k_op_movea_32_i(void) +{ + AX = OPER_I_32(); +} + + +void m68k_op_move_16_frc_d(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + DY = MASK_OUT_BELOW_16(DY) | m68ki_get_ccr(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_move_16_frc_ai(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + m68ki_write_16(EA_AY_AI_16(), m68ki_get_ccr()); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_move_16_frc_pi(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + m68ki_write_16(EA_AY_PI_16(), m68ki_get_ccr()); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_move_16_frc_pd(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + m68ki_write_16(EA_AY_PD_16(), m68ki_get_ccr()); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_move_16_frc_di(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + m68ki_write_16(EA_AY_DI_16(), m68ki_get_ccr()); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_move_16_frc_ix(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + m68ki_write_16(EA_AY_IX_16(), m68ki_get_ccr()); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_move_16_frc_aw(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + m68ki_write_16(EA_AW_16(), m68ki_get_ccr()); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_move_16_frc_al(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + m68ki_write_16(EA_AL_16(), m68ki_get_ccr()); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_move_16_toc_d(void) +{ + m68ki_set_ccr(DY); +} + + +void m68k_op_move_16_toc_ai(void) +{ + m68ki_set_ccr(OPER_AY_AI_16()); +} + + +void m68k_op_move_16_toc_pi(void) +{ + m68ki_set_ccr(OPER_AY_PI_16()); +} + + +void m68k_op_move_16_toc_pd(void) +{ + m68ki_set_ccr(OPER_AY_PD_16()); +} + + +void m68k_op_move_16_toc_di(void) +{ + m68ki_set_ccr(OPER_AY_DI_16()); +} + + +void m68k_op_move_16_toc_ix(void) +{ + m68ki_set_ccr(OPER_AY_IX_16()); +} + + +void m68k_op_move_16_toc_aw(void) +{ + m68ki_set_ccr(OPER_AW_16()); +} + + +void m68k_op_move_16_toc_al(void) +{ + m68ki_set_ccr(OPER_AL_16()); +} + + +void m68k_op_move_16_toc_pcdi(void) +{ + m68ki_set_ccr(OPER_PCDI_16()); +} + + +void m68k_op_move_16_toc_pcix(void) +{ + m68ki_set_ccr(OPER_PCIX_16()); +} + + +void m68k_op_move_16_toc_i(void) +{ + m68ki_set_ccr(OPER_I_16()); +} + + +void m68k_op_move_16_frs_d(void) +{ + if(CPU_TYPE_IS_000(CPU_TYPE) || FLAG_S) /* NS990408 */ + { + DY = MASK_OUT_BELOW_16(DY) | m68ki_get_sr(); + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_move_16_frs_ai(void) +{ + if(CPU_TYPE_IS_000(CPU_TYPE) || FLAG_S) /* NS990408 */ + { + uint ea = EA_AY_AI_16(); + m68ki_write_16(ea, m68ki_get_sr()); + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_move_16_frs_pi(void) +{ + if(CPU_TYPE_IS_000(CPU_TYPE) || FLAG_S) /* NS990408 */ + { + uint ea = EA_AY_PI_16(); + m68ki_write_16(ea, m68ki_get_sr()); + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_move_16_frs_pd(void) +{ + if(CPU_TYPE_IS_000(CPU_TYPE) || FLAG_S) /* NS990408 */ + { + uint ea = EA_AY_PD_16(); + m68ki_write_16(ea, m68ki_get_sr()); + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_move_16_frs_di(void) +{ + if(CPU_TYPE_IS_000(CPU_TYPE) || FLAG_S) /* NS990408 */ + { + uint ea = EA_AY_DI_16(); + m68ki_write_16(ea, m68ki_get_sr()); + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_move_16_frs_ix(void) +{ + if(CPU_TYPE_IS_000(CPU_TYPE) || FLAG_S) /* NS990408 */ + { + uint ea = EA_AY_IX_16(); + m68ki_write_16(ea, m68ki_get_sr()); + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_move_16_frs_aw(void) +{ + if(CPU_TYPE_IS_000(CPU_TYPE) || FLAG_S) /* NS990408 */ + { + uint ea = EA_AW_16(); + m68ki_write_16(ea, m68ki_get_sr()); + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_move_16_frs_al(void) +{ + if(CPU_TYPE_IS_000(CPU_TYPE) || FLAG_S) /* NS990408 */ + { + uint ea = EA_AL_16(); + m68ki_write_16(ea, m68ki_get_sr()); + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_move_16_tos_d(void) +{ + if(FLAG_S) + { + m68ki_set_sr(DY); + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_move_16_tos_ai(void) +{ + if(FLAG_S) + { + uint new_sr = OPER_AY_AI_16(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr(new_sr); + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_move_16_tos_pi(void) +{ + if(FLAG_S) + { + uint new_sr = OPER_AY_PI_16(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr(new_sr); + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_move_16_tos_pd(void) +{ + if(FLAG_S) + { + uint new_sr = OPER_AY_PD_16(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr(new_sr); + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_move_16_tos_di(void) +{ + if(FLAG_S) + { + uint new_sr = OPER_AY_DI_16(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr(new_sr); + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_move_16_tos_ix(void) +{ + if(FLAG_S) + { + uint new_sr = OPER_AY_IX_16(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr(new_sr); + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_move_16_tos_aw(void) +{ + if(FLAG_S) + { + uint new_sr = OPER_AW_16(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr(new_sr); + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_move_16_tos_al(void) +{ + if(FLAG_S) + { + uint new_sr = OPER_AL_16(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr(new_sr); + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_move_16_tos_pcdi(void) +{ + if(FLAG_S) + { + uint new_sr = OPER_PCDI_16(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr(new_sr); + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_move_16_tos_pcix(void) +{ + if(FLAG_S) + { + uint new_sr = OPER_PCIX_16(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr(new_sr); + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_move_16_tos_i(void) +{ + if(FLAG_S) + { + uint new_sr = OPER_I_16(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr(new_sr); + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_move_32_fru(void) +{ + if(FLAG_S) + { + AY = REG_USP; + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_move_32_tou(void) +{ + if(FLAG_S) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + REG_USP = AY; + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_movec_32_cr(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + switch (word2 & 0xfff) + { + case 0x000: /* SFC */ + REG_DA[(word2 >> 12) & 15] = REG_SFC; + return; + case 0x001: /* DFC */ + REG_DA[(word2 >> 12) & 15] = REG_DFC; + return; + case 0x002: /* CACR */ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + REG_DA[(word2 >> 12) & 15] = REG_CACR; + return; + } + return; + case 0x800: /* USP */ + REG_DA[(word2 >> 12) & 15] = REG_USP; + return; + case 0x801: /* VBR */ + REG_DA[(word2 >> 12) & 15] = REG_VBR; + return; + case 0x802: /* CAAR */ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + REG_DA[(word2 >> 12) & 15] = REG_CAAR; + return; + } + m68ki_exception_illegal(); + break; + case 0x803: /* MSP */ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + REG_DA[(word2 >> 12) & 15] = FLAG_M ? REG_SP : REG_MSP; + return; + } + m68ki_exception_illegal(); + return; + case 0x804: /* ISP */ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + REG_DA[(word2 >> 12) & 15] = FLAG_M ? REG_ISP : REG_SP; + return; + } + m68ki_exception_illegal(); + return; + case 0x003: /* TC */ + if(CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x004: /* ITT0 */ + if(CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x005: /* ITT1 */ + if(CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x006: /* DTT0 */ + if(CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x007: /* DTT1 */ + if(CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x805: /* MMUSR */ + if(CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x806: /* URP */ + if(CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x807: /* SRP */ + if(CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + default: + m68ki_exception_illegal(); + return; + } + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_movec_32_rc(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + switch (word2 & 0xfff) + { + case 0x000: /* SFC */ + REG_SFC = REG_DA[(word2 >> 12) & 15] & 7; + return; + case 0x001: /* DFC */ + REG_DFC = REG_DA[(word2 >> 12) & 15] & 7; + return; + case 0x002: /* CACR */ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + REG_CACR = REG_DA[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(); + return; + case 0x800: /* USP */ + REG_USP = REG_DA[(word2 >> 12) & 15]; + return; + case 0x801: /* VBR */ + REG_VBR = REG_DA[(word2 >> 12) & 15]; + return; + case 0x802: /* CAAR */ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + REG_CAAR = REG_DA[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(); + return; + case 0x803: /* MSP */ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + /* we are in supervisor mode so just check for M flag */ + if(!FLAG_M) + { + REG_MSP = REG_DA[(word2 >> 12) & 15]; + return; + } + REG_SP = REG_DA[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(); + return; + case 0x804: /* ISP */ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(!FLAG_M) + { + REG_SP = REG_DA[(word2 >> 12) & 15]; + return; + } + REG_ISP = REG_DA[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(); + return; + case 0x003: /* TC */ + if (CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x004: /* ITT0 */ + if (CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x005: /* ITT1 */ + if (CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x006: /* DTT0 */ + if (CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x007: /* DTT1 */ + if (CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x805: /* MMUSR */ + if (CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x806: /* URP */ + if (CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + case 0x807: /* SRP */ + if (CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(); + return; + default: + m68ki_exception_illegal(); + return; + } + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_movem_16_re_pd(void) +{ + uint i = 0; + uint register_list = OPER_I_16(); + uint ea = AY; + uint count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + ea -= 2; + m68ki_write_16(ea, MASK_OUT_ABOVE_16(REG_DA[15-i])); + count++; + } + AY = ea; + + USE_CYCLES(count<> 8)); + m68ki_write_8(ea += 2, MASK_OUT_ABOVE_8(src)); +} + + +void m68k_op_movep_32_re(void) +{ + uint ea = EA_AY_DI_32(); + uint src = DX; + + m68ki_write_8(ea, MASK_OUT_ABOVE_8(src >> 24)); + m68ki_write_8(ea += 2, MASK_OUT_ABOVE_8(src >> 16)); + m68ki_write_8(ea += 2, MASK_OUT_ABOVE_8(src >> 8)); + m68ki_write_8(ea += 2, MASK_OUT_ABOVE_8(src)); +} + + +void m68k_op_movep_16_er(void) +{ + uint ea = EA_AY_DI_16(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | ((m68ki_read_8(ea) << 8) + m68ki_read_8(ea + 2)); +} + + +void m68k_op_movep_32_er(void) +{ + uint ea = EA_AY_DI_32(); + + DX = (m68ki_read_8(ea) << 24) + (m68ki_read_8(ea + 2) << 16) + + (m68ki_read_8(ea + 4) << 8) + m68ki_read_8(ea + 6); +} + + +void m68k_op_moves_8_ai(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_AI_8(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_8_fc(ea, REG_DFC, MASK_OUT_ABOVE_8(REG_DA[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A[(word2 >> 12) & 7] = MAKE_INT_8(m68ki_read_8_fc(ea, REG_SFC)); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to data register */ + REG_D[(word2 >> 12) & 7] = MASK_OUT_BELOW_8(REG_D[(word2 >> 12) & 7]) | m68ki_read_8_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_moves_8_pi(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_PI_8(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_8_fc(ea, REG_DFC, MASK_OUT_ABOVE_8(REG_DA[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A[(word2 >> 12) & 7] = MAKE_INT_8(m68ki_read_8_fc(ea, REG_SFC)); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to data register */ + REG_D[(word2 >> 12) & 7] = MASK_OUT_BELOW_8(REG_D[(word2 >> 12) & 7]) | m68ki_read_8_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_moves_8_pi7(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = EA_A7_PI_8(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_8_fc(ea, REG_DFC, MASK_OUT_ABOVE_8(REG_DA[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A[(word2 >> 12) & 7] = MAKE_INT_8(m68ki_read_8_fc(ea, REG_SFC)); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to data register */ + REG_D[(word2 >> 12) & 7] = MASK_OUT_BELOW_8(REG_D[(word2 >> 12) & 7]) | m68ki_read_8_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_moves_8_pd(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_PD_8(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_8_fc(ea, REG_DFC, MASK_OUT_ABOVE_8(REG_DA[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A[(word2 >> 12) & 7] = MAKE_INT_8(m68ki_read_8_fc(ea, REG_SFC)); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to data register */ + REG_D[(word2 >> 12) & 7] = MASK_OUT_BELOW_8(REG_D[(word2 >> 12) & 7]) | m68ki_read_8_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_moves_8_pd7(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = EA_A7_PD_8(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_8_fc(ea, REG_DFC, MASK_OUT_ABOVE_8(REG_DA[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A[(word2 >> 12) & 7] = MAKE_INT_8(m68ki_read_8_fc(ea, REG_SFC)); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to data register */ + REG_D[(word2 >> 12) & 7] = MASK_OUT_BELOW_8(REG_D[(word2 >> 12) & 7]) | m68ki_read_8_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_moves_8_di(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_DI_8(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_8_fc(ea, REG_DFC, MASK_OUT_ABOVE_8(REG_DA[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A[(word2 >> 12) & 7] = MAKE_INT_8(m68ki_read_8_fc(ea, REG_SFC)); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to data register */ + REG_D[(word2 >> 12) & 7] = MASK_OUT_BELOW_8(REG_D[(word2 >> 12) & 7]) | m68ki_read_8_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_moves_8_ix(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_IX_8(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_8_fc(ea, REG_DFC, MASK_OUT_ABOVE_8(REG_DA[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A[(word2 >> 12) & 7] = MAKE_INT_8(m68ki_read_8_fc(ea, REG_SFC)); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to data register */ + REG_D[(word2 >> 12) & 7] = MASK_OUT_BELOW_8(REG_D[(word2 >> 12) & 7]) | m68ki_read_8_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_moves_8_aw(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = EA_AW_8(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_8_fc(ea, REG_DFC, MASK_OUT_ABOVE_8(REG_DA[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A[(word2 >> 12) & 7] = MAKE_INT_8(m68ki_read_8_fc(ea, REG_SFC)); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to data register */ + REG_D[(word2 >> 12) & 7] = MASK_OUT_BELOW_8(REG_D[(word2 >> 12) & 7]) | m68ki_read_8_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_moves_8_al(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = EA_AL_8(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_8_fc(ea, REG_DFC, MASK_OUT_ABOVE_8(REG_DA[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A[(word2 >> 12) & 7] = MAKE_INT_8(m68ki_read_8_fc(ea, REG_SFC)); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to data register */ + REG_D[(word2 >> 12) & 7] = MASK_OUT_BELOW_8(REG_D[(word2 >> 12) & 7]) | m68ki_read_8_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_moves_16_ai(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_AI_16(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_16_fc(ea, REG_DFC, MASK_OUT_ABOVE_16(REG_DA[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A[(word2 >> 12) & 7] = MAKE_INT_16(m68ki_read_16_fc(ea, REG_SFC)); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to data register */ + REG_D[(word2 >> 12) & 7] = MASK_OUT_BELOW_16(REG_D[(word2 >> 12) & 7]) | m68ki_read_16_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_moves_16_pi(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_PI_16(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_16_fc(ea, REG_DFC, MASK_OUT_ABOVE_16(REG_DA[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A[(word2 >> 12) & 7] = MAKE_INT_16(m68ki_read_16_fc(ea, REG_SFC)); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to data register */ + REG_D[(word2 >> 12) & 7] = MASK_OUT_BELOW_16(REG_D[(word2 >> 12) & 7]) | m68ki_read_16_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_moves_16_pd(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_PD_16(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_16_fc(ea, REG_DFC, MASK_OUT_ABOVE_16(REG_DA[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A[(word2 >> 12) & 7] = MAKE_INT_16(m68ki_read_16_fc(ea, REG_SFC)); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to data register */ + REG_D[(word2 >> 12) & 7] = MASK_OUT_BELOW_16(REG_D[(word2 >> 12) & 7]) | m68ki_read_16_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_moves_16_di(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_DI_16(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_16_fc(ea, REG_DFC, MASK_OUT_ABOVE_16(REG_DA[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A[(word2 >> 12) & 7] = MAKE_INT_16(m68ki_read_16_fc(ea, REG_SFC)); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to data register */ + REG_D[(word2 >> 12) & 7] = MASK_OUT_BELOW_16(REG_D[(word2 >> 12) & 7]) | m68ki_read_16_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_moves_16_ix(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_IX_16(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_16_fc(ea, REG_DFC, MASK_OUT_ABOVE_16(REG_DA[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A[(word2 >> 12) & 7] = MAKE_INT_16(m68ki_read_16_fc(ea, REG_SFC)); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to data register */ + REG_D[(word2 >> 12) & 7] = MASK_OUT_BELOW_16(REG_D[(word2 >> 12) & 7]) | m68ki_read_16_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_moves_16_aw(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = EA_AW_16(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_16_fc(ea, REG_DFC, MASK_OUT_ABOVE_16(REG_DA[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A[(word2 >> 12) & 7] = MAKE_INT_16(m68ki_read_16_fc(ea, REG_SFC)); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to data register */ + REG_D[(word2 >> 12) & 7] = MASK_OUT_BELOW_16(REG_D[(word2 >> 12) & 7]) | m68ki_read_16_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_moves_16_al(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = EA_AL_16(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_16_fc(ea, REG_DFC, MASK_OUT_ABOVE_16(REG_DA[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A[(word2 >> 12) & 7] = MAKE_INT_16(m68ki_read_16_fc(ea, REG_SFC)); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to data register */ + REG_D[(word2 >> 12) & 7] = MASK_OUT_BELOW_16(REG_D[(word2 >> 12) & 7]) | m68ki_read_16_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_moves_32_ai(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_AI_32(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_32_fc(ea, REG_DFC, REG_DA[(word2 >> 12) & 15]); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to register */ + REG_DA[(word2 >> 12) & 15] = m68ki_read_32_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_moves_32_pi(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_PI_32(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_32_fc(ea, REG_DFC, REG_DA[(word2 >> 12) & 15]); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to register */ + REG_DA[(word2 >> 12) & 15] = m68ki_read_32_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_moves_32_pd(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_PD_32(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_32_fc(ea, REG_DFC, REG_DA[(word2 >> 12) & 15]); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to register */ + REG_DA[(word2 >> 12) & 15] = m68ki_read_32_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_moves_32_di(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_DI_32(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_32_fc(ea, REG_DFC, REG_DA[(word2 >> 12) & 15]); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to register */ + REG_DA[(word2 >> 12) & 15] = m68ki_read_32_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_moves_32_ix(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = EA_AY_IX_32(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_32_fc(ea, REG_DFC, REG_DA[(word2 >> 12) & 15]); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to register */ + REG_DA[(word2 >> 12) & 15] = m68ki_read_32_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_moves_32_aw(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = EA_AW_32(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_32_fc(ea, REG_DFC, REG_DA[(word2 >> 12) & 15]); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to register */ + REG_DA[(word2 >> 12) & 15] = m68ki_read_32_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_moves_32_al(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + if(FLAG_S) + { + uint word2 = OPER_I_16(); + uint ea = EA_AL_32(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_32_fc(ea, REG_DFC, REG_DA[(word2 >> 12) & 15]); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + /* Memory to register */ + REG_DA[(word2 >> 12) & 15] = m68ki_read_32_fc(ea, REG_SFC); + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + USE_CYCLES(2); + return; + } + m68ki_exception_privilege_violation(); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_moveq_32(void) +{ + uint res = DX = MAKE_INT_8(MASK_OUT_ABOVE_8(REG_IR)); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_move16_32(void) +{ + UINT16 w2 = OPER_I_16(); + int ax = REG_IR & 7; + int ay = (w2 >> 12) & 7; + + m68ki_write_32(REG_A[ay], m68ki_read_32(REG_A[ax])); + m68ki_write_32(REG_A[ay]+4, m68ki_read_32(REG_A[ax]+4)); + m68ki_write_32(REG_A[ay]+8, m68ki_read_32(REG_A[ax]+8)); + m68ki_write_32(REG_A[ay]+12, m68ki_read_32(REG_A[ax]+12)); + + REG_A[ax] += 16; + REG_A[ay] += 16; +} + + +void m68k_op_muls_16_d(void) +{ + uint* r_dst = &DX; + uint res = MASK_OUT_ABOVE_32(MAKE_INT_16(DY) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_muls_16_ai(void) +{ + uint* r_dst = &DX; + uint res = MASK_OUT_ABOVE_32(MAKE_INT_16(OPER_AY_AI_16()) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_muls_16_pi(void) +{ + uint* r_dst = &DX; + uint res = MASK_OUT_ABOVE_32(MAKE_INT_16(OPER_AY_PI_16()) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_muls_16_pd(void) +{ + uint* r_dst = &DX; + uint res = MASK_OUT_ABOVE_32(MAKE_INT_16(OPER_AY_PD_16()) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_muls_16_di(void) +{ + uint* r_dst = &DX; + uint res = MASK_OUT_ABOVE_32(MAKE_INT_16(OPER_AY_DI_16()) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_muls_16_ix(void) +{ + uint* r_dst = &DX; + uint res = MASK_OUT_ABOVE_32(MAKE_INT_16(OPER_AY_IX_16()) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_muls_16_aw(void) +{ + uint* r_dst = &DX; + uint res = MASK_OUT_ABOVE_32(MAKE_INT_16(OPER_AW_16()) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_muls_16_al(void) +{ + uint* r_dst = &DX; + uint res = MASK_OUT_ABOVE_32(MAKE_INT_16(OPER_AL_16()) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_muls_16_pcdi(void) +{ + uint* r_dst = &DX; + uint res = MASK_OUT_ABOVE_32(MAKE_INT_16(OPER_PCDI_16()) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_muls_16_pcix(void) +{ + uint* r_dst = &DX; + uint res = MASK_OUT_ABOVE_32(MAKE_INT_16(OPER_PCIX_16()) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_muls_16_i(void) +{ + uint* r_dst = &DX; + uint res = MASK_OUT_ABOVE_32(MAKE_INT_16(OPER_I_16()) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_mulu_16_d(void) +{ + uint* r_dst = &DX; + uint res = MASK_OUT_ABOVE_16(DY) * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_mulu_16_ai(void) +{ + uint* r_dst = &DX; + uint res = OPER_AY_AI_16() * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_mulu_16_pi(void) +{ + uint* r_dst = &DX; + uint res = OPER_AY_PI_16() * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_mulu_16_pd(void) +{ + uint* r_dst = &DX; + uint res = OPER_AY_PD_16() * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_mulu_16_di(void) +{ + uint* r_dst = &DX; + uint res = OPER_AY_DI_16() * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_mulu_16_ix(void) +{ + uint* r_dst = &DX; + uint res = OPER_AY_IX_16() * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_mulu_16_aw(void) +{ + uint* r_dst = &DX; + uint res = OPER_AW_16() * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_mulu_16_al(void) +{ + uint* r_dst = &DX; + uint res = OPER_AL_16() * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_mulu_16_pcdi(void) +{ + uint* r_dst = &DX; + uint res = OPER_PCDI_16() * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_mulu_16_pcix(void) +{ + uint* r_dst = &DX; + uint res = OPER_PCIX_16() * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_mulu_16_i(void) +{ + uint* r_dst = &DX; + uint res = OPER_I_16() * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + FLAG_Z = res; + FLAG_N = NFLAG_32(res); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_mull_32_d(void) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 src = DY; + uint64 dst = REG_D[(word2 >> 12) & 7]; + uint64 res; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (sint64)((sint32)src) * (sint64)((sint32)dst); + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = ((sint64)res != (sint32)res)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = (res > 0xffffffff)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint src = DY; + uint dst = REG_D[(word2 >> 12) & 7]; + uint neg = GET_MSB_32(src ^ dst); + uint src1; + uint src2; + uint dst1; + uint dst2; + uint r1; + uint r2; + uint r3; + uint r4; + uint lo; + uint hi; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + if(GET_MSB_32(src)) + src = (uint)MASK_OUT_ABOVE_32(-(sint)src); + if(GET_MSB_32(dst)) + dst = (uint)MASK_OUT_ABOVE_32(-(sint)dst); + } + + src1 = MASK_OUT_ABOVE_16(src); + src2 = src>>16; + dst1 = MASK_OUT_ABOVE_16(dst); + dst2 = dst>>16; + + + r1 = src1 * dst1; + r2 = src1 * dst2; + r3 = src2 * dst1; + r4 = src2 * dst2; + + lo = r1 + (MASK_OUT_ABOVE_16(r2)<<16) + (MASK_OUT_ABOVE_16(r3)<<16); + hi = r4 + (r2>>16) + (r3>>16) + (((r1>>16) + MASK_OUT_ABOVE_16(r2) + MASK_OUT_ABOVE_16(r3)) >> 16); + + if(BIT_B(word2) && neg) + { + hi = (uint)MASK_OUT_ABOVE_32((-(sint)hi) - (lo != 0)); + lo = (uint)MASK_OUT_ABOVE_32(-(sint)lo); + } + + if(BIT_A(word2)) + { + REG_D[word2 & 7] = hi; + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(hi); + FLAG_Z = hi | lo; + FLAG_V = VFLAG_CLEAR; + return; + } + + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(lo); + FLAG_Z = lo; + if(BIT_B(word2)) + FLAG_V = (!((GET_MSB_32(lo) && hi == 0xffffffff) || (!GET_MSB_32(lo) && !hi)))<<7; + else + FLAG_V = (hi != 0) << 7; + return; + } + m68ki_exception_illegal(); + +#endif +} + + +void m68k_op_mull_32_ai(void) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 src = OPER_AY_AI_32(); + uint64 dst = REG_D[(word2 >> 12) & 7]; + uint64 res; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (sint64)((sint32)src) * (sint64)((sint32)dst); + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = ((sint64)res != (sint32)res)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = (res > 0xffffffff)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint src = OPER_AY_AI_32(); + uint dst = REG_D[(word2 >> 12) & 7]; + uint neg = GET_MSB_32(src ^ dst); + uint src1; + uint src2; + uint dst1; + uint dst2; + uint r1; + uint r2; + uint r3; + uint r4; + uint lo; + uint hi; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + if(GET_MSB_32(src)) + src = (uint)MASK_OUT_ABOVE_32(-(sint)src); + if(GET_MSB_32(dst)) + dst = (uint)MASK_OUT_ABOVE_32(-(sint)dst); + } + + src1 = MASK_OUT_ABOVE_16(src); + src2 = src>>16; + dst1 = MASK_OUT_ABOVE_16(dst); + dst2 = dst>>16; + + + r1 = src1 * dst1; + r2 = src1 * dst2; + r3 = src2 * dst1; + r4 = src2 * dst2; + + lo = r1 + (MASK_OUT_ABOVE_16(r2)<<16) + (MASK_OUT_ABOVE_16(r3)<<16); + hi = r4 + (r2>>16) + (r3>>16) + (((r1>>16) + MASK_OUT_ABOVE_16(r2) + MASK_OUT_ABOVE_16(r3)) >> 16); + + if(BIT_B(word2) && neg) + { + hi = (uint)MASK_OUT_ABOVE_32((-(sint)hi) - (lo != 0)); + lo = (uint)MASK_OUT_ABOVE_32(-(sint)lo); + } + + if(BIT_A(word2)) + { + REG_D[word2 & 7] = hi; + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(hi); + FLAG_Z = hi | lo; + FLAG_V = VFLAG_CLEAR; + return; + } + + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(lo); + FLAG_Z = lo; + if(BIT_B(word2)) + FLAG_V = (!((GET_MSB_32(lo) && hi == 0xffffffff) || (!GET_MSB_32(lo) && !hi)))<<7; + else + FLAG_V = (hi != 0) << 7; + return; + } + m68ki_exception_illegal(); + +#endif +} + + +void m68k_op_mull_32_pi(void) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 src = OPER_AY_PI_32(); + uint64 dst = REG_D[(word2 >> 12) & 7]; + uint64 res; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (sint64)((sint32)src) * (sint64)((sint32)dst); + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = ((sint64)res != (sint32)res)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = (res > 0xffffffff)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint src = OPER_AY_PI_32(); + uint dst = REG_D[(word2 >> 12) & 7]; + uint neg = GET_MSB_32(src ^ dst); + uint src1; + uint src2; + uint dst1; + uint dst2; + uint r1; + uint r2; + uint r3; + uint r4; + uint lo; + uint hi; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + if(GET_MSB_32(src)) + src = (uint)MASK_OUT_ABOVE_32(-(sint)src); + if(GET_MSB_32(dst)) + dst = (uint)MASK_OUT_ABOVE_32(-(sint)dst); + } + + src1 = MASK_OUT_ABOVE_16(src); + src2 = src>>16; + dst1 = MASK_OUT_ABOVE_16(dst); + dst2 = dst>>16; + + + r1 = src1 * dst1; + r2 = src1 * dst2; + r3 = src2 * dst1; + r4 = src2 * dst2; + + lo = r1 + (MASK_OUT_ABOVE_16(r2)<<16) + (MASK_OUT_ABOVE_16(r3)<<16); + hi = r4 + (r2>>16) + (r3>>16) + (((r1>>16) + MASK_OUT_ABOVE_16(r2) + MASK_OUT_ABOVE_16(r3)) >> 16); + + if(BIT_B(word2) && neg) + { + hi = (uint)MASK_OUT_ABOVE_32((-(sint)hi) - (lo != 0)); + lo = (uint)MASK_OUT_ABOVE_32(-(sint)lo); + } + + if(BIT_A(word2)) + { + REG_D[word2 & 7] = hi; + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(hi); + FLAG_Z = hi | lo; + FLAG_V = VFLAG_CLEAR; + return; + } + + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(lo); + FLAG_Z = lo; + if(BIT_B(word2)) + FLAG_V = (!((GET_MSB_32(lo) && hi == 0xffffffff) || (!GET_MSB_32(lo) && !hi)))<<7; + else + FLAG_V = (hi != 0) << 7; + return; + } + m68ki_exception_illegal(); + +#endif +} + + +void m68k_op_mull_32_pd(void) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 src = OPER_AY_PD_32(); + uint64 dst = REG_D[(word2 >> 12) & 7]; + uint64 res; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (sint64)((sint32)src) * (sint64)((sint32)dst); + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = ((sint64)res != (sint32)res)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = (res > 0xffffffff)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint src = OPER_AY_PD_32(); + uint dst = REG_D[(word2 >> 12) & 7]; + uint neg = GET_MSB_32(src ^ dst); + uint src1; + uint src2; + uint dst1; + uint dst2; + uint r1; + uint r2; + uint r3; + uint r4; + uint lo; + uint hi; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + if(GET_MSB_32(src)) + src = (uint)MASK_OUT_ABOVE_32(-(sint)src); + if(GET_MSB_32(dst)) + dst = (uint)MASK_OUT_ABOVE_32(-(sint)dst); + } + + src1 = MASK_OUT_ABOVE_16(src); + src2 = src>>16; + dst1 = MASK_OUT_ABOVE_16(dst); + dst2 = dst>>16; + + + r1 = src1 * dst1; + r2 = src1 * dst2; + r3 = src2 * dst1; + r4 = src2 * dst2; + + lo = r1 + (MASK_OUT_ABOVE_16(r2)<<16) + (MASK_OUT_ABOVE_16(r3)<<16); + hi = r4 + (r2>>16) + (r3>>16) + (((r1>>16) + MASK_OUT_ABOVE_16(r2) + MASK_OUT_ABOVE_16(r3)) >> 16); + + if(BIT_B(word2) && neg) + { + hi = (uint)MASK_OUT_ABOVE_32((-(sint)hi) - (lo != 0)); + lo = (uint)MASK_OUT_ABOVE_32(-(sint)lo); + } + + if(BIT_A(word2)) + { + REG_D[word2 & 7] = hi; + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(hi); + FLAG_Z = hi | lo; + FLAG_V = VFLAG_CLEAR; + return; + } + + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(lo); + FLAG_Z = lo; + if(BIT_B(word2)) + FLAG_V = (!((GET_MSB_32(lo) && hi == 0xffffffff) || (!GET_MSB_32(lo) && !hi)))<<7; + else + FLAG_V = (hi != 0) << 7; + return; + } + m68ki_exception_illegal(); + +#endif +} + + +void m68k_op_mull_32_di(void) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 src = OPER_AY_DI_32(); + uint64 dst = REG_D[(word2 >> 12) & 7]; + uint64 res; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (sint64)((sint32)src) * (sint64)((sint32)dst); + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = ((sint64)res != (sint32)res)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = (res > 0xffffffff)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint src = OPER_AY_DI_32(); + uint dst = REG_D[(word2 >> 12) & 7]; + uint neg = GET_MSB_32(src ^ dst); + uint src1; + uint src2; + uint dst1; + uint dst2; + uint r1; + uint r2; + uint r3; + uint r4; + uint lo; + uint hi; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + if(GET_MSB_32(src)) + src = (uint)MASK_OUT_ABOVE_32(-(sint)src); + if(GET_MSB_32(dst)) + dst = (uint)MASK_OUT_ABOVE_32(-(sint)dst); + } + + src1 = MASK_OUT_ABOVE_16(src); + src2 = src>>16; + dst1 = MASK_OUT_ABOVE_16(dst); + dst2 = dst>>16; + + + r1 = src1 * dst1; + r2 = src1 * dst2; + r3 = src2 * dst1; + r4 = src2 * dst2; + + lo = r1 + (MASK_OUT_ABOVE_16(r2)<<16) + (MASK_OUT_ABOVE_16(r3)<<16); + hi = r4 + (r2>>16) + (r3>>16) + (((r1>>16) + MASK_OUT_ABOVE_16(r2) + MASK_OUT_ABOVE_16(r3)) >> 16); + + if(BIT_B(word2) && neg) + { + hi = (uint)MASK_OUT_ABOVE_32((-(sint)hi) - (lo != 0)); + lo = (uint)MASK_OUT_ABOVE_32(-(sint)lo); + } + + if(BIT_A(word2)) + { + REG_D[word2 & 7] = hi; + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(hi); + FLAG_Z = hi | lo; + FLAG_V = VFLAG_CLEAR; + return; + } + + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(lo); + FLAG_Z = lo; + if(BIT_B(word2)) + FLAG_V = (!((GET_MSB_32(lo) && hi == 0xffffffff) || (!GET_MSB_32(lo) && !hi)))<<7; + else + FLAG_V = (hi != 0) << 7; + return; + } + m68ki_exception_illegal(); + +#endif +} + + +void m68k_op_mull_32_ix(void) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 src = OPER_AY_IX_32(); + uint64 dst = REG_D[(word2 >> 12) & 7]; + uint64 res; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (sint64)((sint32)src) * (sint64)((sint32)dst); + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = ((sint64)res != (sint32)res)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = (res > 0xffffffff)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint src = OPER_AY_IX_32(); + uint dst = REG_D[(word2 >> 12) & 7]; + uint neg = GET_MSB_32(src ^ dst); + uint src1; + uint src2; + uint dst1; + uint dst2; + uint r1; + uint r2; + uint r3; + uint r4; + uint lo; + uint hi; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + if(GET_MSB_32(src)) + src = (uint)MASK_OUT_ABOVE_32(-(sint)src); + if(GET_MSB_32(dst)) + dst = (uint)MASK_OUT_ABOVE_32(-(sint)dst); + } + + src1 = MASK_OUT_ABOVE_16(src); + src2 = src>>16; + dst1 = MASK_OUT_ABOVE_16(dst); + dst2 = dst>>16; + + + r1 = src1 * dst1; + r2 = src1 * dst2; + r3 = src2 * dst1; + r4 = src2 * dst2; + + lo = r1 + (MASK_OUT_ABOVE_16(r2)<<16) + (MASK_OUT_ABOVE_16(r3)<<16); + hi = r4 + (r2>>16) + (r3>>16) + (((r1>>16) + MASK_OUT_ABOVE_16(r2) + MASK_OUT_ABOVE_16(r3)) >> 16); + + if(BIT_B(word2) && neg) + { + hi = (uint)MASK_OUT_ABOVE_32((-(sint)hi) - (lo != 0)); + lo = (uint)MASK_OUT_ABOVE_32(-(sint)lo); + } + + if(BIT_A(word2)) + { + REG_D[word2 & 7] = hi; + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(hi); + FLAG_Z = hi | lo; + FLAG_V = VFLAG_CLEAR; + return; + } + + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(lo); + FLAG_Z = lo; + if(BIT_B(word2)) + FLAG_V = (!((GET_MSB_32(lo) && hi == 0xffffffff) || (!GET_MSB_32(lo) && !hi)))<<7; + else + FLAG_V = (hi != 0) << 7; + return; + } + m68ki_exception_illegal(); + +#endif +} + + +void m68k_op_mull_32_aw(void) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 src = OPER_AW_32(); + uint64 dst = REG_D[(word2 >> 12) & 7]; + uint64 res; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (sint64)((sint32)src) * (sint64)((sint32)dst); + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = ((sint64)res != (sint32)res)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = (res > 0xffffffff)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint src = OPER_AW_32(); + uint dst = REG_D[(word2 >> 12) & 7]; + uint neg = GET_MSB_32(src ^ dst); + uint src1; + uint src2; + uint dst1; + uint dst2; + uint r1; + uint r2; + uint r3; + uint r4; + uint lo; + uint hi; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + if(GET_MSB_32(src)) + src = (uint)MASK_OUT_ABOVE_32(-(sint)src); + if(GET_MSB_32(dst)) + dst = (uint)MASK_OUT_ABOVE_32(-(sint)dst); + } + + src1 = MASK_OUT_ABOVE_16(src); + src2 = src>>16; + dst1 = MASK_OUT_ABOVE_16(dst); + dst2 = dst>>16; + + + r1 = src1 * dst1; + r2 = src1 * dst2; + r3 = src2 * dst1; + r4 = src2 * dst2; + + lo = r1 + (MASK_OUT_ABOVE_16(r2)<<16) + (MASK_OUT_ABOVE_16(r3)<<16); + hi = r4 + (r2>>16) + (r3>>16) + (((r1>>16) + MASK_OUT_ABOVE_16(r2) + MASK_OUT_ABOVE_16(r3)) >> 16); + + if(BIT_B(word2) && neg) + { + hi = (uint)MASK_OUT_ABOVE_32((-(sint)hi) - (lo != 0)); + lo = (uint)MASK_OUT_ABOVE_32(-(sint)lo); + } + + if(BIT_A(word2)) + { + REG_D[word2 & 7] = hi; + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(hi); + FLAG_Z = hi | lo; + FLAG_V = VFLAG_CLEAR; + return; + } + + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(lo); + FLAG_Z = lo; + if(BIT_B(word2)) + FLAG_V = (!((GET_MSB_32(lo) && hi == 0xffffffff) || (!GET_MSB_32(lo) && !hi)))<<7; + else + FLAG_V = (hi != 0) << 7; + return; + } + m68ki_exception_illegal(); + +#endif +} + + +void m68k_op_mull_32_al(void) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 src = OPER_AL_32(); + uint64 dst = REG_D[(word2 >> 12) & 7]; + uint64 res; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (sint64)((sint32)src) * (sint64)((sint32)dst); + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = ((sint64)res != (sint32)res)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = (res > 0xffffffff)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint src = OPER_AL_32(); + uint dst = REG_D[(word2 >> 12) & 7]; + uint neg = GET_MSB_32(src ^ dst); + uint src1; + uint src2; + uint dst1; + uint dst2; + uint r1; + uint r2; + uint r3; + uint r4; + uint lo; + uint hi; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + if(GET_MSB_32(src)) + src = (uint)MASK_OUT_ABOVE_32(-(sint)src); + if(GET_MSB_32(dst)) + dst = (uint)MASK_OUT_ABOVE_32(-(sint)dst); + } + + src1 = MASK_OUT_ABOVE_16(src); + src2 = src>>16; + dst1 = MASK_OUT_ABOVE_16(dst); + dst2 = dst>>16; + + + r1 = src1 * dst1; + r2 = src1 * dst2; + r3 = src2 * dst1; + r4 = src2 * dst2; + + lo = r1 + (MASK_OUT_ABOVE_16(r2)<<16) + (MASK_OUT_ABOVE_16(r3)<<16); + hi = r4 + (r2>>16) + (r3>>16) + (((r1>>16) + MASK_OUT_ABOVE_16(r2) + MASK_OUT_ABOVE_16(r3)) >> 16); + + if(BIT_B(word2) && neg) + { + hi = (uint)MASK_OUT_ABOVE_32((-(sint)hi) - (lo != 0)); + lo = (uint)MASK_OUT_ABOVE_32(-(sint)lo); + } + + if(BIT_A(word2)) + { + REG_D[word2 & 7] = hi; + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(hi); + FLAG_Z = hi | lo; + FLAG_V = VFLAG_CLEAR; + return; + } + + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(lo); + FLAG_Z = lo; + if(BIT_B(word2)) + FLAG_V = (!((GET_MSB_32(lo) && hi == 0xffffffff) || (!GET_MSB_32(lo) && !hi)))<<7; + else + FLAG_V = (hi != 0) << 7; + return; + } + m68ki_exception_illegal(); + +#endif +} + + +void m68k_op_mull_32_pcdi(void) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 src = OPER_PCDI_32(); + uint64 dst = REG_D[(word2 >> 12) & 7]; + uint64 res; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (sint64)((sint32)src) * (sint64)((sint32)dst); + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = ((sint64)res != (sint32)res)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = (res > 0xffffffff)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint src = OPER_PCDI_32(); + uint dst = REG_D[(word2 >> 12) & 7]; + uint neg = GET_MSB_32(src ^ dst); + uint src1; + uint src2; + uint dst1; + uint dst2; + uint r1; + uint r2; + uint r3; + uint r4; + uint lo; + uint hi; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + if(GET_MSB_32(src)) + src = (uint)MASK_OUT_ABOVE_32(-(sint)src); + if(GET_MSB_32(dst)) + dst = (uint)MASK_OUT_ABOVE_32(-(sint)dst); + } + + src1 = MASK_OUT_ABOVE_16(src); + src2 = src>>16; + dst1 = MASK_OUT_ABOVE_16(dst); + dst2 = dst>>16; + + + r1 = src1 * dst1; + r2 = src1 * dst2; + r3 = src2 * dst1; + r4 = src2 * dst2; + + lo = r1 + (MASK_OUT_ABOVE_16(r2)<<16) + (MASK_OUT_ABOVE_16(r3)<<16); + hi = r4 + (r2>>16) + (r3>>16) + (((r1>>16) + MASK_OUT_ABOVE_16(r2) + MASK_OUT_ABOVE_16(r3)) >> 16); + + if(BIT_B(word2) && neg) + { + hi = (uint)MASK_OUT_ABOVE_32((-(sint)hi) - (lo != 0)); + lo = (uint)MASK_OUT_ABOVE_32(-(sint)lo); + } + + if(BIT_A(word2)) + { + REG_D[word2 & 7] = hi; + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(hi); + FLAG_Z = hi | lo; + FLAG_V = VFLAG_CLEAR; + return; + } + + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(lo); + FLAG_Z = lo; + if(BIT_B(word2)) + FLAG_V = (!((GET_MSB_32(lo) && hi == 0xffffffff) || (!GET_MSB_32(lo) && !hi)))<<7; + else + FLAG_V = (hi != 0) << 7; + return; + } + m68ki_exception_illegal(); + +#endif +} + + +void m68k_op_mull_32_pcix(void) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 src = OPER_PCIX_32(); + uint64 dst = REG_D[(word2 >> 12) & 7]; + uint64 res; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (sint64)((sint32)src) * (sint64)((sint32)dst); + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = ((sint64)res != (sint32)res)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = (res > 0xffffffff)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint src = OPER_PCIX_32(); + uint dst = REG_D[(word2 >> 12) & 7]; + uint neg = GET_MSB_32(src ^ dst); + uint src1; + uint src2; + uint dst1; + uint dst2; + uint r1; + uint r2; + uint r3; + uint r4; + uint lo; + uint hi; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + if(GET_MSB_32(src)) + src = (uint)MASK_OUT_ABOVE_32(-(sint)src); + if(GET_MSB_32(dst)) + dst = (uint)MASK_OUT_ABOVE_32(-(sint)dst); + } + + src1 = MASK_OUT_ABOVE_16(src); + src2 = src>>16; + dst1 = MASK_OUT_ABOVE_16(dst); + dst2 = dst>>16; + + + r1 = src1 * dst1; + r2 = src1 * dst2; + r3 = src2 * dst1; + r4 = src2 * dst2; + + lo = r1 + (MASK_OUT_ABOVE_16(r2)<<16) + (MASK_OUT_ABOVE_16(r3)<<16); + hi = r4 + (r2>>16) + (r3>>16) + (((r1>>16) + MASK_OUT_ABOVE_16(r2) + MASK_OUT_ABOVE_16(r3)) >> 16); + + if(BIT_B(word2) && neg) + { + hi = (uint)MASK_OUT_ABOVE_32((-(sint)hi) - (lo != 0)); + lo = (uint)MASK_OUT_ABOVE_32(-(sint)lo); + } + + if(BIT_A(word2)) + { + REG_D[word2 & 7] = hi; + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(hi); + FLAG_Z = hi | lo; + FLAG_V = VFLAG_CLEAR; + return; + } + + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(lo); + FLAG_Z = lo; + if(BIT_B(word2)) + FLAG_V = (!((GET_MSB_32(lo) && hi == 0xffffffff) || (!GET_MSB_32(lo) && !hi)))<<7; + else + FLAG_V = (hi != 0) << 7; + return; + } + m68ki_exception_illegal(); + +#endif +} + + +void m68k_op_mull_32_i(void) +{ +#if M68K_USE_64_BIT + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint64 src = OPER_I_32(); + uint64 dst = REG_D[(word2 >> 12) & 7]; + uint64 res; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (sint64)((sint32)src) * (sint64)((sint32)dst); + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = ((sint64)res != (sint32)res)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_N = NFLAG_32(res); + FLAG_V = (res > 0xffffffff)<<7; + REG_D[(word2 >> 12) & 7] = FLAG_Z; + return; + } + FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); + FLAG_N = NFLAG_64(res); + FLAG_V = VFLAG_CLEAR; + REG_D[word2 & 7] = (res >> 32); + REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(); + +#else + + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint word2 = OPER_I_16(); + uint src = OPER_I_32(); + uint dst = REG_D[(word2 >> 12) & 7]; + uint neg = GET_MSB_32(src ^ dst); + uint src1; + uint src2; + uint dst1; + uint dst2; + uint r1; + uint r2; + uint r3; + uint r4; + uint lo; + uint hi; + + FLAG_C = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + if(GET_MSB_32(src)) + src = (uint)MASK_OUT_ABOVE_32(-(sint)src); + if(GET_MSB_32(dst)) + dst = (uint)MASK_OUT_ABOVE_32(-(sint)dst); + } + + src1 = MASK_OUT_ABOVE_16(src); + src2 = src>>16; + dst1 = MASK_OUT_ABOVE_16(dst); + dst2 = dst>>16; + + + r1 = src1 * dst1; + r2 = src1 * dst2; + r3 = src2 * dst1; + r4 = src2 * dst2; + + lo = r1 + (MASK_OUT_ABOVE_16(r2)<<16) + (MASK_OUT_ABOVE_16(r3)<<16); + hi = r4 + (r2>>16) + (r3>>16) + (((r1>>16) + MASK_OUT_ABOVE_16(r2) + MASK_OUT_ABOVE_16(r3)) >> 16); + + if(BIT_B(word2) && neg) + { + hi = (uint)MASK_OUT_ABOVE_32((-(sint)hi) - (lo != 0)); + lo = (uint)MASK_OUT_ABOVE_32(-(sint)lo); + } + + if(BIT_A(word2)) + { + REG_D[word2 & 7] = hi; + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(hi); + FLAG_Z = hi | lo; + FLAG_V = VFLAG_CLEAR; + return; + } + + REG_D[(word2 >> 12) & 7] = lo; + FLAG_N = NFLAG_32(lo); + FLAG_Z = lo; + if(BIT_B(word2)) + FLAG_V = (!((GET_MSB_32(lo) && hi == 0xffffffff) || (!GET_MSB_32(lo) && !hi)))<<7; + else + FLAG_V = (hi != 0) << 7; + return; + } + m68ki_exception_illegal(); + +#endif +} + + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ + + diff --git a/cpu/musashi/m68kopnz.c b/cpu/musashi/m68kopnz.c new file mode 100644 index 00000000..cda7939a --- /dev/null +++ b/cpu/musashi/m68kopnz.c @@ -0,0 +1,8878 @@ +#include "m68kcpu.h" + +/* ======================================================================== */ +/* ========================= INSTRUCTION HANDLERS ========================= */ +/* ======================================================================== */ + + +void m68k_op_nbcd_8_d(void) +{ + uint* r_dst = &DY; + uint dst = *r_dst; + uint res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1()); + + if(res != 0x9a) + { + FLAG_V = ~res; /* Undefined V behavior */ + + if((res & 0x0f) == 0xa) + res = (res & 0xf0) + 0x10; + + res = MASK_OUT_ABOVE_8(res); + + FLAG_V &= res; /* Undefined V behavior part II */ + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + FLAG_Z |= res; + FLAG_C = CFLAG_SET; + FLAG_X = XFLAG_SET; + } + else + { + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_X = XFLAG_CLEAR; + } + FLAG_N = NFLAG_8(res); /* Undefined N behavior */ +} + + +void m68k_op_nbcd_8_ai(void) +{ + uint ea = EA_AY_AI_8(); + uint dst = m68ki_read_8(ea); + uint res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1()); + + if(res != 0x9a) + { + FLAG_V = ~res; /* Undefined V behavior */ + + if((res & 0x0f) == 0xa) + res = (res & 0xf0) + 0x10; + + res = MASK_OUT_ABOVE_8(res); + + FLAG_V &= res; /* Undefined V behavior part II */ + + m68ki_write_8(ea, MASK_OUT_ABOVE_8(res)); + + FLAG_Z |= res; + FLAG_C = CFLAG_SET; + FLAG_X = XFLAG_SET; + } + else + { + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_X = XFLAG_CLEAR; + } + FLAG_N = NFLAG_8(res); /* Undefined N behavior */ +} + + +void m68k_op_nbcd_8_pi(void) +{ + uint ea = EA_AY_PI_8(); + uint dst = m68ki_read_8(ea); + uint res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1()); + + if(res != 0x9a) + { + FLAG_V = ~res; /* Undefined V behavior */ + + if((res & 0x0f) == 0xa) + res = (res & 0xf0) + 0x10; + + res = MASK_OUT_ABOVE_8(res); + + FLAG_V &= res; /* Undefined V behavior part II */ + + m68ki_write_8(ea, MASK_OUT_ABOVE_8(res)); + + FLAG_Z |= res; + FLAG_C = CFLAG_SET; + FLAG_X = XFLAG_SET; + } + else + { + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_X = XFLAG_CLEAR; + } + FLAG_N = NFLAG_8(res); /* Undefined N behavior */ +} + + +void m68k_op_nbcd_8_pi7(void) +{ + uint ea = EA_A7_PI_8(); + uint dst = m68ki_read_8(ea); + uint res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1()); + + if(res != 0x9a) + { + FLAG_V = ~res; /* Undefined V behavior */ + + if((res & 0x0f) == 0xa) + res = (res & 0xf0) + 0x10; + + res = MASK_OUT_ABOVE_8(res); + + FLAG_V &= res; /* Undefined V behavior part II */ + + m68ki_write_8(ea, MASK_OUT_ABOVE_8(res)); + + FLAG_Z |= res; + FLAG_C = CFLAG_SET; + FLAG_X = XFLAG_SET; + } + else + { + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_X = XFLAG_CLEAR; + } + FLAG_N = NFLAG_8(res); /* Undefined N behavior */ +} + + +void m68k_op_nbcd_8_pd(void) +{ + uint ea = EA_AY_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1()); + + if(res != 0x9a) + { + FLAG_V = ~res; /* Undefined V behavior */ + + if((res & 0x0f) == 0xa) + res = (res & 0xf0) + 0x10; + + res = MASK_OUT_ABOVE_8(res); + + FLAG_V &= res; /* Undefined V behavior part II */ + + m68ki_write_8(ea, MASK_OUT_ABOVE_8(res)); + + FLAG_Z |= res; + FLAG_C = CFLAG_SET; + FLAG_X = XFLAG_SET; + } + else + { + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_X = XFLAG_CLEAR; + } + FLAG_N = NFLAG_8(res); /* Undefined N behavior */ +} + + +void m68k_op_nbcd_8_pd7(void) +{ + uint ea = EA_A7_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1()); + + if(res != 0x9a) + { + FLAG_V = ~res; /* Undefined V behavior */ + + if((res & 0x0f) == 0xa) + res = (res & 0xf0) + 0x10; + + res = MASK_OUT_ABOVE_8(res); + + FLAG_V &= res; /* Undefined V behavior part II */ + + m68ki_write_8(ea, MASK_OUT_ABOVE_8(res)); + + FLAG_Z |= res; + FLAG_C = CFLAG_SET; + FLAG_X = XFLAG_SET; + } + else + { + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_X = XFLAG_CLEAR; + } + FLAG_N = NFLAG_8(res); /* Undefined N behavior */ +} + + +void m68k_op_nbcd_8_di(void) +{ + uint ea = EA_AY_DI_8(); + uint dst = m68ki_read_8(ea); + uint res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1()); + + if(res != 0x9a) + { + FLAG_V = ~res; /* Undefined V behavior */ + + if((res & 0x0f) == 0xa) + res = (res & 0xf0) + 0x10; + + res = MASK_OUT_ABOVE_8(res); + + FLAG_V &= res; /* Undefined V behavior part II */ + + m68ki_write_8(ea, MASK_OUT_ABOVE_8(res)); + + FLAG_Z |= res; + FLAG_C = CFLAG_SET; + FLAG_X = XFLAG_SET; + } + else + { + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_X = XFLAG_CLEAR; + } + FLAG_N = NFLAG_8(res); /* Undefined N behavior */ +} + + +void m68k_op_nbcd_8_ix(void) +{ + uint ea = EA_AY_IX_8(); + uint dst = m68ki_read_8(ea); + uint res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1()); + + if(res != 0x9a) + { + FLAG_V = ~res; /* Undefined V behavior */ + + if((res & 0x0f) == 0xa) + res = (res & 0xf0) + 0x10; + + res = MASK_OUT_ABOVE_8(res); + + FLAG_V &= res; /* Undefined V behavior part II */ + + m68ki_write_8(ea, MASK_OUT_ABOVE_8(res)); + + FLAG_Z |= res; + FLAG_C = CFLAG_SET; + FLAG_X = XFLAG_SET; + } + else + { + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_X = XFLAG_CLEAR; + } + FLAG_N = NFLAG_8(res); /* Undefined N behavior */ +} + + +void m68k_op_nbcd_8_aw(void) +{ + uint ea = EA_AW_8(); + uint dst = m68ki_read_8(ea); + uint res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1()); + + if(res != 0x9a) + { + FLAG_V = ~res; /* Undefined V behavior */ + + if((res & 0x0f) == 0xa) + res = (res & 0xf0) + 0x10; + + res = MASK_OUT_ABOVE_8(res); + + FLAG_V &= res; /* Undefined V behavior part II */ + + m68ki_write_8(ea, MASK_OUT_ABOVE_8(res)); + + FLAG_Z |= res; + FLAG_C = CFLAG_SET; + FLAG_X = XFLAG_SET; + } + else + { + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_X = XFLAG_CLEAR; + } + FLAG_N = NFLAG_8(res); /* Undefined N behavior */ +} + + +void m68k_op_nbcd_8_al(void) +{ + uint ea = EA_AL_8(); + uint dst = m68ki_read_8(ea); + uint res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1()); + + if(res != 0x9a) + { + FLAG_V = ~res; /* Undefined V behavior */ + + if((res & 0x0f) == 0xa) + res = (res & 0xf0) + 0x10; + + res = MASK_OUT_ABOVE_8(res); + + FLAG_V &= res; /* Undefined V behavior part II */ + + m68ki_write_8(ea, MASK_OUT_ABOVE_8(res)); + + FLAG_Z |= res; + FLAG_C = CFLAG_SET; + FLAG_X = XFLAG_SET; + } + else + { + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + FLAG_X = XFLAG_CLEAR; + } + FLAG_N = NFLAG_8(res); /* Undefined N behavior */ +} + + +void m68k_op_neg_8_d(void) +{ + uint* r_dst = &DY; + uint res = 0 - MASK_OUT_ABOVE_8(*r_dst); + + FLAG_N = NFLAG_8(res); + FLAG_C = FLAG_X = CFLAG_8(res); + FLAG_V = *r_dst & res; + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_neg_8_ai(void) +{ + uint ea = EA_AY_AI_8(); + uint src = m68ki_read_8(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_8(res); + FLAG_C = FLAG_X = CFLAG_8(res); + FLAG_V = src & res; + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_neg_8_pi(void) +{ + uint ea = EA_AY_PI_8(); + uint src = m68ki_read_8(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_8(res); + FLAG_C = FLAG_X = CFLAG_8(res); + FLAG_V = src & res; + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_neg_8_pi7(void) +{ + uint ea = EA_A7_PI_8(); + uint src = m68ki_read_8(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_8(res); + FLAG_C = FLAG_X = CFLAG_8(res); + FLAG_V = src & res; + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_neg_8_pd(void) +{ + uint ea = EA_AY_PD_8(); + uint src = m68ki_read_8(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_8(res); + FLAG_C = FLAG_X = CFLAG_8(res); + FLAG_V = src & res; + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_neg_8_pd7(void) +{ + uint ea = EA_A7_PD_8(); + uint src = m68ki_read_8(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_8(res); + FLAG_C = FLAG_X = CFLAG_8(res); + FLAG_V = src & res; + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_neg_8_di(void) +{ + uint ea = EA_AY_DI_8(); + uint src = m68ki_read_8(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_8(res); + FLAG_C = FLAG_X = CFLAG_8(res); + FLAG_V = src & res; + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_neg_8_ix(void) +{ + uint ea = EA_AY_IX_8(); + uint src = m68ki_read_8(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_8(res); + FLAG_C = FLAG_X = CFLAG_8(res); + FLAG_V = src & res; + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_neg_8_aw(void) +{ + uint ea = EA_AW_8(); + uint src = m68ki_read_8(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_8(res); + FLAG_C = FLAG_X = CFLAG_8(res); + FLAG_V = src & res; + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_neg_8_al(void) +{ + uint ea = EA_AL_8(); + uint src = m68ki_read_8(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_8(res); + FLAG_C = FLAG_X = CFLAG_8(res); + FLAG_V = src & res; + FLAG_Z = MASK_OUT_ABOVE_8(res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_neg_16_d(void) +{ + uint* r_dst = &DY; + uint res = 0 - MASK_OUT_ABOVE_16(*r_dst); + + FLAG_N = NFLAG_16(res); + FLAG_C = FLAG_X = CFLAG_16(res); + FLAG_V = (*r_dst & res)>>8; + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_neg_16_ai(void) +{ + uint ea = EA_AY_AI_16(); + uint src = m68ki_read_16(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_16(res); + FLAG_C = FLAG_X = CFLAG_16(res); + FLAG_V = (src & res)>>8; + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_neg_16_pi(void) +{ + uint ea = EA_AY_PI_16(); + uint src = m68ki_read_16(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_16(res); + FLAG_C = FLAG_X = CFLAG_16(res); + FLAG_V = (src & res)>>8; + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_neg_16_pd(void) +{ + uint ea = EA_AY_PD_16(); + uint src = m68ki_read_16(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_16(res); + FLAG_C = FLAG_X = CFLAG_16(res); + FLAG_V = (src & res)>>8; + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_neg_16_di(void) +{ + uint ea = EA_AY_DI_16(); + uint src = m68ki_read_16(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_16(res); + FLAG_C = FLAG_X = CFLAG_16(res); + FLAG_V = (src & res)>>8; + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_neg_16_ix(void) +{ + uint ea = EA_AY_IX_16(); + uint src = m68ki_read_16(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_16(res); + FLAG_C = FLAG_X = CFLAG_16(res); + FLAG_V = (src & res)>>8; + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_neg_16_aw(void) +{ + uint ea = EA_AW_16(); + uint src = m68ki_read_16(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_16(res); + FLAG_C = FLAG_X = CFLAG_16(res); + FLAG_V = (src & res)>>8; + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_neg_16_al(void) +{ + uint ea = EA_AL_16(); + uint src = m68ki_read_16(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_16(res); + FLAG_C = FLAG_X = CFLAG_16(res); + FLAG_V = (src & res)>>8; + FLAG_Z = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_neg_32_d(void) +{ + uint* r_dst = &DY; + uint res = 0 - *r_dst; + + FLAG_N = NFLAG_32(res); + FLAG_C = FLAG_X = CFLAG_SUB_32(*r_dst, 0, res); + FLAG_V = (*r_dst & res)>>24; + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_neg_32_ai(void) +{ + uint ea = EA_AY_AI_32(); + uint src = m68ki_read_32(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_32(res); + FLAG_C = FLAG_X = CFLAG_SUB_32(src, 0, res); + FLAG_V = (src & res)>>24; + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_neg_32_pi(void) +{ + uint ea = EA_AY_PI_32(); + uint src = m68ki_read_32(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_32(res); + FLAG_C = FLAG_X = CFLAG_SUB_32(src, 0, res); + FLAG_V = (src & res)>>24; + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_neg_32_pd(void) +{ + uint ea = EA_AY_PD_32(); + uint src = m68ki_read_32(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_32(res); + FLAG_C = FLAG_X = CFLAG_SUB_32(src, 0, res); + FLAG_V = (src & res)>>24; + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_neg_32_di(void) +{ + uint ea = EA_AY_DI_32(); + uint src = m68ki_read_32(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_32(res); + FLAG_C = FLAG_X = CFLAG_SUB_32(src, 0, res); + FLAG_V = (src & res)>>24; + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_neg_32_ix(void) +{ + uint ea = EA_AY_IX_32(); + uint src = m68ki_read_32(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_32(res); + FLAG_C = FLAG_X = CFLAG_SUB_32(src, 0, res); + FLAG_V = (src & res)>>24; + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_neg_32_aw(void) +{ + uint ea = EA_AW_32(); + uint src = m68ki_read_32(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_32(res); + FLAG_C = FLAG_X = CFLAG_SUB_32(src, 0, res); + FLAG_V = (src & res)>>24; + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_neg_32_al(void) +{ + uint ea = EA_AL_32(); + uint src = m68ki_read_32(ea); + uint res = 0 - src; + + FLAG_N = NFLAG_32(res); + FLAG_C = FLAG_X = CFLAG_SUB_32(src, 0, res); + FLAG_V = (src & res)>>24; + FLAG_Z = MASK_OUT_ABOVE_32(res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_negx_8_d(void) +{ + uint* r_dst = &DY; + uint res = 0 - MASK_OUT_ABOVE_8(*r_dst) - XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = *r_dst & res; + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; +} + + +void m68k_op_negx_8_ai(void) +{ + uint ea = EA_AY_AI_8(); + uint src = m68ki_read_8(ea); + uint res = 0 - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = src & res; + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_negx_8_pi(void) +{ + uint ea = EA_AY_PI_8(); + uint src = m68ki_read_8(ea); + uint res = 0 - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = src & res; + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_negx_8_pi7(void) +{ + uint ea = EA_A7_PI_8(); + uint src = m68ki_read_8(ea); + uint res = 0 - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = src & res; + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_negx_8_pd(void) +{ + uint ea = EA_AY_PD_8(); + uint src = m68ki_read_8(ea); + uint res = 0 - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = src & res; + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_negx_8_pd7(void) +{ + uint ea = EA_A7_PD_8(); + uint src = m68ki_read_8(ea); + uint res = 0 - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = src & res; + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_negx_8_di(void) +{ + uint ea = EA_AY_DI_8(); + uint src = m68ki_read_8(ea); + uint res = 0 - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = src & res; + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_negx_8_ix(void) +{ + uint ea = EA_AY_IX_8(); + uint src = m68ki_read_8(ea); + uint res = 0 - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = src & res; + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_negx_8_aw(void) +{ + uint ea = EA_AW_8(); + uint src = m68ki_read_8(ea); + uint res = 0 - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = src & res; + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_negx_8_al(void) +{ + uint ea = EA_AL_8(); + uint src = m68ki_read_8(ea); + uint res = 0 - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = src & res; + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_negx_16_d(void) +{ + uint* r_dst = &DY; + uint res = 0 - MASK_OUT_ABOVE_16(*r_dst) - XFLAG_AS_1(); + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = (*r_dst & res)>>8; + + res = MASK_OUT_ABOVE_16(res); + FLAG_Z |= res; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; +} + + +void m68k_op_negx_16_ai(void) +{ + uint ea = EA_AY_AI_16(); + uint src = m68ki_read_16(ea); + uint res = 0 - MASK_OUT_ABOVE_16(src) - XFLAG_AS_1(); + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = (src & res)>>8; + + res = MASK_OUT_ABOVE_16(res); + FLAG_Z |= res; + + m68ki_write_16(ea, res); +} + + +void m68k_op_negx_16_pi(void) +{ + uint ea = EA_AY_PI_16(); + uint src = m68ki_read_16(ea); + uint res = 0 - MASK_OUT_ABOVE_16(src) - XFLAG_AS_1(); + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = (src & res)>>8; + + res = MASK_OUT_ABOVE_16(res); + FLAG_Z |= res; + + m68ki_write_16(ea, res); +} + + +void m68k_op_negx_16_pd(void) +{ + uint ea = EA_AY_PD_16(); + uint src = m68ki_read_16(ea); + uint res = 0 - MASK_OUT_ABOVE_16(src) - XFLAG_AS_1(); + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = (src & res)>>8; + + res = MASK_OUT_ABOVE_16(res); + FLAG_Z |= res; + + m68ki_write_16(ea, res); +} + + +void m68k_op_negx_16_di(void) +{ + uint ea = EA_AY_DI_16(); + uint src = m68ki_read_16(ea); + uint res = 0 - MASK_OUT_ABOVE_16(src) - XFLAG_AS_1(); + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = (src & res)>>8; + + res = MASK_OUT_ABOVE_16(res); + FLAG_Z |= res; + + m68ki_write_16(ea, res); +} + + +void m68k_op_negx_16_ix(void) +{ + uint ea = EA_AY_IX_16(); + uint src = m68ki_read_16(ea); + uint res = 0 - MASK_OUT_ABOVE_16(src) - XFLAG_AS_1(); + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = (src & res)>>8; + + res = MASK_OUT_ABOVE_16(res); + FLAG_Z |= res; + + m68ki_write_16(ea, res); +} + + +void m68k_op_negx_16_aw(void) +{ + uint ea = EA_AW_16(); + uint src = m68ki_read_16(ea); + uint res = 0 - MASK_OUT_ABOVE_16(src) - XFLAG_AS_1(); + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = (src & res)>>8; + + res = MASK_OUT_ABOVE_16(res); + FLAG_Z |= res; + + m68ki_write_16(ea, res); +} + + +void m68k_op_negx_16_al(void) +{ + uint ea = EA_AL_16(); + uint src = m68ki_read_16(ea); + uint res = 0 - MASK_OUT_ABOVE_16(src) - XFLAG_AS_1(); + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = (src & res)>>8; + + res = MASK_OUT_ABOVE_16(res); + FLAG_Z |= res; + + m68ki_write_16(ea, res); +} + + +void m68k_op_negx_32_d(void) +{ + uint* r_dst = &DY; + uint res = 0 - MASK_OUT_ABOVE_32(*r_dst) - XFLAG_AS_1(); + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(*r_dst, 0, res); + FLAG_V = (*r_dst & res)>>24; + + res = MASK_OUT_ABOVE_32(res); + FLAG_Z |= res; + + *r_dst = res; +} + + +void m68k_op_negx_32_ai(void) +{ + uint ea = EA_AY_AI_32(); + uint src = m68ki_read_32(ea); + uint res = 0 - MASK_OUT_ABOVE_32(src) - XFLAG_AS_1(); + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, 0, res); + FLAG_V = (src & res)>>24; + + res = MASK_OUT_ABOVE_32(res); + FLAG_Z |= res; + + m68ki_write_32(ea, res); +} + + +void m68k_op_negx_32_pi(void) +{ + uint ea = EA_AY_PI_32(); + uint src = m68ki_read_32(ea); + uint res = 0 - MASK_OUT_ABOVE_32(src) - XFLAG_AS_1(); + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, 0, res); + FLAG_V = (src & res)>>24; + + res = MASK_OUT_ABOVE_32(res); + FLAG_Z |= res; + + m68ki_write_32(ea, res); +} + + +void m68k_op_negx_32_pd(void) +{ + uint ea = EA_AY_PD_32(); + uint src = m68ki_read_32(ea); + uint res = 0 - MASK_OUT_ABOVE_32(src) - XFLAG_AS_1(); + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, 0, res); + FLAG_V = (src & res)>>24; + + res = MASK_OUT_ABOVE_32(res); + FLAG_Z |= res; + + m68ki_write_32(ea, res); +} + + +void m68k_op_negx_32_di(void) +{ + uint ea = EA_AY_DI_32(); + uint src = m68ki_read_32(ea); + uint res = 0 - MASK_OUT_ABOVE_32(src) - XFLAG_AS_1(); + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, 0, res); + FLAG_V = (src & res)>>24; + + res = MASK_OUT_ABOVE_32(res); + FLAG_Z |= res; + + m68ki_write_32(ea, res); +} + + +void m68k_op_negx_32_ix(void) +{ + uint ea = EA_AY_IX_32(); + uint src = m68ki_read_32(ea); + uint res = 0 - MASK_OUT_ABOVE_32(src) - XFLAG_AS_1(); + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, 0, res); + FLAG_V = (src & res)>>24; + + res = MASK_OUT_ABOVE_32(res); + FLAG_Z |= res; + + m68ki_write_32(ea, res); +} + + +void m68k_op_negx_32_aw(void) +{ + uint ea = EA_AW_32(); + uint src = m68ki_read_32(ea); + uint res = 0 - MASK_OUT_ABOVE_32(src) - XFLAG_AS_1(); + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, 0, res); + FLAG_V = (src & res)>>24; + + res = MASK_OUT_ABOVE_32(res); + FLAG_Z |= res; + + m68ki_write_32(ea, res); +} + + +void m68k_op_negx_32_al(void) +{ + uint ea = EA_AL_32(); + uint src = m68ki_read_32(ea); + uint res = 0 - MASK_OUT_ABOVE_32(src) - XFLAG_AS_1(); + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, 0, res); + FLAG_V = (src & res)>>24; + + res = MASK_OUT_ABOVE_32(res); + FLAG_Z |= res; + + m68ki_write_32(ea, res); +} + + +void m68k_op_nop(void) +{ + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ +} + + +void m68k_op_not_8_d(void) +{ + uint* r_dst = &DY; + uint res = MASK_OUT_ABOVE_8(~*r_dst); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_8_ai(void) +{ + uint ea = EA_AY_AI_8(); + uint res = MASK_OUT_ABOVE_8(~m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_8_pi(void) +{ + uint ea = EA_AY_PI_8(); + uint res = MASK_OUT_ABOVE_8(~m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_8_pi7(void) +{ + uint ea = EA_A7_PI_8(); + uint res = MASK_OUT_ABOVE_8(~m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_8_pd(void) +{ + uint ea = EA_AY_PD_8(); + uint res = MASK_OUT_ABOVE_8(~m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_8_pd7(void) +{ + uint ea = EA_A7_PD_8(); + uint res = MASK_OUT_ABOVE_8(~m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_8_di(void) +{ + uint ea = EA_AY_DI_8(); + uint res = MASK_OUT_ABOVE_8(~m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_8_ix(void) +{ + uint ea = EA_AY_IX_8(); + uint res = MASK_OUT_ABOVE_8(~m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_8_aw(void) +{ + uint ea = EA_AW_8(); + uint res = MASK_OUT_ABOVE_8(~m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_8_al(void) +{ + uint ea = EA_AL_8(); + uint res = MASK_OUT_ABOVE_8(~m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_16_d(void) +{ + uint* r_dst = &DY; + uint res = MASK_OUT_ABOVE_16(~*r_dst); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_16_ai(void) +{ + uint ea = EA_AY_AI_16(); + uint res = MASK_OUT_ABOVE_16(~m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_16_pi(void) +{ + uint ea = EA_AY_PI_16(); + uint res = MASK_OUT_ABOVE_16(~m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_16_pd(void) +{ + uint ea = EA_AY_PD_16(); + uint res = MASK_OUT_ABOVE_16(~m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_16_di(void) +{ + uint ea = EA_AY_DI_16(); + uint res = MASK_OUT_ABOVE_16(~m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_16_ix(void) +{ + uint ea = EA_AY_IX_16(); + uint res = MASK_OUT_ABOVE_16(~m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_16_aw(void) +{ + uint ea = EA_AW_16(); + uint res = MASK_OUT_ABOVE_16(~m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_16_al(void) +{ + uint ea = EA_AL_16(); + uint res = MASK_OUT_ABOVE_16(~m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_32_d(void) +{ + uint* r_dst = &DY; + uint res = *r_dst = MASK_OUT_ABOVE_32(~*r_dst); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_32_ai(void) +{ + uint ea = EA_AY_AI_32(); + uint res = MASK_OUT_ABOVE_32(~m68ki_read_32(ea)); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_32_pi(void) +{ + uint ea = EA_AY_PI_32(); + uint res = MASK_OUT_ABOVE_32(~m68ki_read_32(ea)); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_32_pd(void) +{ + uint ea = EA_AY_PD_32(); + uint res = MASK_OUT_ABOVE_32(~m68ki_read_32(ea)); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_32_di(void) +{ + uint ea = EA_AY_DI_32(); + uint res = MASK_OUT_ABOVE_32(~m68ki_read_32(ea)); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_32_ix(void) +{ + uint ea = EA_AY_IX_32(); + uint res = MASK_OUT_ABOVE_32(~m68ki_read_32(ea)); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_32_aw(void) +{ + uint ea = EA_AW_32(); + uint res = MASK_OUT_ABOVE_32(~m68ki_read_32(ea)); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_not_32_al(void) +{ + uint ea = EA_AL_32(); + uint res = MASK_OUT_ABOVE_32(~m68ki_read_32(ea)); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_8_er_d(void) +{ + uint res = MASK_OUT_ABOVE_8((DX |= MASK_OUT_ABOVE_8(DY))); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_8_er_ai(void) +{ + uint res = MASK_OUT_ABOVE_8((DX |= OPER_AY_AI_8())); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_8_er_pi(void) +{ + uint res = MASK_OUT_ABOVE_8((DX |= OPER_AY_PI_8())); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_8_er_pi7(void) +{ + uint res = MASK_OUT_ABOVE_8((DX |= OPER_A7_PI_8())); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_8_er_pd(void) +{ + uint res = MASK_OUT_ABOVE_8((DX |= OPER_AY_PD_8())); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_8_er_pd7(void) +{ + uint res = MASK_OUT_ABOVE_8((DX |= OPER_A7_PD_8())); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_8_er_di(void) +{ + uint res = MASK_OUT_ABOVE_8((DX |= OPER_AY_DI_8())); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_8_er_ix(void) +{ + uint res = MASK_OUT_ABOVE_8((DX |= OPER_AY_IX_8())); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_8_er_aw(void) +{ + uint res = MASK_OUT_ABOVE_8((DX |= OPER_AW_8())); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_8_er_al(void) +{ + uint res = MASK_OUT_ABOVE_8((DX |= OPER_AL_8())); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_8_er_pcdi(void) +{ + uint res = MASK_OUT_ABOVE_8((DX |= OPER_PCDI_8())); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_8_er_pcix(void) +{ + uint res = MASK_OUT_ABOVE_8((DX |= OPER_PCIX_8())); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_8_er_i(void) +{ + uint res = MASK_OUT_ABOVE_8((DX |= OPER_I_8())); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_16_er_d(void) +{ + uint res = MASK_OUT_ABOVE_16((DX |= MASK_OUT_ABOVE_16(DY))); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_16_er_ai(void) +{ + uint res = MASK_OUT_ABOVE_16((DX |= OPER_AY_AI_16())); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_16_er_pi(void) +{ + uint res = MASK_OUT_ABOVE_16((DX |= OPER_AY_PI_16())); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_16_er_pd(void) +{ + uint res = MASK_OUT_ABOVE_16((DX |= OPER_AY_PD_16())); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_16_er_di(void) +{ + uint res = MASK_OUT_ABOVE_16((DX |= OPER_AY_DI_16())); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_16_er_ix(void) +{ + uint res = MASK_OUT_ABOVE_16((DX |= OPER_AY_IX_16())); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_16_er_aw(void) +{ + uint res = MASK_OUT_ABOVE_16((DX |= OPER_AW_16())); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_16_er_al(void) +{ + uint res = MASK_OUT_ABOVE_16((DX |= OPER_AL_16())); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_16_er_pcdi(void) +{ + uint res = MASK_OUT_ABOVE_16((DX |= OPER_PCDI_16())); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_16_er_pcix(void) +{ + uint res = MASK_OUT_ABOVE_16((DX |= OPER_PCIX_16())); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_16_er_i(void) +{ + uint res = MASK_OUT_ABOVE_16((DX |= OPER_I_16())); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_32_er_d(void) +{ + uint res = DX |= DY; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_32_er_ai(void) +{ + uint res = DX |= OPER_AY_AI_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_32_er_pi(void) +{ + uint res = DX |= OPER_AY_PI_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_32_er_pd(void) +{ + uint res = DX |= OPER_AY_PD_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_32_er_di(void) +{ + uint res = DX |= OPER_AY_DI_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_32_er_ix(void) +{ + uint res = DX |= OPER_AY_IX_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_32_er_aw(void) +{ + uint res = DX |= OPER_AW_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_32_er_al(void) +{ + uint res = DX |= OPER_AL_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_32_er_pcdi(void) +{ + uint res = DX |= OPER_PCDI_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_32_er_pcix(void) +{ + uint res = DX |= OPER_PCIX_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_32_er_i(void) +{ + uint res = DX |= OPER_I_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_8_re_ai(void) +{ + uint ea = EA_AY_AI_8(); + uint res = MASK_OUT_ABOVE_8(DX | m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_8_re_pi(void) +{ + uint ea = EA_AY_PI_8(); + uint res = MASK_OUT_ABOVE_8(DX | m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_8_re_pi7(void) +{ + uint ea = EA_A7_PI_8(); + uint res = MASK_OUT_ABOVE_8(DX | m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_8_re_pd(void) +{ + uint ea = EA_AY_PD_8(); + uint res = MASK_OUT_ABOVE_8(DX | m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_8_re_pd7(void) +{ + uint ea = EA_A7_PD_8(); + uint res = MASK_OUT_ABOVE_8(DX | m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_8_re_di(void) +{ + uint ea = EA_AY_DI_8(); + uint res = MASK_OUT_ABOVE_8(DX | m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_8_re_ix(void) +{ + uint ea = EA_AY_IX_8(); + uint res = MASK_OUT_ABOVE_8(DX | m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_8_re_aw(void) +{ + uint ea = EA_AW_8(); + uint res = MASK_OUT_ABOVE_8(DX | m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_8_re_al(void) +{ + uint ea = EA_AL_8(); + uint res = MASK_OUT_ABOVE_8(DX | m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_16_re_ai(void) +{ + uint ea = EA_AY_AI_16(); + uint res = MASK_OUT_ABOVE_16(DX | m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_16_re_pi(void) +{ + uint ea = EA_AY_PI_16(); + uint res = MASK_OUT_ABOVE_16(DX | m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_16_re_pd(void) +{ + uint ea = EA_AY_PD_16(); + uint res = MASK_OUT_ABOVE_16(DX | m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_16_re_di(void) +{ + uint ea = EA_AY_DI_16(); + uint res = MASK_OUT_ABOVE_16(DX | m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_16_re_ix(void) +{ + uint ea = EA_AY_IX_16(); + uint res = MASK_OUT_ABOVE_16(DX | m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_16_re_aw(void) +{ + uint ea = EA_AW_16(); + uint res = MASK_OUT_ABOVE_16(DX | m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_16_re_al(void) +{ + uint ea = EA_AL_16(); + uint res = MASK_OUT_ABOVE_16(DX | m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_32_re_ai(void) +{ + uint ea = EA_AY_AI_32(); + uint res = DX | m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_32_re_pi(void) +{ + uint ea = EA_AY_PI_32(); + uint res = DX | m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_32_re_pd(void) +{ + uint ea = EA_AY_PD_32(); + uint res = DX | m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_32_re_di(void) +{ + uint ea = EA_AY_DI_32(); + uint res = DX | m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_32_re_ix(void) +{ + uint ea = EA_AY_IX_32(); + uint res = DX | m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_32_re_aw(void) +{ + uint ea = EA_AW_32(); + uint res = DX | m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_or_32_re_al(void) +{ + uint ea = EA_AL_32(); + uint res = DX | m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_8_d(void) +{ + uint res = MASK_OUT_ABOVE_8((DY |= OPER_I_8())); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_8_ai(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_AI_8(); + uint res = MASK_OUT_ABOVE_8(src | m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_8_pi(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_PI_8(); + uint res = MASK_OUT_ABOVE_8(src | m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_8_pi7(void) +{ + uint src = OPER_I_8(); + uint ea = EA_A7_PI_8(); + uint res = MASK_OUT_ABOVE_8(src | m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_8_pd(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_PD_8(); + uint res = MASK_OUT_ABOVE_8(src | m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_8_pd7(void) +{ + uint src = OPER_I_8(); + uint ea = EA_A7_PD_8(); + uint res = MASK_OUT_ABOVE_8(src | m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_8_di(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_DI_8(); + uint res = MASK_OUT_ABOVE_8(src | m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_8_ix(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_IX_8(); + uint res = MASK_OUT_ABOVE_8(src | m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_8_aw(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AW_8(); + uint res = MASK_OUT_ABOVE_8(src | m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_8_al(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AL_8(); + uint res = MASK_OUT_ABOVE_8(src | m68ki_read_8(ea)); + + m68ki_write_8(ea, res); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_16_d(void) +{ + uint res = MASK_OUT_ABOVE_16(DY |= OPER_I_16()); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_16_ai(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_AI_16(); + uint res = MASK_OUT_ABOVE_16(src | m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_16_pi(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_PI_16(); + uint res = MASK_OUT_ABOVE_16(src | m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_16_pd(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_PD_16(); + uint res = MASK_OUT_ABOVE_16(src | m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_16_di(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_DI_16(); + uint res = MASK_OUT_ABOVE_16(src | m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_16_ix(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_IX_16(); + uint res = MASK_OUT_ABOVE_16(src | m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_16_aw(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AW_16(); + uint res = MASK_OUT_ABOVE_16(src | m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_16_al(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AL_16(); + uint res = MASK_OUT_ABOVE_16(src | m68ki_read_16(ea)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_32_d(void) +{ + uint res = DY |= OPER_I_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_32_ai(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_AI_32(); + uint res = src | m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_32_pi(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_PI_32(); + uint res = src | m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_32_pd(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_PD_32(); + uint res = src | m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_32_di(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_DI_32(); + uint res = src | m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_32_ix(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_IX_32(); + uint res = src | m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_32_aw(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AW_32(); + uint res = src | m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_32_al(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AL_32(); + uint res = src | m68ki_read_32(ea); + + m68ki_write_32(ea, res); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ori_16_toc(void) +{ + m68ki_set_ccr(m68ki_get_ccr() | OPER_I_16()); +} + + +void m68k_op_ori_16_tos(void) +{ + if(FLAG_S) + { + uint src = OPER_I_16(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr(m68ki_get_sr() | src); + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_pack_16_rr(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + /* Note: DX and DY are reversed in Motorola's docs */ + uint src = DY + OPER_I_16(); + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | ((src >> 4) & 0x00f0) | (src & 0x000f); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_pack_16_mm_ax7(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + /* Note: AX and AY are reversed in Motorola's docs */ + uint ea_src = EA_AY_PD_8(); + uint src = m68ki_read_8(ea_src); + ea_src = EA_AY_PD_8(); + src = ((src << 8) | m68ki_read_8(ea_src)) + OPER_I_16(); + + m68ki_write_8(EA_A7_PD_8(), ((src >> 4) & 0x00f0) | (src & 0x000f)); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_pack_16_mm_ay7(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + /* Note: AX and AY are reversed in Motorola's docs */ + uint ea_src = EA_A7_PD_8(); + uint src = m68ki_read_8(ea_src); + ea_src = EA_A7_PD_8(); + src = ((src << 8) | m68ki_read_8(ea_src)) + OPER_I_16(); + + m68ki_write_8(EA_AX_PD_8(), ((src >> 4) & 0x00f0) | (src & 0x000f)); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_pack_16_mm_axy7(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint ea_src = EA_A7_PD_8(); + uint src = m68ki_read_8(ea_src); + ea_src = EA_A7_PD_8(); + src = ((src << 8) | m68ki_read_8(ea_src)) + OPER_I_16(); + + m68ki_write_8(EA_A7_PD_8(), ((src >> 4) & 0x00f0) | (src & 0x000f)); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_pack_16_mm(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + /* Note: AX and AY are reversed in Motorola's docs */ + uint ea_src = EA_AY_PD_8(); + uint src = m68ki_read_8(ea_src); + ea_src = EA_AY_PD_8(); + src = ((src << 8) | m68ki_read_8(ea_src)) + OPER_I_16(); + + m68ki_write_8(EA_AX_PD_8(), ((src >> 4) & 0x00f0) | (src & 0x000f)); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_pea_32_ai(void) +{ + uint ea = EA_AY_AI_32(); + + m68ki_push_32(ea); +} + + +void m68k_op_pea_32_di(void) +{ + uint ea = EA_AY_DI_32(); + + m68ki_push_32(ea); +} + + +void m68k_op_pea_32_ix(void) +{ + uint ea = EA_AY_IX_32(); + + m68ki_push_32(ea); +} + + +void m68k_op_pea_32_aw(void) +{ + uint ea = EA_AW_32(); + + m68ki_push_32(ea); +} + + +void m68k_op_pea_32_al(void) +{ + uint ea = EA_AL_32(); + + m68ki_push_32(ea); +} + + +void m68k_op_pea_32_pcdi(void) +{ + uint ea = EA_PCDI_32(); + + m68ki_push_32(ea); +} + + +void m68k_op_pea_32_pcix(void) +{ + uint ea = EA_PCIX_32(); + + m68ki_push_32(ea); +} + + +void m68k_op_pflush_32(void) +{ + if(CPU_TYPE_IS_040_PLUS(CPU_TYPE)) + { + // Nothing to do, unless address translation cache is emulated + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_reset(void) +{ + if(FLAG_S) + { + m68ki_output_reset(); /* auto-disable (see m68kcpu.h) */ + USE_CYCLES(CYC_RESET); + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_ror_8_s(void) +{ + uint* r_dst = &DY; + uint orig_shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint shift = orig_shift & 7; + uint src = MASK_OUT_ABOVE_8(*r_dst); + uint res = ROR_8(src, shift); + + if(orig_shift != 0) + USE_CYCLES(orig_shift<> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_16(*r_dst); + uint res = ROR_16(src, shift); + + if(shift != 0) + USE_CYCLES(shift<> 9) - 1) & 7) + 1; + uint64 src = *r_dst; + uint res = ROR_32(src, shift); + + if(shift != 0) + USE_CYCLES(shift<> ((shift - 1) & 15)) << 8; + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_16(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ror_32_r(void) +{ + uint* r_dst = &DY; + uint orig_shift = DX & 0x3f; + uint shift = orig_shift & 31; + uint64 src = *r_dst; + uint res = ROR_32(src, shift); + + if(orig_shift != 0) + { + USE_CYCLES(orig_shift<> ((shift - 1) & 31)) << 8; + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_32(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ror_16_ai(void) +{ + uint ea = EA_AY_AI_16(); + uint src = m68ki_read_16(ea); + uint res = ROR_16(src, 1); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = src << 8; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ror_16_pi(void) +{ + uint ea = EA_AY_PI_16(); + uint src = m68ki_read_16(ea); + uint res = ROR_16(src, 1); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = src << 8; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ror_16_pd(void) +{ + uint ea = EA_AY_PD_16(); + uint src = m68ki_read_16(ea); + uint res = ROR_16(src, 1); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = src << 8; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ror_16_di(void) +{ + uint ea = EA_AY_DI_16(); + uint src = m68ki_read_16(ea); + uint res = ROR_16(src, 1); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = src << 8; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ror_16_ix(void) +{ + uint ea = EA_AY_IX_16(); + uint src = m68ki_read_16(ea); + uint res = ROR_16(src, 1); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = src << 8; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ror_16_aw(void) +{ + uint ea = EA_AW_16(); + uint src = m68ki_read_16(ea); + uint res = ROR_16(src, 1); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = src << 8; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_ror_16_al(void) +{ + uint ea = EA_AL_16(); + uint src = m68ki_read_16(ea); + uint res = ROR_16(src, 1); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = src << 8; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_rol_8_s(void) +{ + uint* r_dst = &DY; + uint orig_shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint shift = orig_shift & 7; + uint src = MASK_OUT_ABOVE_8(*r_dst); + uint res = ROL_8(src, shift); + + if(orig_shift != 0) + USE_CYCLES(orig_shift<> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_16(*r_dst); + uint res = ROL_16(src, shift); + + if(shift != 0) + USE_CYCLES(shift<> (8-shift); + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_rol_32_s(void) +{ + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint64 src = *r_dst; + uint res = ROL_32(src, shift); + + if(shift != 0) + USE_CYCLES(shift<> (24-shift); + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_rol_8_r(void) +{ + uint* r_dst = &DY; + uint orig_shift = DX & 0x3f; + uint shift = orig_shift & 7; + uint src = MASK_OUT_ABOVE_8(*r_dst); + uint res = ROL_8(src, shift); + + if(orig_shift != 0) + { + USE_CYCLES(orig_shift<> 8; + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + FLAG_C = (src & 1)<<8; + FLAG_N = NFLAG_16(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_16(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_rol_32_r(void) +{ + uint* r_dst = &DY; + uint orig_shift = DX & 0x3f; + uint shift = orig_shift & 31; + uint64 src = *r_dst; + uint res = ROL_32(src, shift); + + if(orig_shift != 0) + { + USE_CYCLES(orig_shift<> (32 - shift)) << 8; + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = CFLAG_CLEAR; + FLAG_N = NFLAG_32(src); + FLAG_Z = src; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_rol_16_ai(void) +{ + uint ea = EA_AY_AI_16(); + uint src = m68ki_read_16(ea); + uint res = MASK_OUT_ABOVE_16(ROL_16(src, 1)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = src >> 7; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_rol_16_pi(void) +{ + uint ea = EA_AY_PI_16(); + uint src = m68ki_read_16(ea); + uint res = MASK_OUT_ABOVE_16(ROL_16(src, 1)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = src >> 7; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_rol_16_pd(void) +{ + uint ea = EA_AY_PD_16(); + uint src = m68ki_read_16(ea); + uint res = MASK_OUT_ABOVE_16(ROL_16(src, 1)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = src >> 7; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_rol_16_di(void) +{ + uint ea = EA_AY_DI_16(); + uint src = m68ki_read_16(ea); + uint res = MASK_OUT_ABOVE_16(ROL_16(src, 1)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = src >> 7; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_rol_16_ix(void) +{ + uint ea = EA_AY_IX_16(); + uint src = m68ki_read_16(ea); + uint res = MASK_OUT_ABOVE_16(ROL_16(src, 1)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = src >> 7; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_rol_16_aw(void) +{ + uint ea = EA_AW_16(); + uint src = m68ki_read_16(ea); + uint res = MASK_OUT_ABOVE_16(ROL_16(src, 1)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = src >> 7; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_rol_16_al(void) +{ + uint ea = EA_AL_16(); + uint src = m68ki_read_16(ea); + uint res = MASK_OUT_ABOVE_16(ROL_16(src, 1)); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_C = src >> 7; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_roxr_8_s(void) +{ + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_8(*r_dst); + uint res = ROR_9(src | (XFLAG_AS_1() << 8), shift); + + if(shift != 0) + USE_CYCLES(shift<> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_16(*r_dst); + uint res = ROR_17(src | (XFLAG_AS_1() << 16), shift); + + if(shift != 0) + USE_CYCLES(shift<> 8; + res = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_roxr_32_s(void) +{ +#if M68K_USE_64_BIT + + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint64 src = *r_dst; + uint64 res = src | (((uint64)XFLAG_AS_1()) << 32); + + if(shift != 0) + USE_CYCLES(shift<> 24; + res = MASK_OUT_ABOVE_32(res); + + *r_dst = res; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + +#else + + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint src = *r_dst; + uint res = MASK_OUT_ABOVE_32((ROR_33(src, shift) & ~(1 << (32 - shift))) | (XFLAG_AS_1() << (32 - shift))); + uint new_x_flag = src & (1 << (shift - 1)); + + if(shift != 0) + USE_CYCLES(shift<> 8; + res = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = FLAG_X; + FLAG_N = NFLAG_16(*r_dst); + FLAG_Z = MASK_OUT_ABOVE_16(*r_dst); + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_roxr_32_r(void) +{ +#if M68K_USE_64_BIT + + uint* r_dst = &DY; + uint orig_shift = DX & 0x3f; + + if(orig_shift != 0) + { + uint shift = orig_shift % 33; + uint64 src = *r_dst; + uint64 res = src | (((uint64)XFLAG_AS_1()) << 32); + + res = ROR_33_64(res, shift); + + USE_CYCLES(orig_shift<> 24; + res = MASK_OUT_ABOVE_32(res); + + *r_dst = res; + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = FLAG_X; + FLAG_N = NFLAG_32(*r_dst); + FLAG_Z = *r_dst; + FLAG_V = VFLAG_CLEAR; + +#else + + uint* r_dst = &DY; + uint orig_shift = DX & 0x3f; + uint shift = orig_shift % 33; + uint src = *r_dst; + uint res = MASK_OUT_ABOVE_32((ROR_33(src, shift) & ~(1 << (32 - shift))) | (XFLAG_AS_1() << (32 - shift))); + uint new_x_flag = src & (1 << (shift - 1)); + + if(orig_shift != 0) + USE_CYCLES(orig_shift<> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_roxr_16_pi(void) +{ + uint ea = EA_AY_PI_16(); + uint src = m68ki_read_16(ea); + uint res = ROR_17(src | (XFLAG_AS_1() << 16), 1); + + FLAG_C = FLAG_X = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_roxr_16_pd(void) +{ + uint ea = EA_AY_PD_16(); + uint src = m68ki_read_16(ea); + uint res = ROR_17(src | (XFLAG_AS_1() << 16), 1); + + FLAG_C = FLAG_X = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_roxr_16_di(void) +{ + uint ea = EA_AY_DI_16(); + uint src = m68ki_read_16(ea); + uint res = ROR_17(src | (XFLAG_AS_1() << 16), 1); + + FLAG_C = FLAG_X = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_roxr_16_ix(void) +{ + uint ea = EA_AY_IX_16(); + uint src = m68ki_read_16(ea); + uint res = ROR_17(src | (XFLAG_AS_1() << 16), 1); + + FLAG_C = FLAG_X = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_roxr_16_aw(void) +{ + uint ea = EA_AW_16(); + uint src = m68ki_read_16(ea); + uint res = ROR_17(src | (XFLAG_AS_1() << 16), 1); + + FLAG_C = FLAG_X = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_roxr_16_al(void) +{ + uint ea = EA_AL_16(); + uint src = m68ki_read_16(ea); + uint res = ROR_17(src | (XFLAG_AS_1() << 16), 1); + + FLAG_C = FLAG_X = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_roxl_8_s(void) +{ + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_8(*r_dst); + uint res = ROL_9(src | (XFLAG_AS_1() << 8), shift); + + if(shift != 0) + USE_CYCLES(shift<> 9) - 1) & 7) + 1; + uint src = MASK_OUT_ABOVE_16(*r_dst); + uint res = ROL_17(src | (XFLAG_AS_1() << 16), shift); + + if(shift != 0) + USE_CYCLES(shift<> 8; + res = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_roxl_32_s(void) +{ +#if M68K_USE_64_BIT + + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint64 src = *r_dst; + uint64 res = src | (((uint64)XFLAG_AS_1()) << 32); + + if(shift != 0) + USE_CYCLES(shift<> 24; + res = MASK_OUT_ABOVE_32(res); + + *r_dst = res; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + +#else + + uint* r_dst = &DY; + uint shift = (((REG_IR >> 9) - 1) & 7) + 1; + uint src = *r_dst; + uint res = MASK_OUT_ABOVE_32((ROL_33(src, shift) & ~(1 << (shift - 1))) | (XFLAG_AS_1() << (shift - 1))); + uint new_x_flag = src & (1 << (32 - shift)); + + if(shift != 0) + USE_CYCLES(shift<> 8; + res = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = FLAG_X; + FLAG_N = NFLAG_16(*r_dst); + FLAG_Z = MASK_OUT_ABOVE_16(*r_dst); + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_roxl_32_r(void) +{ +#if M68K_USE_64_BIT + + uint* r_dst = &DY; + uint orig_shift = DX & 0x3f; + + if(orig_shift != 0) + { + uint shift = orig_shift % 33; + uint64 src = *r_dst; + uint64 res = src | (((uint64)XFLAG_AS_1()) << 32); + + res = ROL_33_64(res, shift); + + USE_CYCLES(orig_shift<> 24; + res = MASK_OUT_ABOVE_32(res); + + *r_dst = res; + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + return; + } + + FLAG_C = FLAG_X; + FLAG_N = NFLAG_32(*r_dst); + FLAG_Z = *r_dst; + FLAG_V = VFLAG_CLEAR; + +#else + + uint* r_dst = &DY; + uint orig_shift = DX & 0x3f; + uint shift = orig_shift % 33; + uint src = *r_dst; + uint res = MASK_OUT_ABOVE_32((ROL_33(src, shift) & ~(1 << (shift - 1))) | (XFLAG_AS_1() << (shift - 1))); + uint new_x_flag = src & (1 << (32 - shift)); + + if(orig_shift != 0) + USE_CYCLES(orig_shift<> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_roxl_16_pi(void) +{ + uint ea = EA_AY_PI_16(); + uint src = m68ki_read_16(ea); + uint res = ROL_17(src | (XFLAG_AS_1() << 16), 1); + + FLAG_C = FLAG_X = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_roxl_16_pd(void) +{ + uint ea = EA_AY_PD_16(); + uint src = m68ki_read_16(ea); + uint res = ROL_17(src | (XFLAG_AS_1() << 16), 1); + + FLAG_C = FLAG_X = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_roxl_16_di(void) +{ + uint ea = EA_AY_DI_16(); + uint src = m68ki_read_16(ea); + uint res = ROL_17(src | (XFLAG_AS_1() << 16), 1); + + FLAG_C = FLAG_X = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_roxl_16_ix(void) +{ + uint ea = EA_AY_IX_16(); + uint src = m68ki_read_16(ea); + uint res = ROL_17(src | (XFLAG_AS_1() << 16), 1); + + FLAG_C = FLAG_X = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_roxl_16_aw(void) +{ + uint ea = EA_AW_16(); + uint src = m68ki_read_16(ea); + uint res = ROL_17(src | (XFLAG_AS_1() << 16), 1); + + FLAG_C = FLAG_X = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_roxl_16_al(void) +{ + uint ea = EA_AL_16(); + uint src = m68ki_read_16(ea); + uint res = ROL_17(src | (XFLAG_AS_1() << 16), 1); + + FLAG_C = FLAG_X = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16(ea, res); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_rtd_32(void) +{ + if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) + { + uint new_pc = m68ki_pull_32(); + + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + REG_A[7] = MASK_OUT_ABOVE_32(REG_A[7] + MAKE_INT_16(OPER_I_16())); + m68ki_jump(new_pc); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_rte_32(void) +{ + if(FLAG_S) + { + uint new_sr; + uint new_pc; + uint format_word; + + m68ki_rte_callback(); /* auto-disable (see m68kcpu.h) */ + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + + if(CPU_TYPE_IS_000(CPU_TYPE)) + { + new_sr = m68ki_pull_16(); + new_pc = m68ki_pull_32(); + m68ki_jump(new_pc); + m68ki_set_sr(new_sr); + + CPU_INSTR_MODE = INSTRUCTION_YES; + CPU_RUN_MODE = RUN_MODE_NORMAL; + + return; + } + + if(CPU_TYPE_IS_010(CPU_TYPE)) + { + format_word = m68ki_read_16(REG_A[7]+6) >> 12; + if(format_word == 0) + { + new_sr = m68ki_pull_16(); + new_pc = m68ki_pull_32(); + m68ki_fake_pull_16(); /* format word */ + m68ki_jump(new_pc); + m68ki_set_sr(new_sr); + CPU_INSTR_MODE = INSTRUCTION_YES; + CPU_RUN_MODE = RUN_MODE_NORMAL; + return; + } + CPU_INSTR_MODE = INSTRUCTION_YES; + CPU_RUN_MODE = RUN_MODE_NORMAL; + /* Not handling bus fault (9) */ + m68ki_exception_format_error(); + return; + } + + /* Otherwise it's 020 */ +rte_loop: + format_word = m68ki_read_16(REG_A[7]+6) >> 12; + switch(format_word) + { + case 0: /* Normal */ + new_sr = m68ki_pull_16(); + new_pc = m68ki_pull_32(); + m68ki_fake_pull_16(); /* format word */ + m68ki_jump(new_pc); + m68ki_set_sr(new_sr); + CPU_INSTR_MODE = INSTRUCTION_YES; + CPU_RUN_MODE = RUN_MODE_NORMAL; + return; + case 1: /* Throwaway */ + new_sr = m68ki_pull_16(); + m68ki_fake_pull_32(); /* program counter */ + m68ki_fake_pull_16(); /* format word */ + m68ki_set_sr_noint(new_sr); + goto rte_loop; + case 2: /* Trap */ + new_sr = m68ki_pull_16(); + new_pc = m68ki_pull_32(); + m68ki_fake_pull_16(); /* format word */ + m68ki_fake_pull_32(); /* address */ + m68ki_jump(new_pc); + m68ki_set_sr(new_sr); + CPU_INSTR_MODE = INSTRUCTION_YES; + CPU_RUN_MODE = RUN_MODE_NORMAL; + return; + } + /* Not handling long or short bus fault */ + CPU_INSTR_MODE = INSTRUCTION_YES; + CPU_RUN_MODE = RUN_MODE_NORMAL; + m68ki_exception_format_error(); + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_rtm_32(void) +{ + if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) + { + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", + m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, + m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_rtr_32(void) +{ + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_set_ccr(m68ki_pull_16()); + m68ki_jump(m68ki_pull_32()); +} + + +void m68k_op_rts_32(void) +{ + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + m68ki_jump(m68ki_pull_32()); +} + + +void m68k_op_sbcd_8_rr(void) +{ + uint* r_dst = &DX; + uint src = DY; + uint dst = *r_dst; + uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(); + +// FLAG_V = ~res; /* Undefined V behavior */ + FLAG_V = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to assume cleared. */ + + if(res > 9) + res -= 6; + res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); + if(res > 0x99) + { + res += 0xa0; + FLAG_X = FLAG_C = CFLAG_SET; + FLAG_N = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */ + } + else + FLAG_N = FLAG_X = FLAG_C = 0; + + res = MASK_OUT_ABOVE_8(res); + +// FLAG_V &= res; /* Undefined V behavior part II */ +// FLAG_N = NFLAG_8(res); /* Undefined N behavior */ + FLAG_Z |= res; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; +} + + +void m68k_op_sbcd_8_mm_ax7(void) +{ + uint src = OPER_AY_PD_8(); + uint ea = EA_A7_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(); + +// FLAG_V = ~res; /* Undefined V behavior */ + FLAG_V = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to return zero. */ + + if(res > 9) + res -= 6; + res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); + if(res > 0x99) + { + res += 0xa0; + FLAG_X = FLAG_C = CFLAG_SET; + FLAG_N = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */ + } + else + FLAG_N = FLAG_X = FLAG_C = 0; + + res = MASK_OUT_ABOVE_8(res); + +// FLAG_V &= res; /* Undefined V behavior part II */ +// FLAG_N = NFLAG_8(res); /* Undefined N behavior */ + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_sbcd_8_mm_ay7(void) +{ + uint src = OPER_A7_PD_8(); + uint ea = EA_AX_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(); + +// FLAG_V = ~res; /* Undefined V behavior */ + FLAG_V = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to return zero. */ + + if(res > 9) + res -= 6; + res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); + if(res > 0x99) + { + res += 0xa0; + FLAG_X = FLAG_C = CFLAG_SET; + FLAG_N = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */ + } + else + FLAG_N = FLAG_X = FLAG_C = 0; + + res = MASK_OUT_ABOVE_8(res); + +// FLAG_V &= res; /* Undefined V behavior part II */ +// FLAG_N = NFLAG_8(res); /* Undefined N behavior */ + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_sbcd_8_mm_axy7(void) +{ + uint src = OPER_A7_PD_8(); + uint ea = EA_A7_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(); + +// FLAG_V = ~res; /* Undefined V behavior */ + FLAG_V = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to return zero. */ + + if(res > 9) + res -= 6; + res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); + if(res > 0x99) + { + res += 0xa0; + FLAG_X = FLAG_C = CFLAG_SET; + FLAG_N = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */ + } + else + FLAG_N = FLAG_X = FLAG_C = 0; + + res = MASK_OUT_ABOVE_8(res); + +// FLAG_V &= res; /* Undefined V behavior part II */ +// FLAG_N = NFLAG_8(res); /* Undefined N behavior */ + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_sbcd_8_mm(void) +{ + uint src = OPER_AY_PD_8(); + uint ea = EA_AX_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(); + +// FLAG_V = ~res; /* Undefined V behavior */ + FLAG_V = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to return zero. */ + + if(res > 9) + res -= 6; + res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); + if(res > 0x99) + { + res += 0xa0; + FLAG_X = FLAG_C = CFLAG_SET; + FLAG_N = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */ + } + else + FLAG_N = FLAG_X = FLAG_C = 0; + + res = MASK_OUT_ABOVE_8(res); + +// FLAG_V &= res; /* Undefined V behavior part II */ +// FLAG_N = NFLAG_8(res); /* Undefined N behavior */ + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_st_8_d(void) +{ + DY |= 0xff; +} + + +void m68k_op_st_8_ai(void) +{ + m68ki_write_8(EA_AY_AI_8(), 0xff); +} + + +void m68k_op_st_8_pi(void) +{ + m68ki_write_8(EA_AY_PI_8(), 0xff); +} + + +void m68k_op_st_8_pi7(void) +{ + m68ki_write_8(EA_A7_PI_8(), 0xff); +} + + +void m68k_op_st_8_pd(void) +{ + m68ki_write_8(EA_AY_PD_8(), 0xff); +} + + +void m68k_op_st_8_pd7(void) +{ + m68ki_write_8(EA_A7_PD_8(), 0xff); +} + + +void m68k_op_st_8_di(void) +{ + m68ki_write_8(EA_AY_DI_8(), 0xff); +} + + +void m68k_op_st_8_ix(void) +{ + m68ki_write_8(EA_AY_IX_8(), 0xff); +} + + +void m68k_op_st_8_aw(void) +{ + m68ki_write_8(EA_AW_8(), 0xff); +} + + +void m68k_op_st_8_al(void) +{ + m68ki_write_8(EA_AL_8(), 0xff); +} + + +void m68k_op_sf_8_d(void) +{ + DY &= 0xffffff00; +} + + +void m68k_op_sf_8_ai(void) +{ + m68ki_write_8(EA_AY_AI_8(), 0); +} + + +void m68k_op_sf_8_pi(void) +{ + m68ki_write_8(EA_AY_PI_8(), 0); +} + + +void m68k_op_sf_8_pi7(void) +{ + m68ki_write_8(EA_A7_PI_8(), 0); +} + + +void m68k_op_sf_8_pd(void) +{ + m68ki_write_8(EA_AY_PD_8(), 0); +} + + +void m68k_op_sf_8_pd7(void) +{ + m68ki_write_8(EA_A7_PD_8(), 0); +} + + +void m68k_op_sf_8_di(void) +{ + m68ki_write_8(EA_AY_DI_8(), 0); +} + + +void m68k_op_sf_8_ix(void) +{ + m68ki_write_8(EA_AY_IX_8(), 0); +} + + +void m68k_op_sf_8_aw(void) +{ + m68ki_write_8(EA_AW_8(), 0); +} + + +void m68k_op_sf_8_al(void) +{ + m68ki_write_8(EA_AL_8(), 0); +} + + +void m68k_op_shi_8_d(void) +{ + if(COND_HI()) + { + DY |= 0xff; + USE_CYCLES(CYC_SCC_R_TRUE); + return; + } + DY &= 0xffffff00; +} + + +void m68k_op_sls_8_d(void) +{ + if(COND_LS()) + { + DY |= 0xff; + USE_CYCLES(CYC_SCC_R_TRUE); + return; + } + DY &= 0xffffff00; +} + + +void m68k_op_scc_8_d(void) +{ + if(COND_CC()) + { + DY |= 0xff; + USE_CYCLES(CYC_SCC_R_TRUE); + return; + } + DY &= 0xffffff00; +} + + +void m68k_op_scs_8_d(void) +{ + if(COND_CS()) + { + DY |= 0xff; + USE_CYCLES(CYC_SCC_R_TRUE); + return; + } + DY &= 0xffffff00; +} + + +void m68k_op_sne_8_d(void) +{ + if(COND_NE()) + { + DY |= 0xff; + USE_CYCLES(CYC_SCC_R_TRUE); + return; + } + DY &= 0xffffff00; +} + + +void m68k_op_seq_8_d(void) +{ + if(COND_EQ()) + { + DY |= 0xff; + USE_CYCLES(CYC_SCC_R_TRUE); + return; + } + DY &= 0xffffff00; +} + + +void m68k_op_svc_8_d(void) +{ + if(COND_VC()) + { + DY |= 0xff; + USE_CYCLES(CYC_SCC_R_TRUE); + return; + } + DY &= 0xffffff00; +} + + +void m68k_op_svs_8_d(void) +{ + if(COND_VS()) + { + DY |= 0xff; + USE_CYCLES(CYC_SCC_R_TRUE); + return; + } + DY &= 0xffffff00; +} + + +void m68k_op_spl_8_d(void) +{ + if(COND_PL()) + { + DY |= 0xff; + USE_CYCLES(CYC_SCC_R_TRUE); + return; + } + DY &= 0xffffff00; +} + + +void m68k_op_smi_8_d(void) +{ + if(COND_MI()) + { + DY |= 0xff; + USE_CYCLES(CYC_SCC_R_TRUE); + return; + } + DY &= 0xffffff00; +} + + +void m68k_op_sge_8_d(void) +{ + if(COND_GE()) + { + DY |= 0xff; + USE_CYCLES(CYC_SCC_R_TRUE); + return; + } + DY &= 0xffffff00; +} + + +void m68k_op_slt_8_d(void) +{ + if(COND_LT()) + { + DY |= 0xff; + USE_CYCLES(CYC_SCC_R_TRUE); + return; + } + DY &= 0xffffff00; +} + + +void m68k_op_sgt_8_d(void) +{ + if(COND_GT()) + { + DY |= 0xff; + USE_CYCLES(CYC_SCC_R_TRUE); + return; + } + DY &= 0xffffff00; +} + + +void m68k_op_sle_8_d(void) +{ + if(COND_LE()) + { + DY |= 0xff; + USE_CYCLES(CYC_SCC_R_TRUE); + return; + } + DY &= 0xffffff00; +} + + +void m68k_op_shi_8_ai(void) +{ + m68ki_write_8(EA_AY_AI_8(), COND_HI() ? 0xff : 0); +} + + +void m68k_op_shi_8_pi(void) +{ + m68ki_write_8(EA_AY_PI_8(), COND_HI() ? 0xff : 0); +} + + +void m68k_op_shi_8_pi7(void) +{ + m68ki_write_8(EA_A7_PI_8(), COND_HI() ? 0xff : 0); +} + + +void m68k_op_shi_8_pd(void) +{ + m68ki_write_8(EA_AY_PD_8(), COND_HI() ? 0xff : 0); +} + + +void m68k_op_shi_8_pd7(void) +{ + m68ki_write_8(EA_A7_PD_8(), COND_HI() ? 0xff : 0); +} + + +void m68k_op_shi_8_di(void) +{ + m68ki_write_8(EA_AY_DI_8(), COND_HI() ? 0xff : 0); +} + + +void m68k_op_shi_8_ix(void) +{ + m68ki_write_8(EA_AY_IX_8(), COND_HI() ? 0xff : 0); +} + + +void m68k_op_shi_8_aw(void) +{ + m68ki_write_8(EA_AW_8(), COND_HI() ? 0xff : 0); +} + + +void m68k_op_shi_8_al(void) +{ + m68ki_write_8(EA_AL_8(), COND_HI() ? 0xff : 0); +} + + +void m68k_op_sls_8_ai(void) +{ + m68ki_write_8(EA_AY_AI_8(), COND_LS() ? 0xff : 0); +} + + +void m68k_op_sls_8_pi(void) +{ + m68ki_write_8(EA_AY_PI_8(), COND_LS() ? 0xff : 0); +} + + +void m68k_op_sls_8_pi7(void) +{ + m68ki_write_8(EA_A7_PI_8(), COND_LS() ? 0xff : 0); +} + + +void m68k_op_sls_8_pd(void) +{ + m68ki_write_8(EA_AY_PD_8(), COND_LS() ? 0xff : 0); +} + + +void m68k_op_sls_8_pd7(void) +{ + m68ki_write_8(EA_A7_PD_8(), COND_LS() ? 0xff : 0); +} + + +void m68k_op_sls_8_di(void) +{ + m68ki_write_8(EA_AY_DI_8(), COND_LS() ? 0xff : 0); +} + + +void m68k_op_sls_8_ix(void) +{ + m68ki_write_8(EA_AY_IX_8(), COND_LS() ? 0xff : 0); +} + + +void m68k_op_sls_8_aw(void) +{ + m68ki_write_8(EA_AW_8(), COND_LS() ? 0xff : 0); +} + + +void m68k_op_sls_8_al(void) +{ + m68ki_write_8(EA_AL_8(), COND_LS() ? 0xff : 0); +} + + +void m68k_op_scc_8_ai(void) +{ + m68ki_write_8(EA_AY_AI_8(), COND_CC() ? 0xff : 0); +} + + +void m68k_op_scc_8_pi(void) +{ + m68ki_write_8(EA_AY_PI_8(), COND_CC() ? 0xff : 0); +} + + +void m68k_op_scc_8_pi7(void) +{ + m68ki_write_8(EA_A7_PI_8(), COND_CC() ? 0xff : 0); +} + + +void m68k_op_scc_8_pd(void) +{ + m68ki_write_8(EA_AY_PD_8(), COND_CC() ? 0xff : 0); +} + + +void m68k_op_scc_8_pd7(void) +{ + m68ki_write_8(EA_A7_PD_8(), COND_CC() ? 0xff : 0); +} + + +void m68k_op_scc_8_di(void) +{ + m68ki_write_8(EA_AY_DI_8(), COND_CC() ? 0xff : 0); +} + + +void m68k_op_scc_8_ix(void) +{ + m68ki_write_8(EA_AY_IX_8(), COND_CC() ? 0xff : 0); +} + + +void m68k_op_scc_8_aw(void) +{ + m68ki_write_8(EA_AW_8(), COND_CC() ? 0xff : 0); +} + + +void m68k_op_scc_8_al(void) +{ + m68ki_write_8(EA_AL_8(), COND_CC() ? 0xff : 0); +} + + +void m68k_op_scs_8_ai(void) +{ + m68ki_write_8(EA_AY_AI_8(), COND_CS() ? 0xff : 0); +} + + +void m68k_op_scs_8_pi(void) +{ + m68ki_write_8(EA_AY_PI_8(), COND_CS() ? 0xff : 0); +} + + +void m68k_op_scs_8_pi7(void) +{ + m68ki_write_8(EA_A7_PI_8(), COND_CS() ? 0xff : 0); +} + + +void m68k_op_scs_8_pd(void) +{ + m68ki_write_8(EA_AY_PD_8(), COND_CS() ? 0xff : 0); +} + + +void m68k_op_scs_8_pd7(void) +{ + m68ki_write_8(EA_A7_PD_8(), COND_CS() ? 0xff : 0); +} + + +void m68k_op_scs_8_di(void) +{ + m68ki_write_8(EA_AY_DI_8(), COND_CS() ? 0xff : 0); +} + + +void m68k_op_scs_8_ix(void) +{ + m68ki_write_8(EA_AY_IX_8(), COND_CS() ? 0xff : 0); +} + + +void m68k_op_scs_8_aw(void) +{ + m68ki_write_8(EA_AW_8(), COND_CS() ? 0xff : 0); +} + + +void m68k_op_scs_8_al(void) +{ + m68ki_write_8(EA_AL_8(), COND_CS() ? 0xff : 0); +} + + +void m68k_op_sne_8_ai(void) +{ + m68ki_write_8(EA_AY_AI_8(), COND_NE() ? 0xff : 0); +} + + +void m68k_op_sne_8_pi(void) +{ + m68ki_write_8(EA_AY_PI_8(), COND_NE() ? 0xff : 0); +} + + +void m68k_op_sne_8_pi7(void) +{ + m68ki_write_8(EA_A7_PI_8(), COND_NE() ? 0xff : 0); +} + + +void m68k_op_sne_8_pd(void) +{ + m68ki_write_8(EA_AY_PD_8(), COND_NE() ? 0xff : 0); +} + + +void m68k_op_sne_8_pd7(void) +{ + m68ki_write_8(EA_A7_PD_8(), COND_NE() ? 0xff : 0); +} + + +void m68k_op_sne_8_di(void) +{ + m68ki_write_8(EA_AY_DI_8(), COND_NE() ? 0xff : 0); +} + + +void m68k_op_sne_8_ix(void) +{ + m68ki_write_8(EA_AY_IX_8(), COND_NE() ? 0xff : 0); +} + + +void m68k_op_sne_8_aw(void) +{ + m68ki_write_8(EA_AW_8(), COND_NE() ? 0xff : 0); +} + + +void m68k_op_sne_8_al(void) +{ + m68ki_write_8(EA_AL_8(), COND_NE() ? 0xff : 0); +} + + +void m68k_op_seq_8_ai(void) +{ + m68ki_write_8(EA_AY_AI_8(), COND_EQ() ? 0xff : 0); +} + + +void m68k_op_seq_8_pi(void) +{ + m68ki_write_8(EA_AY_PI_8(), COND_EQ() ? 0xff : 0); +} + + +void m68k_op_seq_8_pi7(void) +{ + m68ki_write_8(EA_A7_PI_8(), COND_EQ() ? 0xff : 0); +} + + +void m68k_op_seq_8_pd(void) +{ + m68ki_write_8(EA_AY_PD_8(), COND_EQ() ? 0xff : 0); +} + + +void m68k_op_seq_8_pd7(void) +{ + m68ki_write_8(EA_A7_PD_8(), COND_EQ() ? 0xff : 0); +} + + +void m68k_op_seq_8_di(void) +{ + m68ki_write_8(EA_AY_DI_8(), COND_EQ() ? 0xff : 0); +} + + +void m68k_op_seq_8_ix(void) +{ + m68ki_write_8(EA_AY_IX_8(), COND_EQ() ? 0xff : 0); +} + + +void m68k_op_seq_8_aw(void) +{ + m68ki_write_8(EA_AW_8(), COND_EQ() ? 0xff : 0); +} + + +void m68k_op_seq_8_al(void) +{ + m68ki_write_8(EA_AL_8(), COND_EQ() ? 0xff : 0); +} + + +void m68k_op_svc_8_ai(void) +{ + m68ki_write_8(EA_AY_AI_8(), COND_VC() ? 0xff : 0); +} + + +void m68k_op_svc_8_pi(void) +{ + m68ki_write_8(EA_AY_PI_8(), COND_VC() ? 0xff : 0); +} + + +void m68k_op_svc_8_pi7(void) +{ + m68ki_write_8(EA_A7_PI_8(), COND_VC() ? 0xff : 0); +} + + +void m68k_op_svc_8_pd(void) +{ + m68ki_write_8(EA_AY_PD_8(), COND_VC() ? 0xff : 0); +} + + +void m68k_op_svc_8_pd7(void) +{ + m68ki_write_8(EA_A7_PD_8(), COND_VC() ? 0xff : 0); +} + + +void m68k_op_svc_8_di(void) +{ + m68ki_write_8(EA_AY_DI_8(), COND_VC() ? 0xff : 0); +} + + +void m68k_op_svc_8_ix(void) +{ + m68ki_write_8(EA_AY_IX_8(), COND_VC() ? 0xff : 0); +} + + +void m68k_op_svc_8_aw(void) +{ + m68ki_write_8(EA_AW_8(), COND_VC() ? 0xff : 0); +} + + +void m68k_op_svc_8_al(void) +{ + m68ki_write_8(EA_AL_8(), COND_VC() ? 0xff : 0); +} + + +void m68k_op_svs_8_ai(void) +{ + m68ki_write_8(EA_AY_AI_8(), COND_VS() ? 0xff : 0); +} + + +void m68k_op_svs_8_pi(void) +{ + m68ki_write_8(EA_AY_PI_8(), COND_VS() ? 0xff : 0); +} + + +void m68k_op_svs_8_pi7(void) +{ + m68ki_write_8(EA_A7_PI_8(), COND_VS() ? 0xff : 0); +} + + +void m68k_op_svs_8_pd(void) +{ + m68ki_write_8(EA_AY_PD_8(), COND_VS() ? 0xff : 0); +} + + +void m68k_op_svs_8_pd7(void) +{ + m68ki_write_8(EA_A7_PD_8(), COND_VS() ? 0xff : 0); +} + + +void m68k_op_svs_8_di(void) +{ + m68ki_write_8(EA_AY_DI_8(), COND_VS() ? 0xff : 0); +} + + +void m68k_op_svs_8_ix(void) +{ + m68ki_write_8(EA_AY_IX_8(), COND_VS() ? 0xff : 0); +} + + +void m68k_op_svs_8_aw(void) +{ + m68ki_write_8(EA_AW_8(), COND_VS() ? 0xff : 0); +} + + +void m68k_op_svs_8_al(void) +{ + m68ki_write_8(EA_AL_8(), COND_VS() ? 0xff : 0); +} + + +void m68k_op_spl_8_ai(void) +{ + m68ki_write_8(EA_AY_AI_8(), COND_PL() ? 0xff : 0); +} + + +void m68k_op_spl_8_pi(void) +{ + m68ki_write_8(EA_AY_PI_8(), COND_PL() ? 0xff : 0); +} + + +void m68k_op_spl_8_pi7(void) +{ + m68ki_write_8(EA_A7_PI_8(), COND_PL() ? 0xff : 0); +} + + +void m68k_op_spl_8_pd(void) +{ + m68ki_write_8(EA_AY_PD_8(), COND_PL() ? 0xff : 0); +} + + +void m68k_op_spl_8_pd7(void) +{ + m68ki_write_8(EA_A7_PD_8(), COND_PL() ? 0xff : 0); +} + + +void m68k_op_spl_8_di(void) +{ + m68ki_write_8(EA_AY_DI_8(), COND_PL() ? 0xff : 0); +} + + +void m68k_op_spl_8_ix(void) +{ + m68ki_write_8(EA_AY_IX_8(), COND_PL() ? 0xff : 0); +} + + +void m68k_op_spl_8_aw(void) +{ + m68ki_write_8(EA_AW_8(), COND_PL() ? 0xff : 0); +} + + +void m68k_op_spl_8_al(void) +{ + m68ki_write_8(EA_AL_8(), COND_PL() ? 0xff : 0); +} + + +void m68k_op_smi_8_ai(void) +{ + m68ki_write_8(EA_AY_AI_8(), COND_MI() ? 0xff : 0); +} + + +void m68k_op_smi_8_pi(void) +{ + m68ki_write_8(EA_AY_PI_8(), COND_MI() ? 0xff : 0); +} + + +void m68k_op_smi_8_pi7(void) +{ + m68ki_write_8(EA_A7_PI_8(), COND_MI() ? 0xff : 0); +} + + +void m68k_op_smi_8_pd(void) +{ + m68ki_write_8(EA_AY_PD_8(), COND_MI() ? 0xff : 0); +} + + +void m68k_op_smi_8_pd7(void) +{ + m68ki_write_8(EA_A7_PD_8(), COND_MI() ? 0xff : 0); +} + + +void m68k_op_smi_8_di(void) +{ + m68ki_write_8(EA_AY_DI_8(), COND_MI() ? 0xff : 0); +} + + +void m68k_op_smi_8_ix(void) +{ + m68ki_write_8(EA_AY_IX_8(), COND_MI() ? 0xff : 0); +} + + +void m68k_op_smi_8_aw(void) +{ + m68ki_write_8(EA_AW_8(), COND_MI() ? 0xff : 0); +} + + +void m68k_op_smi_8_al(void) +{ + m68ki_write_8(EA_AL_8(), COND_MI() ? 0xff : 0); +} + + +void m68k_op_sge_8_ai(void) +{ + m68ki_write_8(EA_AY_AI_8(), COND_GE() ? 0xff : 0); +} + + +void m68k_op_sge_8_pi(void) +{ + m68ki_write_8(EA_AY_PI_8(), COND_GE() ? 0xff : 0); +} + + +void m68k_op_sge_8_pi7(void) +{ + m68ki_write_8(EA_A7_PI_8(), COND_GE() ? 0xff : 0); +} + + +void m68k_op_sge_8_pd(void) +{ + m68ki_write_8(EA_AY_PD_8(), COND_GE() ? 0xff : 0); +} + + +void m68k_op_sge_8_pd7(void) +{ + m68ki_write_8(EA_A7_PD_8(), COND_GE() ? 0xff : 0); +} + + +void m68k_op_sge_8_di(void) +{ + m68ki_write_8(EA_AY_DI_8(), COND_GE() ? 0xff : 0); +} + + +void m68k_op_sge_8_ix(void) +{ + m68ki_write_8(EA_AY_IX_8(), COND_GE() ? 0xff : 0); +} + + +void m68k_op_sge_8_aw(void) +{ + m68ki_write_8(EA_AW_8(), COND_GE() ? 0xff : 0); +} + + +void m68k_op_sge_8_al(void) +{ + m68ki_write_8(EA_AL_8(), COND_GE() ? 0xff : 0); +} + + +void m68k_op_slt_8_ai(void) +{ + m68ki_write_8(EA_AY_AI_8(), COND_LT() ? 0xff : 0); +} + + +void m68k_op_slt_8_pi(void) +{ + m68ki_write_8(EA_AY_PI_8(), COND_LT() ? 0xff : 0); +} + + +void m68k_op_slt_8_pi7(void) +{ + m68ki_write_8(EA_A7_PI_8(), COND_LT() ? 0xff : 0); +} + + +void m68k_op_slt_8_pd(void) +{ + m68ki_write_8(EA_AY_PD_8(), COND_LT() ? 0xff : 0); +} + + +void m68k_op_slt_8_pd7(void) +{ + m68ki_write_8(EA_A7_PD_8(), COND_LT() ? 0xff : 0); +} + + +void m68k_op_slt_8_di(void) +{ + m68ki_write_8(EA_AY_DI_8(), COND_LT() ? 0xff : 0); +} + + +void m68k_op_slt_8_ix(void) +{ + m68ki_write_8(EA_AY_IX_8(), COND_LT() ? 0xff : 0); +} + + +void m68k_op_slt_8_aw(void) +{ + m68ki_write_8(EA_AW_8(), COND_LT() ? 0xff : 0); +} + + +void m68k_op_slt_8_al(void) +{ + m68ki_write_8(EA_AL_8(), COND_LT() ? 0xff : 0); +} + + +void m68k_op_sgt_8_ai(void) +{ + m68ki_write_8(EA_AY_AI_8(), COND_GT() ? 0xff : 0); +} + + +void m68k_op_sgt_8_pi(void) +{ + m68ki_write_8(EA_AY_PI_8(), COND_GT() ? 0xff : 0); +} + + +void m68k_op_sgt_8_pi7(void) +{ + m68ki_write_8(EA_A7_PI_8(), COND_GT() ? 0xff : 0); +} + + +void m68k_op_sgt_8_pd(void) +{ + m68ki_write_8(EA_AY_PD_8(), COND_GT() ? 0xff : 0); +} + + +void m68k_op_sgt_8_pd7(void) +{ + m68ki_write_8(EA_A7_PD_8(), COND_GT() ? 0xff : 0); +} + + +void m68k_op_sgt_8_di(void) +{ + m68ki_write_8(EA_AY_DI_8(), COND_GT() ? 0xff : 0); +} + + +void m68k_op_sgt_8_ix(void) +{ + m68ki_write_8(EA_AY_IX_8(), COND_GT() ? 0xff : 0); +} + + +void m68k_op_sgt_8_aw(void) +{ + m68ki_write_8(EA_AW_8(), COND_GT() ? 0xff : 0); +} + + +void m68k_op_sgt_8_al(void) +{ + m68ki_write_8(EA_AL_8(), COND_GT() ? 0xff : 0); +} + + +void m68k_op_sle_8_ai(void) +{ + m68ki_write_8(EA_AY_AI_8(), COND_LE() ? 0xff : 0); +} + + +void m68k_op_sle_8_pi(void) +{ + m68ki_write_8(EA_AY_PI_8(), COND_LE() ? 0xff : 0); +} + + +void m68k_op_sle_8_pi7(void) +{ + m68ki_write_8(EA_A7_PI_8(), COND_LE() ? 0xff : 0); +} + + +void m68k_op_sle_8_pd(void) +{ + m68ki_write_8(EA_AY_PD_8(), COND_LE() ? 0xff : 0); +} + + +void m68k_op_sle_8_pd7(void) +{ + m68ki_write_8(EA_A7_PD_8(), COND_LE() ? 0xff : 0); +} + + +void m68k_op_sle_8_di(void) +{ + m68ki_write_8(EA_AY_DI_8(), COND_LE() ? 0xff : 0); +} + + +void m68k_op_sle_8_ix(void) +{ + m68ki_write_8(EA_AY_IX_8(), COND_LE() ? 0xff : 0); +} + + +void m68k_op_sle_8_aw(void) +{ + m68ki_write_8(EA_AW_8(), COND_LE() ? 0xff : 0); +} + + +void m68k_op_sle_8_al(void) +{ + m68ki_write_8(EA_AL_8(), COND_LE() ? 0xff : 0); +} + + +void m68k_op_stop(void) +{ + if(FLAG_S) + { + uint new_sr = OPER_I_16(); + m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ + CPU_STOPPED |= STOP_LEVEL_STOP; + m68ki_set_sr(new_sr); + m68ki_remaining_cycles = 0; + return; + } + m68ki_exception_privilege_violation(); +} + + +void m68k_op_sub_8_er_d(void) +{ + uint* r_dst = &DX; + uint src = MASK_OUT_ABOVE_8(DY); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_8_er_ai(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_AI_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_8_er_pi(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_PI_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_8_er_pi7(void) +{ + uint* r_dst = &DX; + uint src = OPER_A7_PI_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_8_er_pd(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_PD_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_8_er_pd7(void) +{ + uint* r_dst = &DX; + uint src = OPER_A7_PD_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_8_er_di(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_DI_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_8_er_ix(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_IX_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_8_er_aw(void) +{ + uint* r_dst = &DX; + uint src = OPER_AW_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_8_er_al(void) +{ + uint* r_dst = &DX; + uint src = OPER_AL_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_8_er_pcdi(void) +{ + uint* r_dst = &DX; + uint src = OPER_PCDI_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_8_er_pcix(void) +{ + uint* r_dst = &DX; + uint src = OPER_PCIX_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_8_er_i(void) +{ + uint* r_dst = &DX; + uint src = OPER_I_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_16_er_d(void) +{ + uint* r_dst = &DX; + uint src = MASK_OUT_ABOVE_16(DY); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_16_er_a(void) +{ + uint* r_dst = &DX; + uint src = MASK_OUT_ABOVE_16(AY); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_16_er_ai(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_AI_16(); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_16_er_pi(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_PI_16(); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_16_er_pd(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_PD_16(); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_16_er_di(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_DI_16(); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_16_er_ix(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_IX_16(); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_16_er_aw(void) +{ + uint* r_dst = &DX; + uint src = OPER_AW_16(); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_16_er_al(void) +{ + uint* r_dst = &DX; + uint src = OPER_AL_16(); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_16_er_pcdi(void) +{ + uint* r_dst = &DX; + uint src = OPER_PCDI_16(); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_16_er_pcix(void) +{ + uint* r_dst = &DX; + uint src = OPER_PCIX_16(); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_16_er_i(void) +{ + uint* r_dst = &DX; + uint src = OPER_I_16(); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_sub_32_er_d(void) +{ + uint* r_dst = &DX; + uint src = DY; + uint dst = *r_dst; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_sub_32_er_a(void) +{ + uint* r_dst = &DX; + uint src = AY; + uint dst = *r_dst; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_sub_32_er_ai(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_AI_32(); + uint dst = *r_dst; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_sub_32_er_pi(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_PI_32(); + uint dst = *r_dst; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_sub_32_er_pd(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_PD_32(); + uint dst = *r_dst; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_sub_32_er_di(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_DI_32(); + uint dst = *r_dst; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_sub_32_er_ix(void) +{ + uint* r_dst = &DX; + uint src = OPER_AY_IX_32(); + uint dst = *r_dst; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_sub_32_er_aw(void) +{ + uint* r_dst = &DX; + uint src = OPER_AW_32(); + uint dst = *r_dst; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_sub_32_er_al(void) +{ + uint* r_dst = &DX; + uint src = OPER_AL_32(); + uint dst = *r_dst; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_sub_32_er_pcdi(void) +{ + uint* r_dst = &DX; + uint src = OPER_PCDI_32(); + uint dst = *r_dst; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_sub_32_er_pcix(void) +{ + uint* r_dst = &DX; + uint src = OPER_PCIX_32(); + uint dst = *r_dst; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_sub_32_er_i(void) +{ + uint* r_dst = &DX; + uint src = OPER_I_32(); + uint dst = *r_dst; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_sub_8_re_ai(void) +{ + uint ea = EA_AY_AI_8(); + uint src = MASK_OUT_ABOVE_8(DX); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_sub_8_re_pi(void) +{ + uint ea = EA_AY_PI_8(); + uint src = MASK_OUT_ABOVE_8(DX); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_sub_8_re_pi7(void) +{ + uint ea = EA_A7_PI_8(); + uint src = MASK_OUT_ABOVE_8(DX); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_sub_8_re_pd(void) +{ + uint ea = EA_AY_PD_8(); + uint src = MASK_OUT_ABOVE_8(DX); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_sub_8_re_pd7(void) +{ + uint ea = EA_A7_PD_8(); + uint src = MASK_OUT_ABOVE_8(DX); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_sub_8_re_di(void) +{ + uint ea = EA_AY_DI_8(); + uint src = MASK_OUT_ABOVE_8(DX); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_sub_8_re_ix(void) +{ + uint ea = EA_AY_IX_8(); + uint src = MASK_OUT_ABOVE_8(DX); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_sub_8_re_aw(void) +{ + uint ea = EA_AW_8(); + uint src = MASK_OUT_ABOVE_8(DX); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_sub_8_re_al(void) +{ + uint ea = EA_AL_8(); + uint src = MASK_OUT_ABOVE_8(DX); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_sub_16_re_ai(void) +{ + uint ea = EA_AY_AI_16(); + uint src = MASK_OUT_ABOVE_16(DX); + uint dst = m68ki_read_16(ea); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_sub_16_re_pi(void) +{ + uint ea = EA_AY_PI_16(); + uint src = MASK_OUT_ABOVE_16(DX); + uint dst = m68ki_read_16(ea); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_sub_16_re_pd(void) +{ + uint ea = EA_AY_PD_16(); + uint src = MASK_OUT_ABOVE_16(DX); + uint dst = m68ki_read_16(ea); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_sub_16_re_di(void) +{ + uint ea = EA_AY_DI_16(); + uint src = MASK_OUT_ABOVE_16(DX); + uint dst = m68ki_read_16(ea); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_sub_16_re_ix(void) +{ + uint ea = EA_AY_IX_16(); + uint src = MASK_OUT_ABOVE_16(DX); + uint dst = m68ki_read_16(ea); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_sub_16_re_aw(void) +{ + uint ea = EA_AW_16(); + uint src = MASK_OUT_ABOVE_16(DX); + uint dst = m68ki_read_16(ea); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_sub_16_re_al(void) +{ + uint ea = EA_AL_16(); + uint src = MASK_OUT_ABOVE_16(DX); + uint dst = m68ki_read_16(ea); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_sub_32_re_ai(void) +{ + uint ea = EA_AY_AI_32(); + uint src = DX; + uint dst = m68ki_read_32(ea); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_sub_32_re_pi(void) +{ + uint ea = EA_AY_PI_32(); + uint src = DX; + uint dst = m68ki_read_32(ea); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_sub_32_re_pd(void) +{ + uint ea = EA_AY_PD_32(); + uint src = DX; + uint dst = m68ki_read_32(ea); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_sub_32_re_di(void) +{ + uint ea = EA_AY_DI_32(); + uint src = DX; + uint dst = m68ki_read_32(ea); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_sub_32_re_ix(void) +{ + uint ea = EA_AY_IX_32(); + uint src = DX; + uint dst = m68ki_read_32(ea); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_sub_32_re_aw(void) +{ + uint ea = EA_AW_32(); + uint src = DX; + uint dst = m68ki_read_32(ea); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_sub_32_re_al(void) +{ + uint ea = EA_AL_32(); + uint src = DX; + uint dst = m68ki_read_32(ea); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_suba_16_d(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - MAKE_INT_16(DY)); +} + + +void m68k_op_suba_16_a(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - MAKE_INT_16(AY)); +} + + +void m68k_op_suba_16_ai(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - MAKE_INT_16(OPER_AY_AI_16())); +} + + +void m68k_op_suba_16_pi(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - MAKE_INT_16(OPER_AY_PI_16())); +} + + +void m68k_op_suba_16_pd(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - MAKE_INT_16(OPER_AY_PD_16())); +} + + +void m68k_op_suba_16_di(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - MAKE_INT_16(OPER_AY_DI_16())); +} + + +void m68k_op_suba_16_ix(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - MAKE_INT_16(OPER_AY_IX_16())); +} + + +void m68k_op_suba_16_aw(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - MAKE_INT_16(OPER_AW_16())); +} + + +void m68k_op_suba_16_al(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - MAKE_INT_16(OPER_AL_16())); +} + + +void m68k_op_suba_16_pcdi(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - MAKE_INT_16(OPER_PCDI_16())); +} + + +void m68k_op_suba_16_pcix(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - MAKE_INT_16(OPER_PCIX_16())); +} + + +void m68k_op_suba_16_i(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - MAKE_INT_16(OPER_I_16())); +} + + +void m68k_op_suba_32_d(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - DY); +} + + +void m68k_op_suba_32_a(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - AY); +} + + +void m68k_op_suba_32_ai(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - OPER_AY_AI_32()); +} + + +void m68k_op_suba_32_pi(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - OPER_AY_PI_32()); +} + + +void m68k_op_suba_32_pd(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - OPER_AY_PD_32()); +} + + +void m68k_op_suba_32_di(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - OPER_AY_DI_32()); +} + + +void m68k_op_suba_32_ix(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - OPER_AY_IX_32()); +} + + +void m68k_op_suba_32_aw(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - OPER_AW_32()); +} + + +void m68k_op_suba_32_al(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - OPER_AL_32()); +} + + +void m68k_op_suba_32_pcdi(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - OPER_PCDI_32()); +} + + +void m68k_op_suba_32_pcix(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - OPER_PCIX_32()); +} + + +void m68k_op_suba_32_i(void) +{ + uint* r_dst = &AX; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - OPER_I_32()); +} + + +void m68k_op_subi_8_d(void) +{ + uint* r_dst = &DY; + uint src = OPER_I_8(); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_subi_8_ai(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_AI_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_subi_8_pi(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_PI_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_subi_8_pi7(void) +{ + uint src = OPER_I_8(); + uint ea = EA_A7_PI_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_subi_8_pd(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_subi_8_pd7(void) +{ + uint src = OPER_I_8(); + uint ea = EA_A7_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_subi_8_di(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_DI_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_subi_8_ix(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AY_IX_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_subi_8_aw(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AW_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_subi_8_al(void) +{ + uint src = OPER_I_8(); + uint ea = EA_AL_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_subi_16_d(void) +{ + uint* r_dst = &DY; + uint src = OPER_I_16(); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_subi_16_ai(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_AI_16(); + uint dst = m68ki_read_16(ea); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_subi_16_pi(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_PI_16(); + uint dst = m68ki_read_16(ea); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_subi_16_pd(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_PD_16(); + uint dst = m68ki_read_16(ea); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_subi_16_di(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_DI_16(); + uint dst = m68ki_read_16(ea); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_subi_16_ix(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AY_IX_16(); + uint dst = m68ki_read_16(ea); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_subi_16_aw(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AW_16(); + uint dst = m68ki_read_16(ea); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_subi_16_al(void) +{ + uint src = OPER_I_16(); + uint ea = EA_AL_16(); + uint dst = m68ki_read_16(ea); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_subi_32_d(void) +{ + uint* r_dst = &DY; + uint src = OPER_I_32(); + uint dst = *r_dst; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_subi_32_ai(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_AI_32(); + uint dst = m68ki_read_32(ea); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_subi_32_pi(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_PI_32(); + uint dst = m68ki_read_32(ea); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_subi_32_pd(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_PD_32(); + uint dst = m68ki_read_32(ea); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_subi_32_di(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_DI_32(); + uint dst = m68ki_read_32(ea); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_subi_32_ix(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AY_IX_32(); + uint dst = m68ki_read_32(ea); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_subi_32_aw(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AW_32(); + uint dst = m68ki_read_32(ea); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_subi_32_al(void) +{ + uint src = OPER_I_32(); + uint ea = EA_AL_32(); + uint dst = m68ki_read_32(ea); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_subq_8_d(void) +{ + uint* r_dst = &DY; + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; +} + + +void m68k_op_subq_8_ai(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_AI_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_subq_8_pi(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_PI_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_subq_8_pi7(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_A7_PI_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_subq_8_pd(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_subq_8_pd7(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_A7_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_subq_8_di(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_DI_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_subq_8_ix(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_IX_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_subq_8_aw(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AW_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_subq_8_al(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AL_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src; + + FLAG_N = NFLAG_8(res); + FLAG_Z = MASK_OUT_ABOVE_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8(ea, FLAG_Z); +} + + +void m68k_op_subq_16_d(void) +{ + uint* r_dst = &DY; + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; +} + + +void m68k_op_subq_16_a(void) +{ + uint* r_dst = &AY; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - ((((REG_IR >> 9) - 1) & 7) + 1)); +} + + +void m68k_op_subq_16_ai(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_AI_16(); + uint dst = m68ki_read_16(ea); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_subq_16_pi(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_PI_16(); + uint dst = m68ki_read_16(ea); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_subq_16_pd(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_PD_16(); + uint dst = m68ki_read_16(ea); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_subq_16_di(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_DI_16(); + uint dst = m68ki_read_16(ea); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_subq_16_ix(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_IX_16(); + uint dst = m68ki_read_16(ea); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_subq_16_aw(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AW_16(); + uint dst = m68ki_read_16(ea); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_subq_16_al(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AL_16(); + uint dst = m68ki_read_16(ea); + uint res = dst - src; + + FLAG_N = NFLAG_16(res); + FLAG_Z = MASK_OUT_ABOVE_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16(ea, FLAG_Z); +} + + +void m68k_op_subq_32_d(void) +{ + uint* r_dst = &DY; + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint dst = *r_dst; + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + *r_dst = FLAG_Z; +} + + +void m68k_op_subq_32_a(void) +{ + uint* r_dst = &AY; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - ((((REG_IR >> 9) - 1) & 7) + 1)); +} + + +void m68k_op_subq_32_ai(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_AI_32(); + uint dst = m68ki_read_32(ea); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_subq_32_pi(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_PI_32(); + uint dst = m68ki_read_32(ea); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_subq_32_pd(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_PD_32(); + uint dst = m68ki_read_32(ea); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_subq_32_di(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_DI_32(); + uint dst = m68ki_read_32(ea); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_subq_32_ix(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AY_IX_32(); + uint dst = m68ki_read_32(ea); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_subq_32_aw(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AW_32(); + uint dst = m68ki_read_32(ea); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_subq_32_al(void) +{ + uint src = (((REG_IR >> 9) - 1) & 7) + 1; + uint ea = EA_AL_32(); + uint dst = m68ki_read_32(ea); + uint res = dst - src; + + FLAG_N = NFLAG_32(res); + FLAG_Z = MASK_OUT_ABOVE_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32(ea, FLAG_Z); +} + + +void m68k_op_subx_8_rr(void) +{ + uint* r_dst = &DX; + uint src = MASK_OUT_ABOVE_8(DY); + uint dst = MASK_OUT_ABOVE_8(*r_dst); + uint res = dst - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; +} + + +void m68k_op_subx_16_rr(void) +{ + uint* r_dst = &DX; + uint src = MASK_OUT_ABOVE_16(DY); + uint dst = MASK_OUT_ABOVE_16(*r_dst); + uint res = dst - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + res = MASK_OUT_ABOVE_16(res); + FLAG_Z |= res; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; +} + + +void m68k_op_subx_32_rr(void) +{ + uint* r_dst = &DX; + uint src = DY; + uint dst = *r_dst; + uint res = dst - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + res = MASK_OUT_ABOVE_32(res); + FLAG_Z |= res; + + *r_dst = res; +} + + +void m68k_op_subx_8_mm_ax7(void) +{ + uint src = OPER_AY_PD_8(); + uint ea = EA_A7_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_subx_8_mm_ay7(void) +{ + uint src = OPER_A7_PD_8(); + uint ea = EA_AX_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_subx_8_mm_axy7(void) +{ + uint src = OPER_A7_PD_8(); + uint ea = EA_A7_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_subx_8_mm(void) +{ + uint src = OPER_AY_PD_8(); + uint ea = EA_AX_PD_8(); + uint dst = m68ki_read_8(ea); + uint res = dst - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_8(res); + FLAG_X = FLAG_C = CFLAG_8(res); + FLAG_V = VFLAG_SUB_8(src, dst, res); + + res = MASK_OUT_ABOVE_8(res); + FLAG_Z |= res; + + m68ki_write_8(ea, res); +} + + +void m68k_op_subx_16_mm(void) +{ + uint src = OPER_AY_PD_16(); + uint ea = EA_AX_PD_16(); + uint dst = m68ki_read_16(ea); + uint res = dst - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_16(res); + FLAG_X = FLAG_C = CFLAG_16(res); + FLAG_V = VFLAG_SUB_16(src, dst, res); + + res = MASK_OUT_ABOVE_16(res); + FLAG_Z |= res; + + m68ki_write_16(ea, res); +} + + +void m68k_op_subx_32_mm(void) +{ + uint src = OPER_AY_PD_32(); + uint ea = EA_AX_PD_32(); + uint dst = m68ki_read_32(ea); + uint res = dst - src - XFLAG_AS_1(); + + FLAG_N = NFLAG_32(res); + FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); + FLAG_V = VFLAG_SUB_32(src, dst, res); + + res = MASK_OUT_ABOVE_32(res); + FLAG_Z |= res; + + m68ki_write_32(ea, res); +} + + +void m68k_op_swap_32(void) +{ + uint* r_dst = &DY; + + FLAG_Z = MASK_OUT_ABOVE_32(*r_dst<<16); + *r_dst = (*r_dst>>16) | FLAG_Z; + + FLAG_Z = *r_dst; + FLAG_N = NFLAG_32(*r_dst); + FLAG_C = CFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; +} + + +void m68k_op_tas_8_d(void) +{ + uint* r_dst = &DY; + + FLAG_Z = MASK_OUT_ABOVE_8(*r_dst); + FLAG_N = NFLAG_8(*r_dst); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + *r_dst |= 0x80; +} + + +void m68k_op_tas_8_ai(void) +{ + uint ea = EA_AY_AI_8(); + uint dst = m68ki_read_8(ea); + + FLAG_Z = dst; + FLAG_N = NFLAG_8(dst); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +// m68ki_write_8(ea, dst | 0x80); // notaz: genesis, but only to mem +} + + +void m68k_op_tas_8_pi(void) +{ + uint ea = EA_AY_PI_8(); + uint dst = m68ki_read_8(ea); + + FLAG_Z = dst; + FLAG_N = NFLAG_8(dst); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +// m68ki_write_8(ea, dst | 0x80); // notaz: genesis, but only to mem +} + + +void m68k_op_tas_8_pi7(void) +{ + uint ea = EA_A7_PI_8(); + uint dst = m68ki_read_8(ea); + + FLAG_Z = dst; + FLAG_N = NFLAG_8(dst); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +// m68ki_write_8(ea, dst | 0x80); // notaz: genesis, but only to mem +} + + +void m68k_op_tas_8_pd(void) +{ + uint ea = EA_AY_PD_8(); + uint dst = m68ki_read_8(ea); + + FLAG_Z = dst; + FLAG_N = NFLAG_8(dst); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +// m68ki_write_8(ea, dst | 0x80); // notaz: genesis, but only to mem +} + + +void m68k_op_tas_8_pd7(void) +{ + uint ea = EA_A7_PD_8(); + uint dst = m68ki_read_8(ea); + + FLAG_Z = dst; + FLAG_N = NFLAG_8(dst); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +// m68ki_write_8(ea, dst | 0x80); // notaz: genesis, but only to mem +} + + +void m68k_op_tas_8_di(void) +{ + uint ea = EA_AY_DI_8(); + uint dst = m68ki_read_8(ea); + + FLAG_Z = dst; + FLAG_N = NFLAG_8(dst); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +// m68ki_write_8(ea, dst | 0x80); // notaz: genesis, but only to mem +} + + +void m68k_op_tas_8_ix(void) +{ + uint ea = EA_AY_IX_8(); + uint dst = m68ki_read_8(ea); + + FLAG_Z = dst; + FLAG_N = NFLAG_8(dst); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +// m68ki_write_8(ea, dst | 0x80); // notaz: genesis, but only to mem +} + + +void m68k_op_tas_8_aw(void) +{ + uint ea = EA_AW_8(); + uint dst = m68ki_read_8(ea); + + FLAG_Z = dst; + FLAG_N = NFLAG_8(dst); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +// m68ki_write_8(ea, dst | 0x80); // notaz: genesis, but only to mem +} + + +void m68k_op_tas_8_al(void) +{ + uint ea = EA_AL_8(); + uint dst = m68ki_read_8(ea); + + FLAG_Z = dst; + FLAG_N = NFLAG_8(dst); + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +// m68ki_write_8(ea, dst | 0x80); // notaz: genesis, but only to mem +} + + +void m68k_op_trap(void) +{ + /* Trap#n stacks exception frame type 0 */ + m68ki_exception_trapN(EXCEPTION_TRAP_BASE + (REG_IR & 0xf)); /* HJB 990403 */ +} + + +void m68k_op_trapt(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapt_16(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapt_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapf(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapf_16(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + REG_PC += 2; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapf_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + REG_PC += 4; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_traphi(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_HI()) + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapls(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_LS()) + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapcc(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_CC()) + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapcs(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_CS()) + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapne(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_NE()) + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapeq(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_EQ()) + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapvc(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_VC()) + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapvs(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_VS()) + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trappl(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_PL()) + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapmi(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_MI()) + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapge(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_GE()) + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_traplt(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_LT()) + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapgt(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_GT()) + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_traple(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_LE()) + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_traphi_16(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_HI()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 2; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapls_16(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_LS()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 2; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapcc_16(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_CC()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 2; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapcs_16(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_CS()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 2; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapne_16(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_NE()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 2; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapeq_16(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_EQ()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 2; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapvc_16(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_VC()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 2; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapvs_16(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_VS()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 2; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trappl_16(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_PL()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 2; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapmi_16(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_MI()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 2; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapge_16(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_GE()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 2; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_traplt_16(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_LT()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 2; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapgt_16(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_GT()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 2; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_traple_16(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_LE()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 2; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_traphi_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_HI()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 4; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapls_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_LS()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 4; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapcc_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_CC()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 4; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapcs_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_CS()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 4; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapne_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_NE()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 4; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapeq_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_EQ()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 4; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapvc_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_VC()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 4; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapvs_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_VS()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 4; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trappl_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_PL()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 4; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapmi_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_MI()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 4; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapge_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_GE()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 4; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_traplt_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_LT()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 4; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapgt_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_GT()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 4; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_traple_32(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + if(COND_LE()) + { + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC += 4; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_trapv(void) +{ + if(COND_VC()) + { + return; + } + m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ +} + + +void m68k_op_tst_8_d(void) +{ + uint res = MASK_OUT_ABOVE_8(DY); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_8_ai(void) +{ + uint res = OPER_AY_AI_8(); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_8_pi(void) +{ + uint res = OPER_AY_PI_8(); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_8_pi7(void) +{ + uint res = OPER_A7_PI_8(); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_8_pd(void) +{ + uint res = OPER_AY_PD_8(); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_8_pd7(void) +{ + uint res = OPER_A7_PD_8(); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_8_di(void) +{ + uint res = OPER_AY_DI_8(); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_8_ix(void) +{ + uint res = OPER_AY_IX_8(); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_8_aw(void) +{ + uint res = OPER_AW_8(); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_8_al(void) +{ + uint res = OPER_AL_8(); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_8_pcdi(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint res = OPER_PCDI_8(); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_tst_8_pcix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint res = OPER_PCIX_8(); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_tst_8_i(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint res = OPER_I_8(); + + FLAG_N = NFLAG_8(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_tst_16_d(void) +{ + uint res = MASK_OUT_ABOVE_16(DY); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_16_a(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint res = MAKE_INT_16(AY); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_tst_16_ai(void) +{ + uint res = OPER_AY_AI_16(); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_16_pi(void) +{ + uint res = OPER_AY_PI_16(); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_16_pd(void) +{ + uint res = OPER_AY_PD_16(); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_16_di(void) +{ + uint res = OPER_AY_DI_16(); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_16_ix(void) +{ + uint res = OPER_AY_IX_16(); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_16_aw(void) +{ + uint res = OPER_AW_16(); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_16_al(void) +{ + uint res = OPER_AL_16(); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_16_pcdi(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint res = OPER_PCDI_16(); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_tst_16_pcix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint res = OPER_PCIX_16(); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_tst_16_i(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint res = OPER_I_16(); + + FLAG_N = NFLAG_16(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_tst_32_d(void) +{ + uint res = DY; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_32_a(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint res = AY; + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_tst_32_ai(void) +{ + uint res = OPER_AY_AI_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_32_pi(void) +{ + uint res = OPER_AY_PI_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_32_pd(void) +{ + uint res = OPER_AY_PD_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_32_di(void) +{ + uint res = OPER_AY_DI_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_32_ix(void) +{ + uint res = OPER_AY_IX_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_32_aw(void) +{ + uint res = OPER_AW_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_32_al(void) +{ + uint res = OPER_AL_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; +} + + +void m68k_op_tst_32_pcdi(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint res = OPER_PCDI_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_tst_32_pcix(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint res = OPER_PCIX_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_tst_32_i(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint res = OPER_I_32(); + + FLAG_N = NFLAG_32(res); + FLAG_Z = res; + FLAG_V = VFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_unlk_32_a7(void) +{ + REG_A[7] = m68ki_read_32(REG_A[7]); +} + + +void m68k_op_unlk_32(void) +{ + uint* r_dst = &AY; + + REG_A[7] = *r_dst; + *r_dst = m68ki_pull_32(); +} + + +void m68k_op_unpk_16_rr(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + /* Note: DX and DY are reversed in Motorola's docs */ + uint src = DY; + uint* r_dst = &DX; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (((((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16()) & 0xffff); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_unpk_16_mm_ax7(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + /* Note: AX and AY are reversed in Motorola's docs */ + uint src = OPER_AY_PD_8(); + uint ea_dst; + + src = (((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16(); + ea_dst = EA_A7_PD_8(); + m68ki_write_8(ea_dst, (src >> 8) & 0xff); + ea_dst = EA_A7_PD_8(); + m68ki_write_8(ea_dst, src & 0xff); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_unpk_16_mm_ay7(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + /* Note: AX and AY are reversed in Motorola's docs */ + uint src = OPER_A7_PD_8(); + uint ea_dst; + + src = (((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16(); + ea_dst = EA_AX_PD_8(); + m68ki_write_8(ea_dst, (src >> 8) & 0xff); + ea_dst = EA_AX_PD_8(); + m68ki_write_8(ea_dst, src & 0xff); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_unpk_16_mm_axy7(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + uint src = OPER_A7_PD_8(); + uint ea_dst; + + src = (((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16(); + ea_dst = EA_A7_PD_8(); + m68ki_write_8(ea_dst, (src >> 8) & 0xff); + ea_dst = EA_A7_PD_8(); + m68ki_write_8(ea_dst, src & 0xff); + return; + } + m68ki_exception_illegal(); +} + + +void m68k_op_unpk_16_mm(void) +{ + if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) + { + /* Note: AX and AY are reversed in Motorola's docs */ + uint src = OPER_AY_PD_8(); + uint ea_dst; + + src = (((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16(); + ea_dst = EA_AX_PD_8(); + m68ki_write_8(ea_dst, (src >> 8) & 0xff); + ea_dst = EA_AX_PD_8(); + m68ki_write_8(ea_dst, src & 0xff); + return; + } + m68ki_exception_illegal(); +} + + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ + + diff --git a/cpu/musashi/m68kops.c b/cpu/musashi/m68kops.c new file mode 100644 index 00000000..9f469032 --- /dev/null +++ b/cpu/musashi/m68kops.c @@ -0,0 +1,2093 @@ +/* ======================================================================== */ +/* ========================= OPCODE TABLE BUILDER ========================= */ +/* ======================================================================== */ + +#include "m68kops.h" + +#define NUM_CPU_TYPES 4 + +void (*m68ki_instruction_jump_table[0x10000])(void); /* opcode handler jump table */ +unsigned char m68ki_cycles[NUM_CPU_TYPES][0x10000]; /* Cycles used by CPU type */ + +/* This is used to generate the opcode handler jump table */ +typedef struct +{ + void (*opcode_handler)(void); /* handler function */ + unsigned int mask; /* mask on opcode */ + unsigned int match; /* what to match after masking */ + unsigned char cycles[NUM_CPU_TYPES]; /* cycles each cpu type takes */ +} opcode_handler_struct; + + +/* Opcode handler table */ +static opcode_handler_struct m68k_opcode_handler_table[] = +{ +/* function mask match 000 010 020 040 */ + {m68k_op_1010 , 0xf000, 0xa000, { 4, 4, 4, 4}}, + {m68k_op_1111 , 0xf000, 0xf000, { 4, 4, 4, 4}}, + {m68k_op_moveq_32 , 0xf100, 0x7000, { 4, 4, 2, 2}}, + {m68k_op_cpbcc_32 , 0xf180, 0xf080, { 0, 0, 4, 0}}, + {m68k_op_cpgen_32 , 0xf1c0, 0xf000, { 0, 0, 4, 0}}, + {m68k_op_cpscc_32 , 0xf1c0, 0xf040, { 0, 0, 4, 0}}, + {m68k_op_bra_8 , 0xff00, 0x6000, { 10, 10, 10, 10}}, + {m68k_op_bsr_8 , 0xff00, 0x6100, { 18, 18, 7, 7}}, + {m68k_op_bhi_8 , 0xff00, 0x6200, { 10, 10, 6, 6}}, + {m68k_op_bls_8 , 0xff00, 0x6300, { 10, 10, 6, 6}}, + {m68k_op_bcc_8 , 0xff00, 0x6400, { 10, 10, 6, 6}}, + {m68k_op_bcs_8 , 0xff00, 0x6500, { 10, 10, 6, 6}}, + {m68k_op_bne_8 , 0xff00, 0x6600, { 10, 10, 6, 6}}, + {m68k_op_beq_8 , 0xff00, 0x6700, { 10, 10, 6, 6}}, + {m68k_op_bvc_8 , 0xff00, 0x6800, { 10, 10, 6, 6}}, + {m68k_op_bvs_8 , 0xff00, 0x6900, { 10, 10, 6, 6}}, + {m68k_op_bpl_8 , 0xff00, 0x6a00, { 10, 10, 6, 6}}, + {m68k_op_bmi_8 , 0xff00, 0x6b00, { 10, 10, 6, 6}}, + {m68k_op_bge_8 , 0xff00, 0x6c00, { 10, 10, 6, 6}}, + {m68k_op_blt_8 , 0xff00, 0x6d00, { 10, 10, 6, 6}}, + {m68k_op_bgt_8 , 0xff00, 0x6e00, { 10, 10, 6, 6}}, + {m68k_op_ble_8 , 0xff00, 0x6f00, { 10, 10, 6, 6}}, + {m68k_op_btst_32_r_d , 0xf1f8, 0x0100, { 6, 6, 4, 4}}, + {m68k_op_movep_16_er , 0xf1f8, 0x0108, { 16, 16, 12, 12}}, + {m68k_op_btst_8_r_ai , 0xf1f8, 0x0110, { 8, 8, 8, 8}}, + {m68k_op_btst_8_r_pi , 0xf1f8, 0x0118, { 8, 8, 8, 8}}, + {m68k_op_btst_8_r_pd , 0xf1f8, 0x0120, { 10, 10, 9, 9}}, + {m68k_op_btst_8_r_di , 0xf1f8, 0x0128, { 12, 12, 9, 9}}, + {m68k_op_btst_8_r_ix , 0xf1f8, 0x0130, { 14, 14, 11, 11}}, + {m68k_op_bchg_32_r_d , 0xf1f8, 0x0140, { 8, 8, 4, 4}}, + {m68k_op_movep_32_er , 0xf1f8, 0x0148, { 24, 24, 18, 18}}, + {m68k_op_bchg_8_r_ai , 0xf1f8, 0x0150, { 12, 12, 8, 8}}, + {m68k_op_bchg_8_r_pi , 0xf1f8, 0x0158, { 12, 12, 8, 8}}, + {m68k_op_bchg_8_r_pd , 0xf1f8, 0x0160, { 14, 14, 9, 9}}, + {m68k_op_bchg_8_r_di , 0xf1f8, 0x0168, { 16, 16, 9, 9}}, + {m68k_op_bchg_8_r_ix , 0xf1f8, 0x0170, { 18, 18, 11, 11}}, + {m68k_op_bclr_32_r_d , 0xf1f8, 0x0180, { 10, 10, 4, 4}}, + {m68k_op_movep_16_re , 0xf1f8, 0x0188, { 16, 16, 11, 11}}, + {m68k_op_bclr_8_r_ai , 0xf1f8, 0x0190, { 12, 14, 8, 8}}, + {m68k_op_bclr_8_r_pi , 0xf1f8, 0x0198, { 12, 14, 8, 8}}, + {m68k_op_bclr_8_r_pd , 0xf1f8, 0x01a0, { 14, 16, 9, 9}}, + {m68k_op_bclr_8_r_di , 0xf1f8, 0x01a8, { 16, 18, 9, 9}}, + {m68k_op_bclr_8_r_ix , 0xf1f8, 0x01b0, { 18, 20, 11, 11}}, + {m68k_op_bset_32_r_d , 0xf1f8, 0x01c0, { 8, 8, 4, 4}}, + {m68k_op_movep_32_re , 0xf1f8, 0x01c8, { 24, 24, 17, 17}}, + {m68k_op_bset_8_r_ai , 0xf1f8, 0x01d0, { 12, 12, 8, 8}}, + {m68k_op_bset_8_r_pi , 0xf1f8, 0x01d8, { 12, 12, 8, 8}}, + {m68k_op_bset_8_r_pd , 0xf1f8, 0x01e0, { 14, 14, 9, 9}}, + {m68k_op_bset_8_r_di , 0xf1f8, 0x01e8, { 16, 16, 9, 9}}, + {m68k_op_bset_8_r_ix , 0xf1f8, 0x01f0, { 18, 18, 11, 11}}, + {m68k_op_move_8_d_d , 0xf1f8, 0x1000, { 4, 4, 2, 2}}, + {m68k_op_move_8_d_ai , 0xf1f8, 0x1010, { 8, 8, 6, 6}}, + {m68k_op_move_8_d_pi , 0xf1f8, 0x1018, { 8, 8, 6, 6}}, + {m68k_op_move_8_d_pd , 0xf1f8, 0x1020, { 10, 10, 7, 7}}, + {m68k_op_move_8_d_di , 0xf1f8, 0x1028, { 12, 12, 7, 7}}, + {m68k_op_move_8_d_ix , 0xf1f8, 0x1030, { 14, 14, 9, 9}}, + {m68k_op_move_8_ai_d , 0xf1f8, 0x1080, { 8, 8, 4, 4}}, + {m68k_op_move_8_ai_ai , 0xf1f8, 0x1090, { 12, 12, 8, 8}}, + {m68k_op_move_8_ai_pi , 0xf1f8, 0x1098, { 12, 12, 8, 8}}, + {m68k_op_move_8_ai_pd , 0xf1f8, 0x10a0, { 14, 14, 9, 9}}, + {m68k_op_move_8_ai_di , 0xf1f8, 0x10a8, { 16, 16, 9, 9}}, + {m68k_op_move_8_ai_ix , 0xf1f8, 0x10b0, { 18, 18, 11, 11}}, + {m68k_op_move_8_pi_d , 0xf1f8, 0x10c0, { 8, 8, 4, 4}}, + {m68k_op_move_8_pi_ai , 0xf1f8, 0x10d0, { 12, 12, 8, 8}}, + {m68k_op_move_8_pi_pi , 0xf1f8, 0x10d8, { 12, 12, 8, 8}}, + {m68k_op_move_8_pi_pd , 0xf1f8, 0x10e0, { 14, 14, 9, 9}}, + {m68k_op_move_8_pi_di , 0xf1f8, 0x10e8, { 16, 16, 9, 9}}, + {m68k_op_move_8_pi_ix , 0xf1f8, 0x10f0, { 18, 18, 11, 11}}, + {m68k_op_move_8_pd_d , 0xf1f8, 0x1100, { 8, 8, 5, 5}}, + {m68k_op_move_8_pd_ai , 0xf1f8, 0x1110, { 12, 12, 9, 9}}, + {m68k_op_move_8_pd_pi , 0xf1f8, 0x1118, { 12, 12, 9, 9}}, + {m68k_op_move_8_pd_pd , 0xf1f8, 0x1120, { 14, 14, 10, 10}}, + {m68k_op_move_8_pd_di , 0xf1f8, 0x1128, { 16, 16, 10, 10}}, + {m68k_op_move_8_pd_ix , 0xf1f8, 0x1130, { 18, 18, 12, 12}}, + {m68k_op_move_8_di_d , 0xf1f8, 0x1140, { 12, 12, 5, 5}}, + {m68k_op_move_8_di_ai , 0xf1f8, 0x1150, { 16, 16, 9, 9}}, + {m68k_op_move_8_di_pi , 0xf1f8, 0x1158, { 16, 16, 9, 9}}, + {m68k_op_move_8_di_pd , 0xf1f8, 0x1160, { 18, 18, 10, 10}}, + {m68k_op_move_8_di_di , 0xf1f8, 0x1168, { 20, 20, 10, 10}}, + {m68k_op_move_8_di_ix , 0xf1f8, 0x1170, { 22, 22, 12, 12}}, + {m68k_op_move_8_ix_d , 0xf1f8, 0x1180, { 14, 14, 7, 7}}, + {m68k_op_move_8_ix_ai , 0xf1f8, 0x1190, { 18, 18, 11, 11}}, + {m68k_op_move_8_ix_pi , 0xf1f8, 0x1198, { 18, 18, 11, 11}}, + {m68k_op_move_8_ix_pd , 0xf1f8, 0x11a0, { 20, 20, 12, 12}}, + {m68k_op_move_8_ix_di , 0xf1f8, 0x11a8, { 22, 22, 12, 12}}, + {m68k_op_move_8_ix_ix , 0xf1f8, 0x11b0, { 24, 24, 14, 14}}, + {m68k_op_move_32_d_d , 0xf1f8, 0x2000, { 4, 4, 2, 2}}, + {m68k_op_move_32_d_a , 0xf1f8, 0x2008, { 4, 4, 2, 2}}, + {m68k_op_move_32_d_ai , 0xf1f8, 0x2010, { 12, 12, 6, 6}}, + {m68k_op_move_32_d_pi , 0xf1f8, 0x2018, { 12, 12, 6, 6}}, + {m68k_op_move_32_d_pd , 0xf1f8, 0x2020, { 14, 14, 7, 7}}, + {m68k_op_move_32_d_di , 0xf1f8, 0x2028, { 16, 16, 7, 7}}, + {m68k_op_move_32_d_ix , 0xf1f8, 0x2030, { 18, 18, 9, 9}}, + {m68k_op_movea_32_d , 0xf1f8, 0x2040, { 4, 4, 2, 2}}, + {m68k_op_movea_32_a , 0xf1f8, 0x2048, { 4, 4, 2, 2}}, + {m68k_op_movea_32_ai , 0xf1f8, 0x2050, { 12, 12, 6, 6}}, + {m68k_op_movea_32_pi , 0xf1f8, 0x2058, { 12, 12, 6, 6}}, + {m68k_op_movea_32_pd , 0xf1f8, 0x2060, { 14, 14, 7, 7}}, + {m68k_op_movea_32_di , 0xf1f8, 0x2068, { 16, 16, 7, 7}}, + {m68k_op_movea_32_ix , 0xf1f8, 0x2070, { 18, 18, 9, 9}}, + {m68k_op_move_32_ai_d , 0xf1f8, 0x2080, { 12, 12, 4, 4}}, + {m68k_op_move_32_ai_a , 0xf1f8, 0x2088, { 12, 12, 4, 4}}, + {m68k_op_move_32_ai_ai , 0xf1f8, 0x2090, { 20, 20, 8, 8}}, + {m68k_op_move_32_ai_pi , 0xf1f8, 0x2098, { 20, 20, 8, 8}}, + {m68k_op_move_32_ai_pd , 0xf1f8, 0x20a0, { 22, 22, 9, 9}}, + {m68k_op_move_32_ai_di , 0xf1f8, 0x20a8, { 24, 24, 9, 9}}, + {m68k_op_move_32_ai_ix , 0xf1f8, 0x20b0, { 26, 26, 11, 11}}, + {m68k_op_move_32_pi_d , 0xf1f8, 0x20c0, { 12, 12, 4, 4}}, + {m68k_op_move_32_pi_a , 0xf1f8, 0x20c8, { 12, 12, 4, 4}}, + {m68k_op_move_32_pi_ai , 0xf1f8, 0x20d0, { 20, 20, 8, 8}}, + {m68k_op_move_32_pi_pi , 0xf1f8, 0x20d8, { 20, 20, 8, 8}}, + {m68k_op_move_32_pi_pd , 0xf1f8, 0x20e0, { 22, 22, 9, 9}}, + {m68k_op_move_32_pi_di , 0xf1f8, 0x20e8, { 24, 24, 9, 9}}, + {m68k_op_move_32_pi_ix , 0xf1f8, 0x20f0, { 26, 26, 11, 11}}, + {m68k_op_move_32_pd_d , 0xf1f8, 0x2100, { 12, 14, 5, 5}}, + {m68k_op_move_32_pd_a , 0xf1f8, 0x2108, { 12, 14, 5, 5}}, + {m68k_op_move_32_pd_ai , 0xf1f8, 0x2110, { 20, 22, 9, 9}}, + {m68k_op_move_32_pd_pi , 0xf1f8, 0x2118, { 20, 22, 9, 9}}, + {m68k_op_move_32_pd_pd , 0xf1f8, 0x2120, { 22, 24, 10, 10}}, + {m68k_op_move_32_pd_di , 0xf1f8, 0x2128, { 24, 26, 10, 10}}, + {m68k_op_move_32_pd_ix , 0xf1f8, 0x2130, { 26, 28, 12, 12}}, + {m68k_op_move_32_di_d , 0xf1f8, 0x2140, { 16, 16, 5, 5}}, + {m68k_op_move_32_di_a , 0xf1f8, 0x2148, { 16, 16, 5, 5}}, + {m68k_op_move_32_di_ai , 0xf1f8, 0x2150, { 24, 24, 9, 9}}, + {m68k_op_move_32_di_pi , 0xf1f8, 0x2158, { 24, 24, 9, 9}}, + {m68k_op_move_32_di_pd , 0xf1f8, 0x2160, { 26, 26, 10, 10}}, + {m68k_op_move_32_di_di , 0xf1f8, 0x2168, { 28, 28, 10, 10}}, + {m68k_op_move_32_di_ix , 0xf1f8, 0x2170, { 30, 30, 12, 12}}, + {m68k_op_move_32_ix_d , 0xf1f8, 0x2180, { 18, 18, 7, 7}}, + {m68k_op_move_32_ix_a , 0xf1f8, 0x2188, { 18, 18, 7, 7}}, + {m68k_op_move_32_ix_ai , 0xf1f8, 0x2190, { 26, 26, 11, 11}}, + {m68k_op_move_32_ix_pi , 0xf1f8, 0x2198, { 26, 26, 11, 11}}, + {m68k_op_move_32_ix_pd , 0xf1f8, 0x21a0, { 28, 28, 12, 12}}, + {m68k_op_move_32_ix_di , 0xf1f8, 0x21a8, { 30, 30, 12, 12}}, + {m68k_op_move_32_ix_ix , 0xf1f8, 0x21b0, { 32, 32, 14, 14}}, + {m68k_op_move_16_d_d , 0xf1f8, 0x3000, { 4, 4, 2, 2}}, + {m68k_op_move_16_d_a , 0xf1f8, 0x3008, { 4, 4, 2, 2}}, + {m68k_op_move_16_d_ai , 0xf1f8, 0x3010, { 8, 8, 6, 6}}, + {m68k_op_move_16_d_pi , 0xf1f8, 0x3018, { 8, 8, 6, 6}}, + {m68k_op_move_16_d_pd , 0xf1f8, 0x3020, { 10, 10, 7, 7}}, + {m68k_op_move_16_d_di , 0xf1f8, 0x3028, { 12, 12, 7, 7}}, + {m68k_op_move_16_d_ix , 0xf1f8, 0x3030, { 14, 14, 9, 9}}, + {m68k_op_movea_16_d , 0xf1f8, 0x3040, { 4, 4, 2, 2}}, + {m68k_op_movea_16_a , 0xf1f8, 0x3048, { 4, 4, 2, 2}}, + {m68k_op_movea_16_ai , 0xf1f8, 0x3050, { 8, 8, 6, 6}}, + {m68k_op_movea_16_pi , 0xf1f8, 0x3058, { 8, 8, 6, 6}}, + {m68k_op_movea_16_pd , 0xf1f8, 0x3060, { 10, 10, 7, 7}}, + {m68k_op_movea_16_di , 0xf1f8, 0x3068, { 12, 12, 7, 7}}, + {m68k_op_movea_16_ix , 0xf1f8, 0x3070, { 14, 14, 9, 9}}, + {m68k_op_move_16_ai_d , 0xf1f8, 0x3080, { 8, 8, 4, 4}}, + {m68k_op_move_16_ai_a , 0xf1f8, 0x3088, { 8, 8, 4, 4}}, + {m68k_op_move_16_ai_ai , 0xf1f8, 0x3090, { 12, 12, 8, 8}}, + {m68k_op_move_16_ai_pi , 0xf1f8, 0x3098, { 12, 12, 8, 8}}, + {m68k_op_move_16_ai_pd , 0xf1f8, 0x30a0, { 14, 14, 9, 9}}, + {m68k_op_move_16_ai_di , 0xf1f8, 0x30a8, { 16, 16, 9, 9}}, + {m68k_op_move_16_ai_ix , 0xf1f8, 0x30b0, { 18, 18, 11, 11}}, + {m68k_op_move_16_pi_d , 0xf1f8, 0x30c0, { 8, 8, 4, 4}}, + {m68k_op_move_16_pi_a , 0xf1f8, 0x30c8, { 8, 8, 4, 4}}, + {m68k_op_move_16_pi_ai , 0xf1f8, 0x30d0, { 12, 12, 8, 8}}, + {m68k_op_move_16_pi_pi , 0xf1f8, 0x30d8, { 12, 12, 8, 8}}, + {m68k_op_move_16_pi_pd , 0xf1f8, 0x30e0, { 14, 14, 9, 9}}, + {m68k_op_move_16_pi_di , 0xf1f8, 0x30e8, { 16, 16, 9, 9}}, + {m68k_op_move_16_pi_ix , 0xf1f8, 0x30f0, { 18, 18, 11, 11}}, + {m68k_op_move_16_pd_d , 0xf1f8, 0x3100, { 8, 8, 5, 5}}, + {m68k_op_move_16_pd_a , 0xf1f8, 0x3108, { 8, 8, 5, 5}}, + {m68k_op_move_16_pd_ai , 0xf1f8, 0x3110, { 12, 12, 9, 9}}, + {m68k_op_move_16_pd_pi , 0xf1f8, 0x3118, { 12, 12, 9, 9}}, + {m68k_op_move_16_pd_pd , 0xf1f8, 0x3120, { 14, 14, 10, 10}}, + {m68k_op_move_16_pd_di , 0xf1f8, 0x3128, { 16, 16, 10, 10}}, + {m68k_op_move_16_pd_ix , 0xf1f8, 0x3130, { 18, 18, 12, 12}}, + {m68k_op_move_16_di_d , 0xf1f8, 0x3140, { 12, 12, 5, 5}}, + {m68k_op_move_16_di_a , 0xf1f8, 0x3148, { 12, 12, 5, 5}}, + {m68k_op_move_16_di_ai , 0xf1f8, 0x3150, { 16, 16, 9, 9}}, + {m68k_op_move_16_di_pi , 0xf1f8, 0x3158, { 16, 16, 9, 9}}, + {m68k_op_move_16_di_pd , 0xf1f8, 0x3160, { 18, 18, 10, 10}}, + {m68k_op_move_16_di_di , 0xf1f8, 0x3168, { 20, 20, 10, 10}}, + {m68k_op_move_16_di_ix , 0xf1f8, 0x3170, { 22, 22, 12, 12}}, + {m68k_op_move_16_ix_d , 0xf1f8, 0x3180, { 14, 14, 7, 7}}, + {m68k_op_move_16_ix_a , 0xf1f8, 0x3188, { 14, 14, 7, 7}}, + {m68k_op_move_16_ix_ai , 0xf1f8, 0x3190, { 18, 18, 11, 11}}, + {m68k_op_move_16_ix_pi , 0xf1f8, 0x3198, { 18, 18, 11, 11}}, + {m68k_op_move_16_ix_pd , 0xf1f8, 0x31a0, { 20, 20, 12, 12}}, + {m68k_op_move_16_ix_di , 0xf1f8, 0x31a8, { 22, 22, 12, 12}}, + {m68k_op_move_16_ix_ix , 0xf1f8, 0x31b0, { 24, 24, 14, 14}}, + {m68k_op_chk_32_d , 0xf1f8, 0x4100, { 0, 0, 8, 8}}, + {m68k_op_chk_32_ai , 0xf1f8, 0x4110, { 0, 0, 12, 12}}, + {m68k_op_chk_32_pi , 0xf1f8, 0x4118, { 0, 0, 12, 12}}, + {m68k_op_chk_32_pd , 0xf1f8, 0x4120, { 0, 0, 13, 13}}, + {m68k_op_chk_32_di , 0xf1f8, 0x4128, { 0, 0, 13, 13}}, + {m68k_op_chk_32_ix , 0xf1f8, 0x4130, { 0, 0, 15, 15}}, + {m68k_op_chk_16_d , 0xf1f8, 0x4180, { 10, 8, 8, 8}}, + {m68k_op_chk_16_ai , 0xf1f8, 0x4190, { 14, 12, 12, 12}}, + {m68k_op_chk_16_pi , 0xf1f8, 0x4198, { 14, 12, 12, 12}}, + {m68k_op_chk_16_pd , 0xf1f8, 0x41a0, { 16, 14, 13, 13}}, + {m68k_op_chk_16_di , 0xf1f8, 0x41a8, { 18, 16, 13, 13}}, + {m68k_op_chk_16_ix , 0xf1f8, 0x41b0, { 20, 18, 15, 15}}, + {m68k_op_lea_32_ai , 0xf1f8, 0x41d0, { 4, 4, 6, 6}}, + {m68k_op_lea_32_di , 0xf1f8, 0x41e8, { 8, 8, 7, 7}}, + {m68k_op_lea_32_ix , 0xf1f8, 0x41f0, { 12, 12, 9, 9}}, + {m68k_op_addq_8_d , 0xf1f8, 0x5000, { 4, 4, 2, 2}}, + {m68k_op_addq_8_ai , 0xf1f8, 0x5010, { 12, 12, 8, 8}}, + {m68k_op_addq_8_pi , 0xf1f8, 0x5018, { 12, 12, 8, 8}}, + {m68k_op_addq_8_pd , 0xf1f8, 0x5020, { 14, 14, 9, 9}}, + {m68k_op_addq_8_di , 0xf1f8, 0x5028, { 16, 16, 9, 9}}, + {m68k_op_addq_8_ix , 0xf1f8, 0x5030, { 18, 18, 11, 11}}, + {m68k_op_addq_16_d , 0xf1f8, 0x5040, { 4, 4, 2, 2}}, + {m68k_op_addq_16_a , 0xf1f8, 0x5048, { 4, 4, 2, 2}}, + {m68k_op_addq_16_ai , 0xf1f8, 0x5050, { 12, 12, 8, 8}}, + {m68k_op_addq_16_pi , 0xf1f8, 0x5058, { 12, 12, 8, 8}}, + {m68k_op_addq_16_pd , 0xf1f8, 0x5060, { 14, 14, 9, 9}}, + {m68k_op_addq_16_di , 0xf1f8, 0x5068, { 16, 16, 9, 9}}, + {m68k_op_addq_16_ix , 0xf1f8, 0x5070, { 18, 18, 11, 11}}, + {m68k_op_addq_32_d , 0xf1f8, 0x5080, { 8, 8, 2, 2}}, + {m68k_op_addq_32_a , 0xf1f8, 0x5088, { 8, 8, 2, 2}}, + {m68k_op_addq_32_ai , 0xf1f8, 0x5090, { 20, 20, 8, 8}}, + {m68k_op_addq_32_pi , 0xf1f8, 0x5098, { 20, 20, 8, 8}}, + {m68k_op_addq_32_pd , 0xf1f8, 0x50a0, { 22, 22, 9, 9}}, + {m68k_op_addq_32_di , 0xf1f8, 0x50a8, { 24, 24, 9, 9}}, + {m68k_op_addq_32_ix , 0xf1f8, 0x50b0, { 26, 26, 11, 11}}, + {m68k_op_subq_8_d , 0xf1f8, 0x5100, { 4, 4, 2, 2}}, + {m68k_op_subq_8_ai , 0xf1f8, 0x5110, { 12, 12, 8, 8}}, + {m68k_op_subq_8_pi , 0xf1f8, 0x5118, { 12, 12, 8, 8}}, + {m68k_op_subq_8_pd , 0xf1f8, 0x5120, { 14, 14, 9, 9}}, + {m68k_op_subq_8_di , 0xf1f8, 0x5128, { 16, 16, 9, 9}}, + {m68k_op_subq_8_ix , 0xf1f8, 0x5130, { 18, 18, 11, 11}}, + {m68k_op_subq_16_d , 0xf1f8, 0x5140, { 4, 4, 2, 2}}, + {m68k_op_subq_16_a , 0xf1f8, 0x5148, { 8, 4, 2, 2}}, + {m68k_op_subq_16_ai , 0xf1f8, 0x5150, { 12, 12, 8, 8}}, + {m68k_op_subq_16_pi , 0xf1f8, 0x5158, { 12, 12, 8, 8}}, + {m68k_op_subq_16_pd , 0xf1f8, 0x5160, { 14, 14, 9, 9}}, + {m68k_op_subq_16_di , 0xf1f8, 0x5168, { 16, 16, 9, 9}}, + {m68k_op_subq_16_ix , 0xf1f8, 0x5170, { 18, 18, 11, 11}}, + {m68k_op_subq_32_d , 0xf1f8, 0x5180, { 8, 8, 2, 2}}, + {m68k_op_subq_32_a , 0xf1f8, 0x5188, { 8, 8, 2, 2}}, + {m68k_op_subq_32_ai , 0xf1f8, 0x5190, { 20, 20, 8, 8}}, + {m68k_op_subq_32_pi , 0xf1f8, 0x5198, { 20, 20, 8, 8}}, + {m68k_op_subq_32_pd , 0xf1f8, 0x51a0, { 22, 22, 9, 9}}, + {m68k_op_subq_32_di , 0xf1f8, 0x51a8, { 24, 24, 9, 9}}, + {m68k_op_subq_32_ix , 0xf1f8, 0x51b0, { 26, 26, 11, 11}}, + {m68k_op_or_8_er_d , 0xf1f8, 0x8000, { 4, 4, 2, 2}}, + {m68k_op_or_8_er_ai , 0xf1f8, 0x8010, { 8, 8, 6, 6}}, + {m68k_op_or_8_er_pi , 0xf1f8, 0x8018, { 8, 8, 6, 6}}, + {m68k_op_or_8_er_pd , 0xf1f8, 0x8020, { 10, 10, 7, 7}}, + {m68k_op_or_8_er_di , 0xf1f8, 0x8028, { 12, 12, 7, 7}}, + {m68k_op_or_8_er_ix , 0xf1f8, 0x8030, { 14, 14, 9, 9}}, + {m68k_op_or_16_er_d , 0xf1f8, 0x8040, { 4, 4, 2, 2}}, + {m68k_op_or_16_er_ai , 0xf1f8, 0x8050, { 8, 8, 6, 6}}, + {m68k_op_or_16_er_pi , 0xf1f8, 0x8058, { 8, 8, 6, 6}}, + {m68k_op_or_16_er_pd , 0xf1f8, 0x8060, { 10, 10, 7, 7}}, + {m68k_op_or_16_er_di , 0xf1f8, 0x8068, { 12, 12, 7, 7}}, + {m68k_op_or_16_er_ix , 0xf1f8, 0x8070, { 14, 14, 9, 9}}, + {m68k_op_or_32_er_d , 0xf1f8, 0x8080, { 8, 6, 2, 2}}, + {m68k_op_or_32_er_ai , 0xf1f8, 0x8090, { 14, 14, 6, 6}}, + {m68k_op_or_32_er_pi , 0xf1f8, 0x8098, { 14, 14, 6, 6}}, + {m68k_op_or_32_er_pd , 0xf1f8, 0x80a0, { 16, 16, 7, 7}}, + {m68k_op_or_32_er_di , 0xf1f8, 0x80a8, { 18, 18, 7, 7}}, + {m68k_op_or_32_er_ix , 0xf1f8, 0x80b0, { 20, 20, 9, 9}}, + {m68k_op_divu_16_d , 0xf1f8, 0x80c0, {140, 108, 44, 44}}, + {m68k_op_divu_16_ai , 0xf1f8, 0x80d0, {144, 112, 48, 48}}, + {m68k_op_divu_16_pi , 0xf1f8, 0x80d8, {144, 112, 48, 48}}, + {m68k_op_divu_16_pd , 0xf1f8, 0x80e0, {146, 114, 49, 49}}, + {m68k_op_divu_16_di , 0xf1f8, 0x80e8, {148, 116, 49, 49}}, + {m68k_op_divu_16_ix , 0xf1f8, 0x80f0, {150, 118, 51, 51}}, + {m68k_op_sbcd_8_rr , 0xf1f8, 0x8100, { 6, 6, 4, 4}}, + {m68k_op_sbcd_8_mm , 0xf1f8, 0x8108, { 18, 18, 16, 16}}, + {m68k_op_or_8_re_ai , 0xf1f8, 0x8110, { 12, 12, 8, 8}}, + {m68k_op_or_8_re_pi , 0xf1f8, 0x8118, { 12, 12, 8, 8}}, + {m68k_op_or_8_re_pd , 0xf1f8, 0x8120, { 14, 14, 9, 9}}, + {m68k_op_or_8_re_di , 0xf1f8, 0x8128, { 16, 16, 9, 9}}, + {m68k_op_or_8_re_ix , 0xf1f8, 0x8130, { 18, 18, 11, 11}}, + {m68k_op_pack_16_rr , 0xf1f8, 0x8140, { 0, 0, 6, 6}}, + {m68k_op_pack_16_mm , 0xf1f8, 0x8148, { 0, 0, 13, 13}}, + {m68k_op_or_16_re_ai , 0xf1f8, 0x8150, { 12, 12, 8, 8}}, + {m68k_op_or_16_re_pi , 0xf1f8, 0x8158, { 12, 12, 8, 8}}, + {m68k_op_or_16_re_pd , 0xf1f8, 0x8160, { 14, 14, 9, 9}}, + {m68k_op_or_16_re_di , 0xf1f8, 0x8168, { 16, 16, 9, 9}}, + {m68k_op_or_16_re_ix , 0xf1f8, 0x8170, { 18, 18, 11, 11}}, + {m68k_op_unpk_16_rr , 0xf1f8, 0x8180, { 0, 0, 8, 8}}, + {m68k_op_unpk_16_mm , 0xf1f8, 0x8188, { 0, 0, 13, 13}}, + {m68k_op_or_32_re_ai , 0xf1f8, 0x8190, { 20, 20, 8, 8}}, + {m68k_op_or_32_re_pi , 0xf1f8, 0x8198, { 20, 20, 8, 8}}, + {m68k_op_or_32_re_pd , 0xf1f8, 0x81a0, { 22, 22, 9, 9}}, + {m68k_op_or_32_re_di , 0xf1f8, 0x81a8, { 24, 24, 9, 9}}, + {m68k_op_or_32_re_ix , 0xf1f8, 0x81b0, { 26, 26, 11, 11}}, + {m68k_op_divs_16_d , 0xf1f8, 0x81c0, {158, 122, 56, 56}}, + {m68k_op_divs_16_ai , 0xf1f8, 0x81d0, {162, 126, 60, 60}}, + {m68k_op_divs_16_pi , 0xf1f8, 0x81d8, {162, 126, 60, 60}}, + {m68k_op_divs_16_pd , 0xf1f8, 0x81e0, {164, 128, 61, 61}}, + {m68k_op_divs_16_di , 0xf1f8, 0x81e8, {166, 130, 61, 61}}, + {m68k_op_divs_16_ix , 0xf1f8, 0x81f0, {168, 132, 63, 63}}, + {m68k_op_sub_8_er_d , 0xf1f8, 0x9000, { 4, 4, 2, 2}}, + {m68k_op_sub_8_er_ai , 0xf1f8, 0x9010, { 8, 8, 6, 6}}, + {m68k_op_sub_8_er_pi , 0xf1f8, 0x9018, { 8, 8, 6, 6}}, + {m68k_op_sub_8_er_pd , 0xf1f8, 0x9020, { 10, 10, 7, 7}}, + {m68k_op_sub_8_er_di , 0xf1f8, 0x9028, { 12, 12, 7, 7}}, + {m68k_op_sub_8_er_ix , 0xf1f8, 0x9030, { 14, 14, 9, 9}}, + {m68k_op_sub_16_er_d , 0xf1f8, 0x9040, { 4, 4, 2, 2}}, + {m68k_op_sub_16_er_a , 0xf1f8, 0x9048, { 4, 4, 2, 2}}, + {m68k_op_sub_16_er_ai , 0xf1f8, 0x9050, { 8, 8, 6, 6}}, + {m68k_op_sub_16_er_pi , 0xf1f8, 0x9058, { 8, 8, 6, 6}}, + {m68k_op_sub_16_er_pd , 0xf1f8, 0x9060, { 10, 10, 7, 7}}, + {m68k_op_sub_16_er_di , 0xf1f8, 0x9068, { 12, 12, 7, 7}}, + {m68k_op_sub_16_er_ix , 0xf1f8, 0x9070, { 14, 14, 9, 9}}, + {m68k_op_sub_32_er_d , 0xf1f8, 0x9080, { 8, 6, 2, 2}}, + {m68k_op_sub_32_er_a , 0xf1f8, 0x9088, { 8, 6, 2, 2}}, + {m68k_op_sub_32_er_ai , 0xf1f8, 0x9090, { 14, 14, 6, 6}}, + {m68k_op_sub_32_er_pi , 0xf1f8, 0x9098, { 14, 14, 6, 6}}, + {m68k_op_sub_32_er_pd , 0xf1f8, 0x90a0, { 16, 16, 7, 7}}, + {m68k_op_sub_32_er_di , 0xf1f8, 0x90a8, { 18, 18, 7, 7}}, + {m68k_op_sub_32_er_ix , 0xf1f8, 0x90b0, { 20, 20, 9, 9}}, + {m68k_op_suba_16_d , 0xf1f8, 0x90c0, { 8, 8, 2, 2}}, + {m68k_op_suba_16_a , 0xf1f8, 0x90c8, { 8, 8, 2, 2}}, + {m68k_op_suba_16_ai , 0xf1f8, 0x90d0, { 12, 12, 6, 6}}, + {m68k_op_suba_16_pi , 0xf1f8, 0x90d8, { 12, 12, 6, 6}}, + {m68k_op_suba_16_pd , 0xf1f8, 0x90e0, { 14, 14, 7, 7}}, + {m68k_op_suba_16_di , 0xf1f8, 0x90e8, { 16, 16, 7, 7}}, + {m68k_op_suba_16_ix , 0xf1f8, 0x90f0, { 18, 18, 9, 9}}, + {m68k_op_subx_8_rr , 0xf1f8, 0x9100, { 4, 4, 2, 2}}, + {m68k_op_subx_8_mm , 0xf1f8, 0x9108, { 18, 18, 12, 12}}, + {m68k_op_sub_8_re_ai , 0xf1f8, 0x9110, { 12, 12, 8, 8}}, + {m68k_op_sub_8_re_pi , 0xf1f8, 0x9118, { 12, 12, 8, 8}}, + {m68k_op_sub_8_re_pd , 0xf1f8, 0x9120, { 14, 14, 9, 9}}, + {m68k_op_sub_8_re_di , 0xf1f8, 0x9128, { 16, 16, 9, 9}}, + {m68k_op_sub_8_re_ix , 0xf1f8, 0x9130, { 18, 18, 11, 11}}, + {m68k_op_subx_16_rr , 0xf1f8, 0x9140, { 4, 4, 2, 2}}, + {m68k_op_subx_16_mm , 0xf1f8, 0x9148, { 18, 18, 12, 12}}, + {m68k_op_sub_16_re_ai , 0xf1f8, 0x9150, { 12, 12, 8, 8}}, + {m68k_op_sub_16_re_pi , 0xf1f8, 0x9158, { 12, 12, 8, 8}}, + {m68k_op_sub_16_re_pd , 0xf1f8, 0x9160, { 14, 14, 9, 9}}, + {m68k_op_sub_16_re_di , 0xf1f8, 0x9168, { 16, 16, 9, 9}}, + {m68k_op_sub_16_re_ix , 0xf1f8, 0x9170, { 18, 18, 11, 11}}, + {m68k_op_subx_32_rr , 0xf1f8, 0x9180, { 8, 6, 2, 2}}, + {m68k_op_subx_32_mm , 0xf1f8, 0x9188, { 30, 30, 12, 12}}, + {m68k_op_sub_32_re_ai , 0xf1f8, 0x9190, { 20, 20, 8, 8}}, + {m68k_op_sub_32_re_pi , 0xf1f8, 0x9198, { 20, 20, 8, 8}}, + {m68k_op_sub_32_re_pd , 0xf1f8, 0x91a0, { 22, 22, 9, 9}}, + {m68k_op_sub_32_re_di , 0xf1f8, 0x91a8, { 24, 24, 9, 9}}, + {m68k_op_sub_32_re_ix , 0xf1f8, 0x91b0, { 26, 26, 11, 11}}, + {m68k_op_suba_32_d , 0xf1f8, 0x91c0, { 8, 6, 2, 2}}, + {m68k_op_suba_32_a , 0xf1f8, 0x91c8, { 8, 6, 2, 2}}, + {m68k_op_suba_32_ai , 0xf1f8, 0x91d0, { 14, 14, 6, 6}}, + {m68k_op_suba_32_pi , 0xf1f8, 0x91d8, { 14, 14, 6, 6}}, + {m68k_op_suba_32_pd , 0xf1f8, 0x91e0, { 16, 16, 7, 7}}, + {m68k_op_suba_32_di , 0xf1f8, 0x91e8, { 18, 18, 7, 7}}, + {m68k_op_suba_32_ix , 0xf1f8, 0x91f0, { 20, 20, 9, 9}}, + {m68k_op_cmp_8_d , 0xf1f8, 0xb000, { 4, 4, 2, 2}}, + {m68k_op_cmp_8_ai , 0xf1f8, 0xb010, { 8, 8, 6, 6}}, + {m68k_op_cmp_8_pi , 0xf1f8, 0xb018, { 8, 8, 6, 6}}, + {m68k_op_cmp_8_pd , 0xf1f8, 0xb020, { 10, 10, 7, 7}}, + {m68k_op_cmp_8_di , 0xf1f8, 0xb028, { 12, 12, 7, 7}}, + {m68k_op_cmp_8_ix , 0xf1f8, 0xb030, { 14, 14, 9, 9}}, + {m68k_op_cmp_16_d , 0xf1f8, 0xb040, { 4, 4, 2, 2}}, + {m68k_op_cmp_16_a , 0xf1f8, 0xb048, { 4, 4, 2, 2}}, + {m68k_op_cmp_16_ai , 0xf1f8, 0xb050, { 8, 8, 6, 6}}, + {m68k_op_cmp_16_pi , 0xf1f8, 0xb058, { 8, 8, 6, 6}}, + {m68k_op_cmp_16_pd , 0xf1f8, 0xb060, { 10, 10, 7, 7}}, + {m68k_op_cmp_16_di , 0xf1f8, 0xb068, { 12, 12, 7, 7}}, + {m68k_op_cmp_16_ix , 0xf1f8, 0xb070, { 14, 14, 9, 9}}, + {m68k_op_cmp_32_d , 0xf1f8, 0xb080, { 6, 6, 2, 2}}, + {m68k_op_cmp_32_a , 0xf1f8, 0xb088, { 6, 6, 2, 2}}, + {m68k_op_cmp_32_ai , 0xf1f8, 0xb090, { 14, 14, 6, 6}}, + {m68k_op_cmp_32_pi , 0xf1f8, 0xb098, { 14, 14, 6, 6}}, + {m68k_op_cmp_32_pd , 0xf1f8, 0xb0a0, { 16, 16, 7, 7}}, + {m68k_op_cmp_32_di , 0xf1f8, 0xb0a8, { 18, 18, 7, 7}}, + {m68k_op_cmp_32_ix , 0xf1f8, 0xb0b0, { 20, 20, 9, 9}}, + {m68k_op_cmpa_16_d , 0xf1f8, 0xb0c0, { 6, 6, 4, 4}}, + {m68k_op_cmpa_16_a , 0xf1f8, 0xb0c8, { 6, 6, 4, 4}}, + {m68k_op_cmpa_16_ai , 0xf1f8, 0xb0d0, { 10, 10, 8, 8}}, + {m68k_op_cmpa_16_pi , 0xf1f8, 0xb0d8, { 10, 10, 8, 8}}, + {m68k_op_cmpa_16_pd , 0xf1f8, 0xb0e0, { 12, 12, 9, 9}}, + {m68k_op_cmpa_16_di , 0xf1f8, 0xb0e8, { 14, 14, 9, 9}}, + {m68k_op_cmpa_16_ix , 0xf1f8, 0xb0f0, { 16, 16, 11, 11}}, + {m68k_op_eor_8_d , 0xf1f8, 0xb100, { 4, 4, 2, 2}}, + {m68k_op_cmpm_8 , 0xf1f8, 0xb108, { 12, 12, 9, 9}}, + {m68k_op_eor_8_ai , 0xf1f8, 0xb110, { 12, 12, 8, 8}}, + {m68k_op_eor_8_pi , 0xf1f8, 0xb118, { 12, 12, 8, 8}}, + {m68k_op_eor_8_pd , 0xf1f8, 0xb120, { 14, 14, 9, 9}}, + {m68k_op_eor_8_di , 0xf1f8, 0xb128, { 16, 16, 9, 9}}, + {m68k_op_eor_8_ix , 0xf1f8, 0xb130, { 18, 18, 11, 11}}, + {m68k_op_eor_16_d , 0xf1f8, 0xb140, { 4, 4, 2, 2}}, + {m68k_op_cmpm_16 , 0xf1f8, 0xb148, { 12, 12, 9, 9}}, + {m68k_op_eor_16_ai , 0xf1f8, 0xb150, { 12, 12, 8, 8}}, + {m68k_op_eor_16_pi , 0xf1f8, 0xb158, { 12, 12, 8, 8}}, + {m68k_op_eor_16_pd , 0xf1f8, 0xb160, { 14, 14, 9, 9}}, + {m68k_op_eor_16_di , 0xf1f8, 0xb168, { 16, 16, 9, 9}}, + {m68k_op_eor_16_ix , 0xf1f8, 0xb170, { 18, 18, 11, 11}}, + {m68k_op_eor_32_d , 0xf1f8, 0xb180, { 8, 6, 2, 2}}, + {m68k_op_cmpm_32 , 0xf1f8, 0xb188, { 20, 20, 9, 9}}, + {m68k_op_eor_32_ai , 0xf1f8, 0xb190, { 20, 20, 8, 8}}, + {m68k_op_eor_32_pi , 0xf1f8, 0xb198, { 20, 20, 8, 8}}, + {m68k_op_eor_32_pd , 0xf1f8, 0xb1a0, { 22, 22, 9, 9}}, + {m68k_op_eor_32_di , 0xf1f8, 0xb1a8, { 24, 24, 9, 9}}, + {m68k_op_eor_32_ix , 0xf1f8, 0xb1b0, { 26, 26, 11, 11}}, + {m68k_op_cmpa_32_d , 0xf1f8, 0xb1c0, { 6, 6, 4, 4}}, + {m68k_op_cmpa_32_a , 0xf1f8, 0xb1c8, { 6, 6, 4, 4}}, + {m68k_op_cmpa_32_ai , 0xf1f8, 0xb1d0, { 14, 14, 8, 8}}, + {m68k_op_cmpa_32_pi , 0xf1f8, 0xb1d8, { 14, 14, 8, 8}}, + {m68k_op_cmpa_32_pd , 0xf1f8, 0xb1e0, { 16, 16, 9, 9}}, + {m68k_op_cmpa_32_di , 0xf1f8, 0xb1e8, { 18, 18, 9, 9}}, + {m68k_op_cmpa_32_ix , 0xf1f8, 0xb1f0, { 20, 20, 11, 11}}, + {m68k_op_and_8_er_d , 0xf1f8, 0xc000, { 4, 4, 2, 2}}, + {m68k_op_and_8_er_ai , 0xf1f8, 0xc010, { 8, 8, 6, 6}}, + {m68k_op_and_8_er_pi , 0xf1f8, 0xc018, { 8, 8, 6, 6}}, + {m68k_op_and_8_er_pd , 0xf1f8, 0xc020, { 10, 10, 7, 7}}, + {m68k_op_and_8_er_di , 0xf1f8, 0xc028, { 12, 12, 7, 7}}, + {m68k_op_and_8_er_ix , 0xf1f8, 0xc030, { 14, 14, 9, 9}}, + {m68k_op_and_16_er_d , 0xf1f8, 0xc040, { 4, 4, 2, 2}}, + {m68k_op_and_16_er_ai , 0xf1f8, 0xc050, { 8, 8, 6, 6}}, + {m68k_op_and_16_er_pi , 0xf1f8, 0xc058, { 8, 8, 6, 6}}, + {m68k_op_and_16_er_pd , 0xf1f8, 0xc060, { 10, 10, 7, 7}}, + {m68k_op_and_16_er_di , 0xf1f8, 0xc068, { 12, 12, 7, 7}}, + {m68k_op_and_16_er_ix , 0xf1f8, 0xc070, { 14, 14, 9, 9}}, + {m68k_op_and_32_er_d , 0xf1f8, 0xc080, { 8, 6, 2, 2}}, + {m68k_op_and_32_er_ai , 0xf1f8, 0xc090, { 14, 14, 6, 6}}, + {m68k_op_and_32_er_pi , 0xf1f8, 0xc098, { 14, 14, 6, 6}}, + {m68k_op_and_32_er_pd , 0xf1f8, 0xc0a0, { 16, 16, 7, 7}}, + {m68k_op_and_32_er_di , 0xf1f8, 0xc0a8, { 18, 18, 7, 7}}, + {m68k_op_and_32_er_ix , 0xf1f8, 0xc0b0, { 20, 20, 9, 9}}, + {m68k_op_mulu_16_d , 0xf1f8, 0xc0c0, { 54, 30, 27, 27}}, + {m68k_op_mulu_16_ai , 0xf1f8, 0xc0d0, { 58, 34, 31, 31}}, + {m68k_op_mulu_16_pi , 0xf1f8, 0xc0d8, { 58, 34, 31, 31}}, + {m68k_op_mulu_16_pd , 0xf1f8, 0xc0e0, { 60, 36, 32, 32}}, + {m68k_op_mulu_16_di , 0xf1f8, 0xc0e8, { 62, 38, 32, 32}}, + {m68k_op_mulu_16_ix , 0xf1f8, 0xc0f0, { 64, 40, 34, 34}}, + {m68k_op_abcd_8_rr , 0xf1f8, 0xc100, { 6, 6, 4, 4}}, + {m68k_op_abcd_8_mm , 0xf1f8, 0xc108, { 18, 18, 16, 16}}, + {m68k_op_and_8_re_ai , 0xf1f8, 0xc110, { 12, 12, 8, 8}}, + {m68k_op_and_8_re_pi , 0xf1f8, 0xc118, { 12, 12, 8, 8}}, + {m68k_op_and_8_re_pd , 0xf1f8, 0xc120, { 14, 14, 9, 9}}, + {m68k_op_and_8_re_di , 0xf1f8, 0xc128, { 16, 16, 9, 9}}, + {m68k_op_and_8_re_ix , 0xf1f8, 0xc130, { 18, 18, 11, 11}}, + {m68k_op_exg_32_dd , 0xf1f8, 0xc140, { 6, 6, 2, 2}}, + {m68k_op_exg_32_aa , 0xf1f8, 0xc148, { 6, 6, 2, 2}}, + {m68k_op_and_16_re_ai , 0xf1f8, 0xc150, { 12, 12, 8, 8}}, + {m68k_op_and_16_re_pi , 0xf1f8, 0xc158, { 12, 12, 8, 8}}, + {m68k_op_and_16_re_pd , 0xf1f8, 0xc160, { 14, 14, 9, 9}}, + {m68k_op_and_16_re_di , 0xf1f8, 0xc168, { 16, 16, 9, 9}}, + {m68k_op_and_16_re_ix , 0xf1f8, 0xc170, { 18, 18, 11, 11}}, + {m68k_op_exg_32_da , 0xf1f8, 0xc188, { 6, 6, 2, 2}}, + {m68k_op_and_32_re_ai , 0xf1f8, 0xc190, { 20, 20, 8, 8}}, + {m68k_op_and_32_re_pi , 0xf1f8, 0xc198, { 20, 20, 8, 8}}, + {m68k_op_and_32_re_pd , 0xf1f8, 0xc1a0, { 22, 22, 9, 9}}, + {m68k_op_and_32_re_di , 0xf1f8, 0xc1a8, { 24, 24, 9, 9}}, + {m68k_op_and_32_re_ix , 0xf1f8, 0xc1b0, { 26, 26, 11, 11}}, + {m68k_op_muls_16_d , 0xf1f8, 0xc1c0, { 54, 32, 27, 27}}, + {m68k_op_muls_16_ai , 0xf1f8, 0xc1d0, { 58, 36, 31, 31}}, + {m68k_op_muls_16_pi , 0xf1f8, 0xc1d8, { 58, 36, 31, 31}}, + {m68k_op_muls_16_pd , 0xf1f8, 0xc1e0, { 60, 38, 32, 32}}, + {m68k_op_muls_16_di , 0xf1f8, 0xc1e8, { 62, 40, 32, 32}}, + {m68k_op_muls_16_ix , 0xf1f8, 0xc1f0, { 64, 42, 34, 34}}, + {m68k_op_add_8_er_d , 0xf1f8, 0xd000, { 4, 4, 2, 2}}, + {m68k_op_add_8_er_ai , 0xf1f8, 0xd010, { 8, 8, 6, 6}}, + {m68k_op_add_8_er_pi , 0xf1f8, 0xd018, { 8, 8, 6, 6}}, + {m68k_op_add_8_er_pd , 0xf1f8, 0xd020, { 10, 10, 7, 7}}, + {m68k_op_add_8_er_di , 0xf1f8, 0xd028, { 12, 12, 7, 7}}, + {m68k_op_add_8_er_ix , 0xf1f8, 0xd030, { 14, 14, 9, 9}}, + {m68k_op_add_16_er_d , 0xf1f8, 0xd040, { 4, 4, 2, 2}}, + {m68k_op_add_16_er_a , 0xf1f8, 0xd048, { 4, 4, 2, 2}}, + {m68k_op_add_16_er_ai , 0xf1f8, 0xd050, { 8, 8, 6, 6}}, + {m68k_op_add_16_er_pi , 0xf1f8, 0xd058, { 8, 8, 6, 6}}, + {m68k_op_add_16_er_pd , 0xf1f8, 0xd060, { 10, 10, 7, 7}}, + {m68k_op_add_16_er_di , 0xf1f8, 0xd068, { 12, 12, 7, 7}}, + {m68k_op_add_16_er_ix , 0xf1f8, 0xd070, { 14, 14, 9, 9}}, + {m68k_op_add_32_er_d , 0xf1f8, 0xd080, { 8, 6, 2, 2}}, + {m68k_op_add_32_er_a , 0xf1f8, 0xd088, { 8, 6, 2, 2}}, + {m68k_op_add_32_er_ai , 0xf1f8, 0xd090, { 14, 14, 6, 6}}, + {m68k_op_add_32_er_pi , 0xf1f8, 0xd098, { 14, 14, 6, 6}}, + {m68k_op_add_32_er_pd , 0xf1f8, 0xd0a0, { 16, 16, 7, 7}}, + {m68k_op_add_32_er_di , 0xf1f8, 0xd0a8, { 18, 18, 7, 7}}, + {m68k_op_add_32_er_ix , 0xf1f8, 0xd0b0, { 20, 20, 9, 9}}, + {m68k_op_adda_16_d , 0xf1f8, 0xd0c0, { 8, 8, 2, 2}}, + {m68k_op_adda_16_a , 0xf1f8, 0xd0c8, { 8, 8, 2, 2}}, + {m68k_op_adda_16_ai , 0xf1f8, 0xd0d0, { 12, 12, 6, 6}}, + {m68k_op_adda_16_pi , 0xf1f8, 0xd0d8, { 12, 12, 6, 6}}, + {m68k_op_adda_16_pd , 0xf1f8, 0xd0e0, { 14, 14, 7, 7}}, + {m68k_op_adda_16_di , 0xf1f8, 0xd0e8, { 16, 16, 7, 7}}, + {m68k_op_adda_16_ix , 0xf1f8, 0xd0f0, { 18, 18, 9, 9}}, + {m68k_op_addx_8_rr , 0xf1f8, 0xd100, { 4, 4, 2, 2}}, + {m68k_op_addx_8_mm , 0xf1f8, 0xd108, { 18, 18, 12, 12}}, + {m68k_op_add_8_re_ai , 0xf1f8, 0xd110, { 12, 12, 8, 8}}, + {m68k_op_add_8_re_pi , 0xf1f8, 0xd118, { 12, 12, 8, 8}}, + {m68k_op_add_8_re_pd , 0xf1f8, 0xd120, { 14, 14, 9, 9}}, + {m68k_op_add_8_re_di , 0xf1f8, 0xd128, { 16, 16, 9, 9}}, + {m68k_op_add_8_re_ix , 0xf1f8, 0xd130, { 18, 18, 11, 11}}, + {m68k_op_addx_16_rr , 0xf1f8, 0xd140, { 4, 4, 2, 2}}, + {m68k_op_addx_16_mm , 0xf1f8, 0xd148, { 18, 18, 12, 12}}, + {m68k_op_add_16_re_ai , 0xf1f8, 0xd150, { 12, 12, 8, 8}}, + {m68k_op_add_16_re_pi , 0xf1f8, 0xd158, { 12, 12, 8, 8}}, + {m68k_op_add_16_re_pd , 0xf1f8, 0xd160, { 14, 14, 9, 9}}, + {m68k_op_add_16_re_di , 0xf1f8, 0xd168, { 16, 16, 9, 9}}, + {m68k_op_add_16_re_ix , 0xf1f8, 0xd170, { 18, 18, 11, 11}}, + {m68k_op_addx_32_rr , 0xf1f8, 0xd180, { 8, 6, 2, 2}}, + {m68k_op_addx_32_mm , 0xf1f8, 0xd188, { 30, 30, 12, 12}}, + {m68k_op_add_32_re_ai , 0xf1f8, 0xd190, { 20, 20, 8, 8}}, + {m68k_op_add_32_re_pi , 0xf1f8, 0xd198, { 20, 20, 8, 8}}, + {m68k_op_add_32_re_pd , 0xf1f8, 0xd1a0, { 22, 22, 9, 9}}, + {m68k_op_add_32_re_di , 0xf1f8, 0xd1a8, { 24, 24, 9, 9}}, + {m68k_op_add_32_re_ix , 0xf1f8, 0xd1b0, { 26, 26, 11, 11}}, + {m68k_op_adda_32_d , 0xf1f8, 0xd1c0, { 8, 6, 2, 2}}, + {m68k_op_adda_32_a , 0xf1f8, 0xd1c8, { 8, 6, 2, 2}}, + {m68k_op_adda_32_ai , 0xf1f8, 0xd1d0, { 14, 14, 6, 6}}, + {m68k_op_adda_32_pi , 0xf1f8, 0xd1d8, { 14, 14, 6, 6}}, + {m68k_op_adda_32_pd , 0xf1f8, 0xd1e0, { 16, 16, 7, 7}}, + {m68k_op_adda_32_di , 0xf1f8, 0xd1e8, { 18, 18, 7, 7}}, + {m68k_op_adda_32_ix , 0xf1f8, 0xd1f0, { 20, 20, 9, 9}}, + {m68k_op_asr_8_s , 0xf1f8, 0xe000, { 6, 6, 6, 6}}, + {m68k_op_lsr_8_s , 0xf1f8, 0xe008, { 6, 6, 4, 4}}, + {m68k_op_roxr_8_s , 0xf1f8, 0xe010, { 6, 6, 12, 12}}, + {m68k_op_ror_8_s , 0xf1f8, 0xe018, { 6, 6, 8, 8}}, + {m68k_op_asr_8_r , 0xf1f8, 0xe020, { 6, 6, 6, 6}}, + {m68k_op_lsr_8_r , 0xf1f8, 0xe028, { 6, 6, 6, 6}}, + {m68k_op_roxr_8_r , 0xf1f8, 0xe030, { 6, 6, 12, 12}}, + {m68k_op_ror_8_r , 0xf1f8, 0xe038, { 6, 6, 8, 8}}, + {m68k_op_asr_16_s , 0xf1f8, 0xe040, { 6, 6, 6, 6}}, + {m68k_op_lsr_16_s , 0xf1f8, 0xe048, { 6, 6, 4, 4}}, + {m68k_op_roxr_16_s , 0xf1f8, 0xe050, { 6, 6, 12, 12}}, + {m68k_op_ror_16_s , 0xf1f8, 0xe058, { 6, 6, 8, 8}}, + {m68k_op_asr_16_r , 0xf1f8, 0xe060, { 6, 6, 6, 6}}, + {m68k_op_lsr_16_r , 0xf1f8, 0xe068, { 6, 6, 6, 6}}, + {m68k_op_roxr_16_r , 0xf1f8, 0xe070, { 6, 6, 12, 12}}, + {m68k_op_ror_16_r , 0xf1f8, 0xe078, { 6, 6, 8, 8}}, + {m68k_op_asr_32_s , 0xf1f8, 0xe080, { 8, 8, 6, 6}}, + {m68k_op_lsr_32_s , 0xf1f8, 0xe088, { 8, 8, 4, 4}}, + {m68k_op_roxr_32_s , 0xf1f8, 0xe090, { 8, 8, 12, 12}}, + {m68k_op_ror_32_s , 0xf1f8, 0xe098, { 8, 8, 8, 8}}, + {m68k_op_asr_32_r , 0xf1f8, 0xe0a0, { 8, 8, 6, 6}}, + {m68k_op_lsr_32_r , 0xf1f8, 0xe0a8, { 8, 8, 6, 6}}, + {m68k_op_roxr_32_r , 0xf1f8, 0xe0b0, { 8, 8, 12, 12}}, + {m68k_op_ror_32_r , 0xf1f8, 0xe0b8, { 8, 8, 8, 8}}, + {m68k_op_asl_8_s , 0xf1f8, 0xe100, { 6, 6, 8, 8}}, + {m68k_op_lsl_8_s , 0xf1f8, 0xe108, { 6, 6, 4, 4}}, + {m68k_op_roxl_8_s , 0xf1f8, 0xe110, { 6, 6, 12, 12}}, + {m68k_op_rol_8_s , 0xf1f8, 0xe118, { 6, 6, 8, 8}}, + {m68k_op_asl_8_r , 0xf1f8, 0xe120, { 6, 6, 8, 8}}, + {m68k_op_lsl_8_r , 0xf1f8, 0xe128, { 6, 6, 6, 6}}, + {m68k_op_roxl_8_r , 0xf1f8, 0xe130, { 6, 6, 12, 12}}, + {m68k_op_rol_8_r , 0xf1f8, 0xe138, { 6, 6, 8, 8}}, + {m68k_op_asl_16_s , 0xf1f8, 0xe140, { 6, 6, 8, 8}}, + {m68k_op_lsl_16_s , 0xf1f8, 0xe148, { 6, 6, 4, 4}}, + {m68k_op_roxl_16_s , 0xf1f8, 0xe150, { 6, 6, 12, 12}}, + {m68k_op_rol_16_s , 0xf1f8, 0xe158, { 6, 6, 8, 8}}, + {m68k_op_asl_16_r , 0xf1f8, 0xe160, { 6, 6, 8, 8}}, + {m68k_op_lsl_16_r , 0xf1f8, 0xe168, { 6, 6, 6, 6}}, + {m68k_op_roxl_16_r , 0xf1f8, 0xe170, { 6, 6, 12, 12}}, + {m68k_op_rol_16_r , 0xf1f8, 0xe178, { 6, 6, 8, 8}}, + {m68k_op_asl_32_s , 0xf1f8, 0xe180, { 8, 8, 8, 8}}, + {m68k_op_lsl_32_s , 0xf1f8, 0xe188, { 8, 8, 4, 4}}, + {m68k_op_roxl_32_s , 0xf1f8, 0xe190, { 8, 8, 12, 12}}, + {m68k_op_rol_32_s , 0xf1f8, 0xe198, { 8, 8, 8, 8}}, + {m68k_op_asl_32_r , 0xf1f8, 0xe1a0, { 8, 8, 8, 8}}, + {m68k_op_lsl_32_r , 0xf1f8, 0xe1a8, { 8, 8, 6, 6}}, + {m68k_op_roxl_32_r , 0xf1f8, 0xe1b0, { 8, 8, 12, 12}}, + {m68k_op_rol_32_r , 0xf1f8, 0xe1b8, { 8, 8, 8, 8}}, + {m68k_op_cpdbcc_32 , 0xf1f8, 0xf048, { 0, 0, 4, 0}}, + {m68k_op_cptrapcc_32 , 0xf1f8, 0xf078, { 0, 0, 4, 0}}, + {m68k_op_rtm_32 , 0xfff0, 0x06c0, { 0, 0, 19, 19}}, + {m68k_op_trap , 0xfff0, 0x4e40, { 4, 4, 4, 4}}, + {m68k_op_btst_8_r_pi7 , 0xf1ff, 0x011f, { 8, 8, 8, 8}}, + {m68k_op_btst_8_r_pd7 , 0xf1ff, 0x0127, { 10, 10, 9, 9}}, + {m68k_op_btst_8_r_aw , 0xf1ff, 0x0138, { 12, 12, 8, 8}}, + {m68k_op_btst_8_r_al , 0xf1ff, 0x0139, { 16, 16, 8, 8}}, + {m68k_op_btst_8_r_pcdi , 0xf1ff, 0x013a, { 12, 12, 9, 9}}, + {m68k_op_btst_8_r_pcix , 0xf1ff, 0x013b, { 14, 14, 11, 11}}, + {m68k_op_btst_8_r_i , 0xf1ff, 0x013c, { 8, 8, 6, 6}}, + {m68k_op_bchg_8_r_pi7 , 0xf1ff, 0x015f, { 12, 12, 8, 8}}, + {m68k_op_bchg_8_r_pd7 , 0xf1ff, 0x0167, { 14, 14, 9, 9}}, + {m68k_op_bchg_8_r_aw , 0xf1ff, 0x0178, { 16, 16, 8, 8}}, + {m68k_op_bchg_8_r_al , 0xf1ff, 0x0179, { 20, 20, 8, 8}}, + {m68k_op_bclr_8_r_pi7 , 0xf1ff, 0x019f, { 12, 14, 8, 8}}, + {m68k_op_bclr_8_r_pd7 , 0xf1ff, 0x01a7, { 14, 16, 9, 9}}, + {m68k_op_bclr_8_r_aw , 0xf1ff, 0x01b8, { 16, 18, 8, 8}}, + {m68k_op_bclr_8_r_al , 0xf1ff, 0x01b9, { 20, 22, 8, 8}}, + {m68k_op_bset_8_r_pi7 , 0xf1ff, 0x01df, { 12, 12, 8, 8}}, + {m68k_op_bset_8_r_pd7 , 0xf1ff, 0x01e7, { 14, 14, 9, 9}}, + {m68k_op_bset_8_r_aw , 0xf1ff, 0x01f8, { 16, 16, 8, 8}}, + {m68k_op_bset_8_r_al , 0xf1ff, 0x01f9, { 20, 20, 8, 8}}, + {m68k_op_move_8_d_pi7 , 0xf1ff, 0x101f, { 8, 8, 6, 6}}, + {m68k_op_move_8_d_pd7 , 0xf1ff, 0x1027, { 10, 10, 7, 7}}, + {m68k_op_move_8_d_aw , 0xf1ff, 0x1038, { 12, 12, 6, 6}}, + {m68k_op_move_8_d_al , 0xf1ff, 0x1039, { 16, 16, 6, 6}}, + {m68k_op_move_8_d_pcdi , 0xf1ff, 0x103a, { 12, 12, 7, 7}}, + {m68k_op_move_8_d_pcix , 0xf1ff, 0x103b, { 14, 14, 9, 9}}, + {m68k_op_move_8_d_i , 0xf1ff, 0x103c, { 8, 8, 4, 4}}, + {m68k_op_move_8_ai_pi7 , 0xf1ff, 0x109f, { 12, 12, 8, 8}}, + {m68k_op_move_8_ai_pd7 , 0xf1ff, 0x10a7, { 14, 14, 9, 9}}, + {m68k_op_move_8_ai_aw , 0xf1ff, 0x10b8, { 16, 16, 8, 8}}, + {m68k_op_move_8_ai_al , 0xf1ff, 0x10b9, { 20, 20, 8, 8}}, + {m68k_op_move_8_ai_pcdi , 0xf1ff, 0x10ba, { 16, 16, 9, 9}}, + {m68k_op_move_8_ai_pcix , 0xf1ff, 0x10bb, { 18, 18, 11, 11}}, + {m68k_op_move_8_ai_i , 0xf1ff, 0x10bc, { 12, 12, 6, 6}}, + {m68k_op_move_8_pi_pi7 , 0xf1ff, 0x10df, { 12, 12, 8, 8}}, + {m68k_op_move_8_pi_pd7 , 0xf1ff, 0x10e7, { 14, 14, 9, 9}}, + {m68k_op_move_8_pi_aw , 0xf1ff, 0x10f8, { 16, 16, 8, 8}}, + {m68k_op_move_8_pi_al , 0xf1ff, 0x10f9, { 20, 20, 8, 8}}, + {m68k_op_move_8_pi_pcdi , 0xf1ff, 0x10fa, { 16, 16, 9, 9}}, + {m68k_op_move_8_pi_pcix , 0xf1ff, 0x10fb, { 18, 18, 11, 11}}, + {m68k_op_move_8_pi_i , 0xf1ff, 0x10fc, { 12, 12, 6, 6}}, + {m68k_op_move_8_pd_pi7 , 0xf1ff, 0x111f, { 12, 12, 9, 9}}, + {m68k_op_move_8_pd_pd7 , 0xf1ff, 0x1127, { 14, 14, 10, 10}}, + {m68k_op_move_8_pd_aw , 0xf1ff, 0x1138, { 16, 16, 9, 9}}, + {m68k_op_move_8_pd_al , 0xf1ff, 0x1139, { 20, 20, 9, 9}}, + {m68k_op_move_8_pd_pcdi , 0xf1ff, 0x113a, { 16, 16, 10, 10}}, + {m68k_op_move_8_pd_pcix , 0xf1ff, 0x113b, { 18, 18, 12, 12}}, + {m68k_op_move_8_pd_i , 0xf1ff, 0x113c, { 12, 12, 7, 7}}, + {m68k_op_move_8_di_pi7 , 0xf1ff, 0x115f, { 16, 16, 9, 9}}, + {m68k_op_move_8_di_pd7 , 0xf1ff, 0x1167, { 18, 18, 10, 10}}, + {m68k_op_move_8_di_aw , 0xf1ff, 0x1178, { 20, 20, 9, 9}}, + {m68k_op_move_8_di_al , 0xf1ff, 0x1179, { 24, 24, 9, 9}}, + {m68k_op_move_8_di_pcdi , 0xf1ff, 0x117a, { 20, 20, 10, 10}}, + {m68k_op_move_8_di_pcix , 0xf1ff, 0x117b, { 22, 22, 12, 12}}, + {m68k_op_move_8_di_i , 0xf1ff, 0x117c, { 16, 16, 7, 7}}, + {m68k_op_move_8_ix_pi7 , 0xf1ff, 0x119f, { 18, 18, 11, 11}}, + {m68k_op_move_8_ix_pd7 , 0xf1ff, 0x11a7, { 20, 20, 12, 12}}, + {m68k_op_move_8_ix_aw , 0xf1ff, 0x11b8, { 22, 22, 11, 11}}, + {m68k_op_move_8_ix_al , 0xf1ff, 0x11b9, { 26, 26, 11, 11}}, + {m68k_op_move_8_ix_pcdi , 0xf1ff, 0x11ba, { 22, 22, 12, 12}}, + {m68k_op_move_8_ix_pcix , 0xf1ff, 0x11bb, { 24, 24, 14, 14}}, + {m68k_op_move_8_ix_i , 0xf1ff, 0x11bc, { 18, 18, 9, 9}}, + {m68k_op_move_32_d_aw , 0xf1ff, 0x2038, { 16, 16, 6, 6}}, + {m68k_op_move_32_d_al , 0xf1ff, 0x2039, { 20, 20, 6, 6}}, + {m68k_op_move_32_d_pcdi , 0xf1ff, 0x203a, { 16, 16, 7, 7}}, + {m68k_op_move_32_d_pcix , 0xf1ff, 0x203b, { 18, 18, 9, 9}}, + {m68k_op_move_32_d_i , 0xf1ff, 0x203c, { 12, 12, 6, 6}}, + {m68k_op_movea_32_aw , 0xf1ff, 0x2078, { 16, 16, 6, 6}}, + {m68k_op_movea_32_al , 0xf1ff, 0x2079, { 20, 20, 6, 6}}, + {m68k_op_movea_32_pcdi , 0xf1ff, 0x207a, { 16, 16, 7, 7}}, + {m68k_op_movea_32_pcix , 0xf1ff, 0x207b, { 18, 18, 9, 9}}, + {m68k_op_movea_32_i , 0xf1ff, 0x207c, { 12, 12, 6, 6}}, + {m68k_op_move_32_ai_aw , 0xf1ff, 0x20b8, { 24, 24, 8, 8}}, + {m68k_op_move_32_ai_al , 0xf1ff, 0x20b9, { 28, 28, 8, 8}}, + {m68k_op_move_32_ai_pcdi , 0xf1ff, 0x20ba, { 24, 24, 9, 9}}, + {m68k_op_move_32_ai_pcix , 0xf1ff, 0x20bb, { 26, 26, 11, 11}}, + {m68k_op_move_32_ai_i , 0xf1ff, 0x20bc, { 20, 20, 8, 8}}, + {m68k_op_move_32_pi_aw , 0xf1ff, 0x20f8, { 24, 24, 8, 8}}, + {m68k_op_move_32_pi_al , 0xf1ff, 0x20f9, { 28, 28, 8, 8}}, + {m68k_op_move_32_pi_pcdi , 0xf1ff, 0x20fa, { 24, 24, 9, 9}}, + {m68k_op_move_32_pi_pcix , 0xf1ff, 0x20fb, { 26, 26, 11, 11}}, + {m68k_op_move_32_pi_i , 0xf1ff, 0x20fc, { 20, 20, 8, 8}}, + {m68k_op_move_32_pd_aw , 0xf1ff, 0x2138, { 24, 26, 9, 9}}, + {m68k_op_move_32_pd_al , 0xf1ff, 0x2139, { 28, 30, 9, 9}}, + {m68k_op_move_32_pd_pcdi , 0xf1ff, 0x213a, { 24, 26, 10, 10}}, + {m68k_op_move_32_pd_pcix , 0xf1ff, 0x213b, { 26, 28, 12, 12}}, + {m68k_op_move_32_pd_i , 0xf1ff, 0x213c, { 20, 22, 9, 9}}, + {m68k_op_move_32_di_aw , 0xf1ff, 0x2178, { 28, 28, 9, 9}}, + {m68k_op_move_32_di_al , 0xf1ff, 0x2179, { 32, 32, 9, 9}}, + {m68k_op_move_32_di_pcdi , 0xf1ff, 0x217a, { 28, 28, 10, 10}}, + {m68k_op_move_32_di_pcix , 0xf1ff, 0x217b, { 30, 30, 12, 12}}, + {m68k_op_move_32_di_i , 0xf1ff, 0x217c, { 24, 24, 9, 9}}, + {m68k_op_move_32_ix_aw , 0xf1ff, 0x21b8, { 30, 30, 11, 11}}, + {m68k_op_move_32_ix_al , 0xf1ff, 0x21b9, { 34, 34, 11, 11}}, + {m68k_op_move_32_ix_pcdi , 0xf1ff, 0x21ba, { 30, 30, 12, 12}}, + {m68k_op_move_32_ix_pcix , 0xf1ff, 0x21bb, { 32, 32, 14, 14}}, + {m68k_op_move_32_ix_i , 0xf1ff, 0x21bc, { 26, 26, 11, 11}}, + {m68k_op_move_16_d_aw , 0xf1ff, 0x3038, { 12, 12, 6, 6}}, + {m68k_op_move_16_d_al , 0xf1ff, 0x3039, { 16, 16, 6, 6}}, + {m68k_op_move_16_d_pcdi , 0xf1ff, 0x303a, { 12, 12, 7, 7}}, + {m68k_op_move_16_d_pcix , 0xf1ff, 0x303b, { 14, 14, 9, 9}}, + {m68k_op_move_16_d_i , 0xf1ff, 0x303c, { 8, 8, 4, 4}}, + {m68k_op_movea_16_aw , 0xf1ff, 0x3078, { 12, 12, 6, 6}}, + {m68k_op_movea_16_al , 0xf1ff, 0x3079, { 16, 16, 6, 6}}, + {m68k_op_movea_16_pcdi , 0xf1ff, 0x307a, { 12, 12, 7, 7}}, + {m68k_op_movea_16_pcix , 0xf1ff, 0x307b, { 14, 14, 9, 9}}, + {m68k_op_movea_16_i , 0xf1ff, 0x307c, { 8, 8, 4, 4}}, + {m68k_op_move_16_ai_aw , 0xf1ff, 0x30b8, { 16, 16, 8, 8}}, + {m68k_op_move_16_ai_al , 0xf1ff, 0x30b9, { 20, 20, 8, 8}}, + {m68k_op_move_16_ai_pcdi , 0xf1ff, 0x30ba, { 16, 16, 9, 9}}, + {m68k_op_move_16_ai_pcix , 0xf1ff, 0x30bb, { 18, 18, 11, 11}}, + {m68k_op_move_16_ai_i , 0xf1ff, 0x30bc, { 12, 12, 6, 6}}, + {m68k_op_move_16_pi_aw , 0xf1ff, 0x30f8, { 16, 16, 8, 8}}, + {m68k_op_move_16_pi_al , 0xf1ff, 0x30f9, { 20, 20, 8, 8}}, + {m68k_op_move_16_pi_pcdi , 0xf1ff, 0x30fa, { 16, 16, 9, 9}}, + {m68k_op_move_16_pi_pcix , 0xf1ff, 0x30fb, { 18, 18, 11, 11}}, + {m68k_op_move_16_pi_i , 0xf1ff, 0x30fc, { 12, 12, 6, 6}}, + {m68k_op_move_16_pd_aw , 0xf1ff, 0x3138, { 16, 16, 9, 9}}, + {m68k_op_move_16_pd_al , 0xf1ff, 0x3139, { 20, 20, 9, 9}}, + {m68k_op_move_16_pd_pcdi , 0xf1ff, 0x313a, { 16, 16, 10, 10}}, + {m68k_op_move_16_pd_pcix , 0xf1ff, 0x313b, { 18, 18, 12, 12}}, + {m68k_op_move_16_pd_i , 0xf1ff, 0x313c, { 12, 12, 7, 7}}, + {m68k_op_move_16_di_aw , 0xf1ff, 0x3178, { 20, 20, 9, 9}}, + {m68k_op_move_16_di_al , 0xf1ff, 0x3179, { 24, 24, 9, 9}}, + {m68k_op_move_16_di_pcdi , 0xf1ff, 0x317a, { 20, 20, 10, 10}}, + {m68k_op_move_16_di_pcix , 0xf1ff, 0x317b, { 22, 22, 12, 12}}, + {m68k_op_move_16_di_i , 0xf1ff, 0x317c, { 16, 16, 7, 7}}, + {m68k_op_move_16_ix_aw , 0xf1ff, 0x31b8, { 22, 22, 11, 11}}, + {m68k_op_move_16_ix_al , 0xf1ff, 0x31b9, { 26, 26, 11, 11}}, + {m68k_op_move_16_ix_pcdi , 0xf1ff, 0x31ba, { 22, 22, 12, 12}}, + {m68k_op_move_16_ix_pcix , 0xf1ff, 0x31bb, { 24, 24, 14, 14}}, + {m68k_op_move_16_ix_i , 0xf1ff, 0x31bc, { 18, 18, 9, 9}}, + {m68k_op_chk_32_aw , 0xf1ff, 0x4138, { 0, 0, 12, 12}}, + {m68k_op_chk_32_al , 0xf1ff, 0x4139, { 0, 0, 12, 12}}, + {m68k_op_chk_32_pcdi , 0xf1ff, 0x413a, { 0, 0, 13, 13}}, + {m68k_op_chk_32_pcix , 0xf1ff, 0x413b, { 0, 0, 15, 15}}, + {m68k_op_chk_32_i , 0xf1ff, 0x413c, { 0, 0, 12, 12}}, + {m68k_op_chk_16_aw , 0xf1ff, 0x41b8, { 18, 16, 12, 12}}, + {m68k_op_chk_16_al , 0xf1ff, 0x41b9, { 22, 20, 12, 12}}, + {m68k_op_chk_16_pcdi , 0xf1ff, 0x41ba, { 18, 16, 13, 13}}, + {m68k_op_chk_16_pcix , 0xf1ff, 0x41bb, { 20, 18, 15, 15}}, + {m68k_op_chk_16_i , 0xf1ff, 0x41bc, { 14, 12, 10, 10}}, + {m68k_op_lea_32_aw , 0xf1ff, 0x41f8, { 8, 8, 6, 6}}, + {m68k_op_lea_32_al , 0xf1ff, 0x41f9, { 12, 12, 6, 6}}, + {m68k_op_lea_32_pcdi , 0xf1ff, 0x41fa, { 8, 8, 7, 7}}, + {m68k_op_lea_32_pcix , 0xf1ff, 0x41fb, { 12, 12, 9, 9}}, + {m68k_op_addq_8_pi7 , 0xf1ff, 0x501f, { 12, 12, 8, 8}}, + {m68k_op_addq_8_pd7 , 0xf1ff, 0x5027, { 14, 14, 9, 9}}, + {m68k_op_addq_8_aw , 0xf1ff, 0x5038, { 16, 16, 8, 8}}, + {m68k_op_addq_8_al , 0xf1ff, 0x5039, { 20, 20, 8, 8}}, + {m68k_op_addq_16_aw , 0xf1ff, 0x5078, { 16, 16, 8, 8}}, + {m68k_op_addq_16_al , 0xf1ff, 0x5079, { 20, 20, 8, 8}}, + {m68k_op_addq_32_aw , 0xf1ff, 0x50b8, { 24, 24, 8, 8}}, + {m68k_op_addq_32_al , 0xf1ff, 0x50b9, { 28, 28, 8, 8}}, + {m68k_op_subq_8_pi7 , 0xf1ff, 0x511f, { 12, 12, 8, 8}}, + {m68k_op_subq_8_pd7 , 0xf1ff, 0x5127, { 14, 14, 9, 9}}, + {m68k_op_subq_8_aw , 0xf1ff, 0x5138, { 16, 16, 8, 8}}, + {m68k_op_subq_8_al , 0xf1ff, 0x5139, { 20, 20, 8, 8}}, + {m68k_op_subq_16_aw , 0xf1ff, 0x5178, { 16, 16, 8, 8}}, + {m68k_op_subq_16_al , 0xf1ff, 0x5179, { 20, 20, 8, 8}}, + {m68k_op_subq_32_aw , 0xf1ff, 0x51b8, { 24, 24, 8, 8}}, + {m68k_op_subq_32_al , 0xf1ff, 0x51b9, { 28, 28, 8, 8}}, + {m68k_op_or_8_er_pi7 , 0xf1ff, 0x801f, { 8, 8, 6, 6}}, + {m68k_op_or_8_er_pd7 , 0xf1ff, 0x8027, { 10, 10, 7, 7}}, + {m68k_op_or_8_er_aw , 0xf1ff, 0x8038, { 12, 12, 6, 6}}, + {m68k_op_or_8_er_al , 0xf1ff, 0x8039, { 16, 16, 6, 6}}, + {m68k_op_or_8_er_pcdi , 0xf1ff, 0x803a, { 12, 12, 7, 7}}, + {m68k_op_or_8_er_pcix , 0xf1ff, 0x803b, { 14, 14, 9, 9}}, + {m68k_op_or_8_er_i , 0xf1ff, 0x803c, { 8, 8, 4, 4}}, + {m68k_op_or_16_er_aw , 0xf1ff, 0x8078, { 12, 12, 6, 6}}, + {m68k_op_or_16_er_al , 0xf1ff, 0x8079, { 16, 16, 6, 6}}, + {m68k_op_or_16_er_pcdi , 0xf1ff, 0x807a, { 12, 12, 7, 7}}, + {m68k_op_or_16_er_pcix , 0xf1ff, 0x807b, { 14, 14, 9, 9}}, + {m68k_op_or_16_er_i , 0xf1ff, 0x807c, { 8, 8, 4, 4}}, + {m68k_op_or_32_er_aw , 0xf1ff, 0x80b8, { 18, 18, 6, 6}}, + {m68k_op_or_32_er_al , 0xf1ff, 0x80b9, { 22, 22, 6, 6}}, + {m68k_op_or_32_er_pcdi , 0xf1ff, 0x80ba, { 18, 18, 7, 7}}, + {m68k_op_or_32_er_pcix , 0xf1ff, 0x80bb, { 20, 20, 9, 9}}, + {m68k_op_or_32_er_i , 0xf1ff, 0x80bc, { 16, 14, 6, 6}}, + {m68k_op_divu_16_aw , 0xf1ff, 0x80f8, {148, 116, 48, 48}}, + {m68k_op_divu_16_al , 0xf1ff, 0x80f9, {152, 120, 48, 48}}, + {m68k_op_divu_16_pcdi , 0xf1ff, 0x80fa, {148, 116, 49, 49}}, + {m68k_op_divu_16_pcix , 0xf1ff, 0x80fb, {150, 118, 51, 51}}, + {m68k_op_divu_16_i , 0xf1ff, 0x80fc, {144, 112, 46, 46}}, + {m68k_op_sbcd_8_mm_ay7 , 0xf1ff, 0x810f, { 18, 18, 16, 16}}, + {m68k_op_or_8_re_pi7 , 0xf1ff, 0x811f, { 12, 12, 8, 8}}, + {m68k_op_or_8_re_pd7 , 0xf1ff, 0x8127, { 14, 14, 9, 9}}, + {m68k_op_or_8_re_aw , 0xf1ff, 0x8138, { 16, 16, 8, 8}}, + {m68k_op_or_8_re_al , 0xf1ff, 0x8139, { 20, 20, 8, 8}}, + {m68k_op_pack_16_mm_ay7 , 0xf1ff, 0x814f, { 0, 0, 13, 13}}, + {m68k_op_or_16_re_aw , 0xf1ff, 0x8178, { 16, 16, 8, 8}}, + {m68k_op_or_16_re_al , 0xf1ff, 0x8179, { 20, 20, 8, 8}}, + {m68k_op_unpk_16_mm_ay7 , 0xf1ff, 0x818f, { 0, 0, 13, 13}}, + {m68k_op_or_32_re_aw , 0xf1ff, 0x81b8, { 24, 24, 8, 8}}, + {m68k_op_or_32_re_al , 0xf1ff, 0x81b9, { 28, 28, 8, 8}}, + {m68k_op_divs_16_aw , 0xf1ff, 0x81f8, {166, 130, 60, 60}}, + {m68k_op_divs_16_al , 0xf1ff, 0x81f9, {170, 134, 60, 60}}, + {m68k_op_divs_16_pcdi , 0xf1ff, 0x81fa, {166, 130, 61, 61}}, + {m68k_op_divs_16_pcix , 0xf1ff, 0x81fb, {168, 132, 63, 63}}, + {m68k_op_divs_16_i , 0xf1ff, 0x81fc, {162, 126, 58, 58}}, + {m68k_op_sub_8_er_pi7 , 0xf1ff, 0x901f, { 8, 8, 6, 6}}, + {m68k_op_sub_8_er_pd7 , 0xf1ff, 0x9027, { 10, 10, 7, 7}}, + {m68k_op_sub_8_er_aw , 0xf1ff, 0x9038, { 12, 12, 6, 6}}, + {m68k_op_sub_8_er_al , 0xf1ff, 0x9039, { 16, 16, 6, 6}}, + {m68k_op_sub_8_er_pcdi , 0xf1ff, 0x903a, { 12, 12, 7, 7}}, + {m68k_op_sub_8_er_pcix , 0xf1ff, 0x903b, { 14, 14, 9, 9}}, + {m68k_op_sub_8_er_i , 0xf1ff, 0x903c, { 8, 8, 4, 4}}, + {m68k_op_sub_16_er_aw , 0xf1ff, 0x9078, { 12, 12, 6, 6}}, + {m68k_op_sub_16_er_al , 0xf1ff, 0x9079, { 16, 16, 6, 6}}, + {m68k_op_sub_16_er_pcdi , 0xf1ff, 0x907a, { 12, 12, 7, 7}}, + {m68k_op_sub_16_er_pcix , 0xf1ff, 0x907b, { 14, 14, 9, 9}}, + {m68k_op_sub_16_er_i , 0xf1ff, 0x907c, { 8, 8, 4, 4}}, + {m68k_op_sub_32_er_aw , 0xf1ff, 0x90b8, { 18, 18, 6, 6}}, + {m68k_op_sub_32_er_al , 0xf1ff, 0x90b9, { 22, 22, 6, 6}}, + {m68k_op_sub_32_er_pcdi , 0xf1ff, 0x90ba, { 18, 18, 7, 7}}, + {m68k_op_sub_32_er_pcix , 0xf1ff, 0x90bb, { 20, 20, 9, 9}}, + {m68k_op_sub_32_er_i , 0xf1ff, 0x90bc, { 16, 14, 6, 6}}, + {m68k_op_suba_16_aw , 0xf1ff, 0x90f8, { 16, 16, 6, 6}}, + {m68k_op_suba_16_al , 0xf1ff, 0x90f9, { 20, 20, 6, 6}}, + {m68k_op_suba_16_pcdi , 0xf1ff, 0x90fa, { 16, 16, 7, 7}}, + {m68k_op_suba_16_pcix , 0xf1ff, 0x90fb, { 18, 18, 9, 9}}, + {m68k_op_suba_16_i , 0xf1ff, 0x90fc, { 12, 12, 4, 4}}, + {m68k_op_subx_8_mm_ay7 , 0xf1ff, 0x910f, { 18, 18, 12, 12}}, + {m68k_op_sub_8_re_pi7 , 0xf1ff, 0x911f, { 12, 12, 8, 8}}, + {m68k_op_sub_8_re_pd7 , 0xf1ff, 0x9127, { 14, 14, 9, 9}}, + {m68k_op_sub_8_re_aw , 0xf1ff, 0x9138, { 16, 16, 8, 8}}, + {m68k_op_sub_8_re_al , 0xf1ff, 0x9139, { 20, 20, 8, 8}}, + {m68k_op_sub_16_re_aw , 0xf1ff, 0x9178, { 16, 16, 8, 8}}, + {m68k_op_sub_16_re_al , 0xf1ff, 0x9179, { 20, 20, 8, 8}}, + {m68k_op_sub_32_re_aw , 0xf1ff, 0x91b8, { 24, 24, 8, 8}}, + {m68k_op_sub_32_re_al , 0xf1ff, 0x91b9, { 28, 28, 8, 8}}, + {m68k_op_suba_32_aw , 0xf1ff, 0x91f8, { 18, 18, 6, 6}}, + {m68k_op_suba_32_al , 0xf1ff, 0x91f9, { 22, 22, 6, 6}}, + {m68k_op_suba_32_pcdi , 0xf1ff, 0x91fa, { 18, 18, 7, 7}}, + {m68k_op_suba_32_pcix , 0xf1ff, 0x91fb, { 20, 20, 9, 9}}, + {m68k_op_suba_32_i , 0xf1ff, 0x91fc, { 16, 14, 6, 6}}, + {m68k_op_cmp_8_pi7 , 0xf1ff, 0xb01f, { 8, 8, 6, 6}}, + {m68k_op_cmp_8_pd7 , 0xf1ff, 0xb027, { 10, 10, 7, 7}}, + {m68k_op_cmp_8_aw , 0xf1ff, 0xb038, { 12, 12, 6, 6}}, + {m68k_op_cmp_8_al , 0xf1ff, 0xb039, { 16, 16, 6, 6}}, + {m68k_op_cmp_8_pcdi , 0xf1ff, 0xb03a, { 12, 12, 7, 7}}, + {m68k_op_cmp_8_pcix , 0xf1ff, 0xb03b, { 14, 14, 9, 9}}, + {m68k_op_cmp_8_i , 0xf1ff, 0xb03c, { 8, 8, 4, 4}}, + {m68k_op_cmp_16_aw , 0xf1ff, 0xb078, { 12, 12, 6, 6}}, + {m68k_op_cmp_16_al , 0xf1ff, 0xb079, { 16, 16, 6, 6}}, + {m68k_op_cmp_16_pcdi , 0xf1ff, 0xb07a, { 12, 12, 7, 7}}, + {m68k_op_cmp_16_pcix , 0xf1ff, 0xb07b, { 14, 14, 9, 9}}, + {m68k_op_cmp_16_i , 0xf1ff, 0xb07c, { 8, 8, 4, 4}}, + {m68k_op_cmp_32_aw , 0xf1ff, 0xb0b8, { 18, 18, 6, 6}}, + {m68k_op_cmp_32_al , 0xf1ff, 0xb0b9, { 22, 22, 6, 6}}, + {m68k_op_cmp_32_pcdi , 0xf1ff, 0xb0ba, { 18, 18, 7, 7}}, + {m68k_op_cmp_32_pcix , 0xf1ff, 0xb0bb, { 20, 20, 9, 9}}, + {m68k_op_cmp_32_i , 0xf1ff, 0xb0bc, { 14, 14, 6, 6}}, + {m68k_op_cmpa_16_aw , 0xf1ff, 0xb0f8, { 14, 14, 8, 8}}, + {m68k_op_cmpa_16_al , 0xf1ff, 0xb0f9, { 18, 18, 8, 8}}, + {m68k_op_cmpa_16_pcdi , 0xf1ff, 0xb0fa, { 14, 14, 9, 9}}, + {m68k_op_cmpa_16_pcix , 0xf1ff, 0xb0fb, { 16, 16, 11, 11}}, + {m68k_op_cmpa_16_i , 0xf1ff, 0xb0fc, { 10, 10, 6, 6}}, + {m68k_op_cmpm_8_ay7 , 0xf1ff, 0xb10f, { 12, 12, 9, 9}}, + {m68k_op_eor_8_pi7 , 0xf1ff, 0xb11f, { 12, 12, 8, 8}}, + {m68k_op_eor_8_pd7 , 0xf1ff, 0xb127, { 14, 14, 9, 9}}, + {m68k_op_eor_8_aw , 0xf1ff, 0xb138, { 16, 16, 8, 8}}, + {m68k_op_eor_8_al , 0xf1ff, 0xb139, { 20, 20, 8, 8}}, + {m68k_op_eor_16_aw , 0xf1ff, 0xb178, { 16, 16, 8, 8}}, + {m68k_op_eor_16_al , 0xf1ff, 0xb179, { 20, 20, 8, 8}}, + {m68k_op_eor_32_aw , 0xf1ff, 0xb1b8, { 24, 24, 8, 8}}, + {m68k_op_eor_32_al , 0xf1ff, 0xb1b9, { 28, 28, 8, 8}}, + {m68k_op_cmpa_32_aw , 0xf1ff, 0xb1f8, { 18, 18, 8, 8}}, + {m68k_op_cmpa_32_al , 0xf1ff, 0xb1f9, { 22, 22, 8, 8}}, + {m68k_op_cmpa_32_pcdi , 0xf1ff, 0xb1fa, { 18, 18, 9, 9}}, + {m68k_op_cmpa_32_pcix , 0xf1ff, 0xb1fb, { 20, 20, 11, 11}}, + {m68k_op_cmpa_32_i , 0xf1ff, 0xb1fc, { 14, 14, 8, 8}}, + {m68k_op_and_8_er_pi7 , 0xf1ff, 0xc01f, { 8, 8, 6, 6}}, + {m68k_op_and_8_er_pd7 , 0xf1ff, 0xc027, { 10, 10, 7, 7}}, + {m68k_op_and_8_er_aw , 0xf1ff, 0xc038, { 12, 12, 6, 6}}, + {m68k_op_and_8_er_al , 0xf1ff, 0xc039, { 16, 16, 6, 6}}, + {m68k_op_and_8_er_pcdi , 0xf1ff, 0xc03a, { 12, 12, 7, 7}}, + {m68k_op_and_8_er_pcix , 0xf1ff, 0xc03b, { 14, 14, 9, 9}}, + {m68k_op_and_8_er_i , 0xf1ff, 0xc03c, { 8, 8, 4, 4}}, + {m68k_op_and_16_er_aw , 0xf1ff, 0xc078, { 12, 12, 6, 6}}, + {m68k_op_and_16_er_al , 0xf1ff, 0xc079, { 16, 16, 6, 6}}, + {m68k_op_and_16_er_pcdi , 0xf1ff, 0xc07a, { 12, 12, 7, 7}}, + {m68k_op_and_16_er_pcix , 0xf1ff, 0xc07b, { 14, 14, 9, 9}}, + {m68k_op_and_16_er_i , 0xf1ff, 0xc07c, { 8, 8, 4, 4}}, + {m68k_op_and_32_er_aw , 0xf1ff, 0xc0b8, { 18, 18, 6, 6}}, + {m68k_op_and_32_er_al , 0xf1ff, 0xc0b9, { 22, 22, 6, 6}}, + {m68k_op_and_32_er_pcdi , 0xf1ff, 0xc0ba, { 18, 18, 7, 7}}, + {m68k_op_and_32_er_pcix , 0xf1ff, 0xc0bb, { 20, 20, 9, 9}}, + {m68k_op_and_32_er_i , 0xf1ff, 0xc0bc, { 16, 14, 6, 6}}, + {m68k_op_mulu_16_aw , 0xf1ff, 0xc0f8, { 62, 38, 31, 31}}, + {m68k_op_mulu_16_al , 0xf1ff, 0xc0f9, { 66, 42, 31, 31}}, + {m68k_op_mulu_16_pcdi , 0xf1ff, 0xc0fa, { 62, 38, 32, 32}}, + {m68k_op_mulu_16_pcix , 0xf1ff, 0xc0fb, { 64, 40, 34, 34}}, + {m68k_op_mulu_16_i , 0xf1ff, 0xc0fc, { 58, 34, 29, 29}}, + {m68k_op_abcd_8_mm_ay7 , 0xf1ff, 0xc10f, { 18, 18, 16, 16}}, + {m68k_op_and_8_re_pi7 , 0xf1ff, 0xc11f, { 12, 12, 8, 8}}, + {m68k_op_and_8_re_pd7 , 0xf1ff, 0xc127, { 14, 14, 9, 9}}, + {m68k_op_and_8_re_aw , 0xf1ff, 0xc138, { 16, 16, 8, 8}}, + {m68k_op_and_8_re_al , 0xf1ff, 0xc139, { 20, 20, 8, 8}}, + {m68k_op_and_16_re_aw , 0xf1ff, 0xc178, { 16, 16, 8, 8}}, + {m68k_op_and_16_re_al , 0xf1ff, 0xc179, { 20, 20, 8, 8}}, + {m68k_op_and_32_re_aw , 0xf1ff, 0xc1b8, { 24, 24, 8, 8}}, + {m68k_op_and_32_re_al , 0xf1ff, 0xc1b9, { 28, 28, 8, 8}}, + {m68k_op_muls_16_aw , 0xf1ff, 0xc1f8, { 62, 40, 31, 31}}, + {m68k_op_muls_16_al , 0xf1ff, 0xc1f9, { 66, 44, 31, 31}}, + {m68k_op_muls_16_pcdi , 0xf1ff, 0xc1fa, { 62, 40, 32, 32}}, + {m68k_op_muls_16_pcix , 0xf1ff, 0xc1fb, { 64, 42, 34, 34}}, + {m68k_op_muls_16_i , 0xf1ff, 0xc1fc, { 58, 36, 29, 29}}, + {m68k_op_add_8_er_pi7 , 0xf1ff, 0xd01f, { 8, 8, 6, 6}}, + {m68k_op_add_8_er_pd7 , 0xf1ff, 0xd027, { 10, 10, 7, 7}}, + {m68k_op_add_8_er_aw , 0xf1ff, 0xd038, { 12, 12, 6, 6}}, + {m68k_op_add_8_er_al , 0xf1ff, 0xd039, { 16, 16, 6, 6}}, + {m68k_op_add_8_er_pcdi , 0xf1ff, 0xd03a, { 12, 12, 7, 7}}, + {m68k_op_add_8_er_pcix , 0xf1ff, 0xd03b, { 14, 14, 9, 9}}, + {m68k_op_add_8_er_i , 0xf1ff, 0xd03c, { 8, 8, 4, 4}}, + {m68k_op_add_16_er_aw , 0xf1ff, 0xd078, { 12, 12, 6, 6}}, + {m68k_op_add_16_er_al , 0xf1ff, 0xd079, { 16, 16, 6, 6}}, + {m68k_op_add_16_er_pcdi , 0xf1ff, 0xd07a, { 12, 12, 7, 7}}, + {m68k_op_add_16_er_pcix , 0xf1ff, 0xd07b, { 14, 14, 9, 9}}, + {m68k_op_add_16_er_i , 0xf1ff, 0xd07c, { 8, 8, 4, 4}}, + {m68k_op_add_32_er_aw , 0xf1ff, 0xd0b8, { 18, 18, 6, 6}}, + {m68k_op_add_32_er_al , 0xf1ff, 0xd0b9, { 22, 22, 6, 6}}, + {m68k_op_add_32_er_pcdi , 0xf1ff, 0xd0ba, { 18, 18, 7, 7}}, + {m68k_op_add_32_er_pcix , 0xf1ff, 0xd0bb, { 20, 20, 9, 9}}, + {m68k_op_add_32_er_i , 0xf1ff, 0xd0bc, { 16, 14, 6, 6}}, + {m68k_op_adda_16_aw , 0xf1ff, 0xd0f8, { 16, 16, 6, 6}}, + {m68k_op_adda_16_al , 0xf1ff, 0xd0f9, { 20, 20, 6, 6}}, + {m68k_op_adda_16_pcdi , 0xf1ff, 0xd0fa, { 16, 16, 7, 7}}, + {m68k_op_adda_16_pcix , 0xf1ff, 0xd0fb, { 18, 18, 9, 9}}, + {m68k_op_adda_16_i , 0xf1ff, 0xd0fc, { 12, 12, 4, 4}}, + {m68k_op_addx_8_mm_ay7 , 0xf1ff, 0xd10f, { 18, 18, 12, 12}}, + {m68k_op_add_8_re_pi7 , 0xf1ff, 0xd11f, { 12, 12, 8, 8}}, + {m68k_op_add_8_re_pd7 , 0xf1ff, 0xd127, { 14, 14, 9, 9}}, + {m68k_op_add_8_re_aw , 0xf1ff, 0xd138, { 16, 16, 8, 8}}, + {m68k_op_add_8_re_al , 0xf1ff, 0xd139, { 20, 20, 8, 8}}, + {m68k_op_add_16_re_aw , 0xf1ff, 0xd178, { 16, 16, 8, 8}}, + {m68k_op_add_16_re_al , 0xf1ff, 0xd179, { 20, 20, 8, 8}}, + {m68k_op_add_32_re_aw , 0xf1ff, 0xd1b8, { 24, 24, 8, 8}}, + {m68k_op_add_32_re_al , 0xf1ff, 0xd1b9, { 28, 28, 8, 8}}, + {m68k_op_adda_32_aw , 0xf1ff, 0xd1f8, { 18, 18, 6, 6}}, + {m68k_op_adda_32_al , 0xf1ff, 0xd1f9, { 22, 22, 6, 6}}, + {m68k_op_adda_32_pcdi , 0xf1ff, 0xd1fa, { 18, 18, 7, 7}}, + {m68k_op_adda_32_pcix , 0xf1ff, 0xd1fb, { 20, 20, 9, 9}}, + {m68k_op_adda_32_i , 0xf1ff, 0xd1fc, { 16, 14, 6, 6}}, + {m68k_op_ori_8_d , 0xfff8, 0x0000, { 8, 8, 2, 2}}, + {m68k_op_ori_8_ai , 0xfff8, 0x0010, { 16, 16, 8, 8}}, + {m68k_op_ori_8_pi , 0xfff8, 0x0018, { 16, 16, 8, 8}}, + {m68k_op_ori_8_pd , 0xfff8, 0x0020, { 18, 18, 9, 9}}, + {m68k_op_ori_8_di , 0xfff8, 0x0028, { 20, 20, 9, 9}}, + {m68k_op_ori_8_ix , 0xfff8, 0x0030, { 22, 22, 11, 11}}, + {m68k_op_ori_16_d , 0xfff8, 0x0040, { 8, 8, 2, 2}}, + {m68k_op_ori_16_ai , 0xfff8, 0x0050, { 16, 16, 8, 8}}, + {m68k_op_ori_16_pi , 0xfff8, 0x0058, { 16, 16, 8, 8}}, + {m68k_op_ori_16_pd , 0xfff8, 0x0060, { 18, 18, 9, 9}}, + {m68k_op_ori_16_di , 0xfff8, 0x0068, { 20, 20, 9, 9}}, + {m68k_op_ori_16_ix , 0xfff8, 0x0070, { 22, 22, 11, 11}}, + {m68k_op_ori_32_d , 0xfff8, 0x0080, { 16, 14, 2, 2}}, + {m68k_op_ori_32_ai , 0xfff8, 0x0090, { 28, 28, 8, 8}}, + {m68k_op_ori_32_pi , 0xfff8, 0x0098, { 28, 28, 8, 8}}, + {m68k_op_ori_32_pd , 0xfff8, 0x00a0, { 30, 30, 9, 9}}, + {m68k_op_ori_32_di , 0xfff8, 0x00a8, { 32, 32, 9, 9}}, + {m68k_op_ori_32_ix , 0xfff8, 0x00b0, { 34, 34, 11, 11}}, + {m68k_op_chk2cmp2_8_ai , 0xfff8, 0x00d0, { 0, 0, 22, 22}}, + {m68k_op_chk2cmp2_8_di , 0xfff8, 0x00e8, { 0, 0, 23, 23}}, + {m68k_op_chk2cmp2_8_ix , 0xfff8, 0x00f0, { 0, 0, 25, 25}}, + {m68k_op_andi_8_d , 0xfff8, 0x0200, { 8, 8, 2, 2}}, + {m68k_op_andi_8_ai , 0xfff8, 0x0210, { 16, 16, 8, 8}}, + {m68k_op_andi_8_pi , 0xfff8, 0x0218, { 16, 16, 8, 8}}, + {m68k_op_andi_8_pd , 0xfff8, 0x0220, { 18, 18, 9, 9}}, + {m68k_op_andi_8_di , 0xfff8, 0x0228, { 20, 20, 9, 9}}, + {m68k_op_andi_8_ix , 0xfff8, 0x0230, { 22, 22, 11, 11}}, + {m68k_op_andi_16_d , 0xfff8, 0x0240, { 8, 8, 2, 2}}, + {m68k_op_andi_16_ai , 0xfff8, 0x0250, { 16, 16, 8, 8}}, + {m68k_op_andi_16_pi , 0xfff8, 0x0258, { 16, 16, 8, 8}}, + {m68k_op_andi_16_pd , 0xfff8, 0x0260, { 18, 18, 9, 9}}, + {m68k_op_andi_16_di , 0xfff8, 0x0268, { 20, 20, 9, 9}}, + {m68k_op_andi_16_ix , 0xfff8, 0x0270, { 22, 22, 11, 11}}, + {m68k_op_andi_32_d , 0xfff8, 0x0280, { 14, 14, 2, 2}}, + {m68k_op_andi_32_ai , 0xfff8, 0x0290, { 28, 28, 8, 8}}, + {m68k_op_andi_32_pi , 0xfff8, 0x0298, { 28, 28, 8, 8}}, + {m68k_op_andi_32_pd , 0xfff8, 0x02a0, { 30, 30, 9, 9}}, + {m68k_op_andi_32_di , 0xfff8, 0x02a8, { 32, 32, 9, 9}}, + {m68k_op_andi_32_ix , 0xfff8, 0x02b0, { 34, 34, 11, 11}}, + {m68k_op_chk2cmp2_16_ai , 0xfff8, 0x02d0, { 0, 0, 22, 22}}, + {m68k_op_chk2cmp2_16_di , 0xfff8, 0x02e8, { 0, 0, 23, 23}}, + {m68k_op_chk2cmp2_16_ix , 0xfff8, 0x02f0, { 0, 0, 25, 25}}, + {m68k_op_subi_8_d , 0xfff8, 0x0400, { 8, 8, 2, 2}}, + {m68k_op_subi_8_ai , 0xfff8, 0x0410, { 16, 16, 8, 8}}, + {m68k_op_subi_8_pi , 0xfff8, 0x0418, { 16, 16, 8, 8}}, + {m68k_op_subi_8_pd , 0xfff8, 0x0420, { 18, 18, 9, 9}}, + {m68k_op_subi_8_di , 0xfff8, 0x0428, { 20, 20, 9, 9}}, + {m68k_op_subi_8_ix , 0xfff8, 0x0430, { 22, 22, 11, 11}}, + {m68k_op_subi_16_d , 0xfff8, 0x0440, { 8, 8, 2, 2}}, + {m68k_op_subi_16_ai , 0xfff8, 0x0450, { 16, 16, 8, 8}}, + {m68k_op_subi_16_pi , 0xfff8, 0x0458, { 16, 16, 8, 8}}, + {m68k_op_subi_16_pd , 0xfff8, 0x0460, { 18, 18, 9, 9}}, + {m68k_op_subi_16_di , 0xfff8, 0x0468, { 20, 20, 9, 9}}, + {m68k_op_subi_16_ix , 0xfff8, 0x0470, { 22, 22, 11, 11}}, + {m68k_op_subi_32_d , 0xfff8, 0x0480, { 16, 14, 2, 2}}, + {m68k_op_subi_32_ai , 0xfff8, 0x0490, { 28, 28, 8, 8}}, + {m68k_op_subi_32_pi , 0xfff8, 0x0498, { 28, 28, 8, 8}}, + {m68k_op_subi_32_pd , 0xfff8, 0x04a0, { 30, 30, 9, 9}}, + {m68k_op_subi_32_di , 0xfff8, 0x04a8, { 32, 32, 9, 9}}, + {m68k_op_subi_32_ix , 0xfff8, 0x04b0, { 34, 34, 11, 11}}, + {m68k_op_chk2cmp2_32_ai , 0xfff8, 0x04d0, { 0, 0, 22, 22}}, + {m68k_op_chk2cmp2_32_di , 0xfff8, 0x04e8, { 0, 0, 23, 23}}, + {m68k_op_chk2cmp2_32_ix , 0xfff8, 0x04f0, { 0, 0, 25, 25}}, + {m68k_op_addi_8_d , 0xfff8, 0x0600, { 8, 8, 2, 2}}, + {m68k_op_addi_8_ai , 0xfff8, 0x0610, { 16, 16, 8, 8}}, + {m68k_op_addi_8_pi , 0xfff8, 0x0618, { 16, 16, 8, 8}}, + {m68k_op_addi_8_pd , 0xfff8, 0x0620, { 18, 18, 9, 9}}, + {m68k_op_addi_8_di , 0xfff8, 0x0628, { 20, 20, 9, 9}}, + {m68k_op_addi_8_ix , 0xfff8, 0x0630, { 22, 22, 11, 11}}, + {m68k_op_addi_16_d , 0xfff8, 0x0640, { 8, 8, 2, 2}}, + {m68k_op_addi_16_ai , 0xfff8, 0x0650, { 16, 16, 8, 8}}, + {m68k_op_addi_16_pi , 0xfff8, 0x0658, { 16, 16, 8, 8}}, + {m68k_op_addi_16_pd , 0xfff8, 0x0660, { 18, 18, 9, 9}}, + {m68k_op_addi_16_di , 0xfff8, 0x0668, { 20, 20, 9, 9}}, + {m68k_op_addi_16_ix , 0xfff8, 0x0670, { 22, 22, 11, 11}}, + {m68k_op_addi_32_d , 0xfff8, 0x0680, { 16, 14, 2, 2}}, + {m68k_op_addi_32_ai , 0xfff8, 0x0690, { 28, 28, 8, 8}}, + {m68k_op_addi_32_pi , 0xfff8, 0x0698, { 28, 28, 8, 8}}, + {m68k_op_addi_32_pd , 0xfff8, 0x06a0, { 30, 30, 9, 9}}, + {m68k_op_addi_32_di , 0xfff8, 0x06a8, { 32, 32, 9, 9}}, + {m68k_op_addi_32_ix , 0xfff8, 0x06b0, { 34, 34, 11, 11}}, + {m68k_op_callm_32_ai , 0xfff8, 0x06d0, { 0, 0, 64, 64}}, + {m68k_op_callm_32_di , 0xfff8, 0x06e8, { 0, 0, 65, 65}}, + {m68k_op_callm_32_ix , 0xfff8, 0x06f0, { 0, 0, 67, 67}}, + {m68k_op_btst_32_s_d , 0xfff8, 0x0800, { 10, 10, 4, 4}}, + {m68k_op_btst_8_s_ai , 0xfff8, 0x0810, { 12, 12, 8, 8}}, + {m68k_op_btst_8_s_pi , 0xfff8, 0x0818, { 12, 12, 8, 8}}, + {m68k_op_btst_8_s_pd , 0xfff8, 0x0820, { 14, 14, 9, 9}}, + {m68k_op_btst_8_s_di , 0xfff8, 0x0828, { 16, 16, 9, 9}}, + {m68k_op_btst_8_s_ix , 0xfff8, 0x0830, { 18, 18, 11, 11}}, + {m68k_op_bchg_32_s_d , 0xfff8, 0x0840, { 12, 12, 4, 4}}, + {m68k_op_bchg_8_s_ai , 0xfff8, 0x0850, { 16, 16, 8, 8}}, + {m68k_op_bchg_8_s_pi , 0xfff8, 0x0858, { 16, 16, 8, 8}}, + {m68k_op_bchg_8_s_pd , 0xfff8, 0x0860, { 18, 18, 9, 9}}, + {m68k_op_bchg_8_s_di , 0xfff8, 0x0868, { 20, 20, 9, 9}}, + {m68k_op_bchg_8_s_ix , 0xfff8, 0x0870, { 22, 22, 11, 11}}, + {m68k_op_bclr_32_s_d , 0xfff8, 0x0880, { 14, 14, 4, 4}}, + {m68k_op_bclr_8_s_ai , 0xfff8, 0x0890, { 16, 16, 8, 8}}, + {m68k_op_bclr_8_s_pi , 0xfff8, 0x0898, { 16, 16, 8, 8}}, + {m68k_op_bclr_8_s_pd , 0xfff8, 0x08a0, { 18, 18, 9, 9}}, + {m68k_op_bclr_8_s_di , 0xfff8, 0x08a8, { 20, 20, 9, 9}}, + {m68k_op_bclr_8_s_ix , 0xfff8, 0x08b0, { 22, 22, 11, 11}}, + {m68k_op_bset_32_s_d , 0xfff8, 0x08c0, { 12, 12, 4, 4}}, + {m68k_op_bset_8_s_ai , 0xfff8, 0x08d0, { 16, 16, 8, 8}}, + {m68k_op_bset_8_s_pi , 0xfff8, 0x08d8, { 16, 16, 8, 8}}, + {m68k_op_bset_8_s_pd , 0xfff8, 0x08e0, { 18, 18, 9, 9}}, + {m68k_op_bset_8_s_di , 0xfff8, 0x08e8, { 20, 20, 9, 9}}, + {m68k_op_bset_8_s_ix , 0xfff8, 0x08f0, { 22, 22, 11, 11}}, + {m68k_op_eori_8_d , 0xfff8, 0x0a00, { 8, 8, 2, 2}}, + {m68k_op_eori_8_ai , 0xfff8, 0x0a10, { 16, 16, 8, 8}}, + {m68k_op_eori_8_pi , 0xfff8, 0x0a18, { 16, 16, 8, 8}}, + {m68k_op_eori_8_pd , 0xfff8, 0x0a20, { 18, 18, 9, 9}}, + {m68k_op_eori_8_di , 0xfff8, 0x0a28, { 20, 20, 9, 9}}, + {m68k_op_eori_8_ix , 0xfff8, 0x0a30, { 22, 22, 11, 11}}, + {m68k_op_eori_16_d , 0xfff8, 0x0a40, { 8, 8, 2, 2}}, + {m68k_op_eori_16_ai , 0xfff8, 0x0a50, { 16, 16, 8, 8}}, + {m68k_op_eori_16_pi , 0xfff8, 0x0a58, { 16, 16, 8, 8}}, + {m68k_op_eori_16_pd , 0xfff8, 0x0a60, { 18, 18, 9, 9}}, + {m68k_op_eori_16_di , 0xfff8, 0x0a68, { 20, 20, 9, 9}}, + {m68k_op_eori_16_ix , 0xfff8, 0x0a70, { 22, 22, 11, 11}}, + {m68k_op_eori_32_d , 0xfff8, 0x0a80, { 16, 14, 2, 2}}, + {m68k_op_eori_32_ai , 0xfff8, 0x0a90, { 28, 28, 8, 8}}, + {m68k_op_eori_32_pi , 0xfff8, 0x0a98, { 28, 28, 8, 8}}, + {m68k_op_eori_32_pd , 0xfff8, 0x0aa0, { 30, 30, 9, 9}}, + {m68k_op_eori_32_di , 0xfff8, 0x0aa8, { 32, 32, 9, 9}}, + {m68k_op_eori_32_ix , 0xfff8, 0x0ab0, { 34, 34, 11, 11}}, + {m68k_op_cas_8_ai , 0xfff8, 0x0ad0, { 0, 0, 16, 16}}, + {m68k_op_cas_8_pi , 0xfff8, 0x0ad8, { 0, 0, 16, 16}}, + {m68k_op_cas_8_pd , 0xfff8, 0x0ae0, { 0, 0, 17, 17}}, + {m68k_op_cas_8_di , 0xfff8, 0x0ae8, { 0, 0, 17, 17}}, + {m68k_op_cas_8_ix , 0xfff8, 0x0af0, { 0, 0, 19, 19}}, + {m68k_op_cmpi_8_d , 0xfff8, 0x0c00, { 8, 8, 2, 2}}, + {m68k_op_cmpi_8_ai , 0xfff8, 0x0c10, { 12, 12, 6, 6}}, + {m68k_op_cmpi_8_pi , 0xfff8, 0x0c18, { 12, 12, 6, 6}}, + {m68k_op_cmpi_8_pd , 0xfff8, 0x0c20, { 14, 14, 7, 7}}, + {m68k_op_cmpi_8_di , 0xfff8, 0x0c28, { 16, 16, 7, 7}}, + {m68k_op_cmpi_8_ix , 0xfff8, 0x0c30, { 18, 18, 9, 9}}, + {m68k_op_cmpi_16_d , 0xfff8, 0x0c40, { 8, 8, 2, 2}}, + {m68k_op_cmpi_16_ai , 0xfff8, 0x0c50, { 12, 12, 6, 6}}, + {m68k_op_cmpi_16_pi , 0xfff8, 0x0c58, { 12, 12, 6, 6}}, + {m68k_op_cmpi_16_pd , 0xfff8, 0x0c60, { 14, 14, 7, 7}}, + {m68k_op_cmpi_16_di , 0xfff8, 0x0c68, { 16, 16, 7, 7}}, + {m68k_op_cmpi_16_ix , 0xfff8, 0x0c70, { 18, 18, 9, 9}}, + {m68k_op_cmpi_32_d , 0xfff8, 0x0c80, { 14, 12, 2, 2}}, + {m68k_op_cmpi_32_ai , 0xfff8, 0x0c90, { 20, 20, 6, 6}}, + {m68k_op_cmpi_32_pi , 0xfff8, 0x0c98, { 20, 20, 6, 6}}, + {m68k_op_cmpi_32_pd , 0xfff8, 0x0ca0, { 22, 22, 7, 7}}, + {m68k_op_cmpi_32_di , 0xfff8, 0x0ca8, { 24, 24, 7, 7}}, + {m68k_op_cmpi_32_ix , 0xfff8, 0x0cb0, { 26, 26, 9, 9}}, + {m68k_op_cas_16_ai , 0xfff8, 0x0cd0, { 0, 0, 16, 16}}, + {m68k_op_cas_16_pi , 0xfff8, 0x0cd8, { 0, 0, 16, 16}}, + {m68k_op_cas_16_pd , 0xfff8, 0x0ce0, { 0, 0, 17, 17}}, + {m68k_op_cas_16_di , 0xfff8, 0x0ce8, { 0, 0, 17, 17}}, + {m68k_op_cas_16_ix , 0xfff8, 0x0cf0, { 0, 0, 19, 19}}, + {m68k_op_moves_8_ai , 0xfff8, 0x0e10, { 0, 18, 9, 9}}, + {m68k_op_moves_8_pi , 0xfff8, 0x0e18, { 0, 18, 9, 9}}, + {m68k_op_moves_8_pd , 0xfff8, 0x0e20, { 0, 20, 10, 10}}, + {m68k_op_moves_8_di , 0xfff8, 0x0e28, { 0, 26, 10, 10}}, + {m68k_op_moves_8_ix , 0xfff8, 0x0e30, { 0, 30, 12, 12}}, + {m68k_op_moves_16_ai , 0xfff8, 0x0e50, { 0, 18, 9, 9}}, + {m68k_op_moves_16_pi , 0xfff8, 0x0e58, { 0, 18, 9, 9}}, + {m68k_op_moves_16_pd , 0xfff8, 0x0e60, { 0, 20, 10, 10}}, + {m68k_op_moves_16_di , 0xfff8, 0x0e68, { 0, 26, 10, 10}}, + {m68k_op_moves_16_ix , 0xfff8, 0x0e70, { 0, 30, 12, 12}}, + {m68k_op_moves_32_ai , 0xfff8, 0x0e90, { 0, 22, 9, 9}}, + {m68k_op_moves_32_pi , 0xfff8, 0x0e98, { 0, 22, 9, 9}}, + {m68k_op_moves_32_pd , 0xfff8, 0x0ea0, { 0, 28, 10, 10}}, + {m68k_op_moves_32_di , 0xfff8, 0x0ea8, { 0, 32, 10, 10}}, + {m68k_op_moves_32_ix , 0xfff8, 0x0eb0, { 0, 36, 12, 12}}, + {m68k_op_cas_32_ai , 0xfff8, 0x0ed0, { 0, 0, 16, 16}}, + {m68k_op_cas_32_pi , 0xfff8, 0x0ed8, { 0, 0, 16, 16}}, + {m68k_op_cas_32_pd , 0xfff8, 0x0ee0, { 0, 0, 17, 17}}, + {m68k_op_cas_32_di , 0xfff8, 0x0ee8, { 0, 0, 17, 17}}, + {m68k_op_cas_32_ix , 0xfff8, 0x0ef0, { 0, 0, 19, 19}}, + {m68k_op_move_8_aw_d , 0xfff8, 0x11c0, { 12, 12, 4, 4}}, + {m68k_op_move_8_aw_ai , 0xfff8, 0x11d0, { 16, 16, 8, 8}}, + {m68k_op_move_8_aw_pi , 0xfff8, 0x11d8, { 16, 16, 8, 8}}, + {m68k_op_move_8_aw_pd , 0xfff8, 0x11e0, { 18, 18, 9, 9}}, + {m68k_op_move_8_aw_di , 0xfff8, 0x11e8, { 20, 20, 9, 9}}, + {m68k_op_move_8_aw_ix , 0xfff8, 0x11f0, { 22, 22, 11, 11}}, + {m68k_op_move_8_al_d , 0xfff8, 0x13c0, { 16, 16, 6, 6}}, + {m68k_op_move_8_al_ai , 0xfff8, 0x13d0, { 20, 20, 10, 10}}, + {m68k_op_move_8_al_pi , 0xfff8, 0x13d8, { 20, 20, 10, 10}}, + {m68k_op_move_8_al_pd , 0xfff8, 0x13e0, { 22, 22, 11, 11}}, + {m68k_op_move_8_al_di , 0xfff8, 0x13e8, { 24, 24, 11, 11}}, + {m68k_op_move_8_al_ix , 0xfff8, 0x13f0, { 26, 26, 13, 13}}, + {m68k_op_move_8_pi7_d , 0xfff8, 0x1ec0, { 8, 8, 4, 4}}, + {m68k_op_move_8_pi7_ai , 0xfff8, 0x1ed0, { 12, 12, 8, 8}}, + {m68k_op_move_8_pi7_pi , 0xfff8, 0x1ed8, { 12, 12, 8, 8}}, + {m68k_op_move_8_pi7_pd , 0xfff8, 0x1ee0, { 14, 14, 9, 9}}, + {m68k_op_move_8_pi7_di , 0xfff8, 0x1ee8, { 16, 16, 9, 9}}, + {m68k_op_move_8_pi7_ix , 0xfff8, 0x1ef0, { 18, 18, 11, 11}}, + {m68k_op_move_8_pd7_d , 0xfff8, 0x1f00, { 8, 8, 5, 5}}, + {m68k_op_move_8_pd7_ai , 0xfff8, 0x1f10, { 12, 12, 9, 9}}, + {m68k_op_move_8_pd7_pi , 0xfff8, 0x1f18, { 12, 12, 9, 9}}, + {m68k_op_move_8_pd7_pd , 0xfff8, 0x1f20, { 14, 14, 10, 10}}, + {m68k_op_move_8_pd7_di , 0xfff8, 0x1f28, { 16, 16, 10, 10}}, + {m68k_op_move_8_pd7_ix , 0xfff8, 0x1f30, { 18, 18, 12, 12}}, + {m68k_op_move_32_aw_d , 0xfff8, 0x21c0, { 16, 16, 4, 4}}, + {m68k_op_move_32_aw_a , 0xfff8, 0x21c8, { 16, 16, 4, 4}}, + {m68k_op_move_32_aw_ai , 0xfff8, 0x21d0, { 24, 24, 8, 8}}, + {m68k_op_move_32_aw_pi , 0xfff8, 0x21d8, { 24, 24, 8, 8}}, + {m68k_op_move_32_aw_pd , 0xfff8, 0x21e0, { 26, 26, 9, 9}}, + {m68k_op_move_32_aw_di , 0xfff8, 0x21e8, { 28, 28, 9, 9}}, + {m68k_op_move_32_aw_ix , 0xfff8, 0x21f0, { 30, 30, 11, 11}}, + {m68k_op_move_32_al_d , 0xfff8, 0x23c0, { 20, 20, 6, 6}}, + {m68k_op_move_32_al_a , 0xfff8, 0x23c8, { 20, 20, 6, 6}}, + {m68k_op_move_32_al_ai , 0xfff8, 0x23d0, { 28, 28, 10, 10}}, + {m68k_op_move_32_al_pi , 0xfff8, 0x23d8, { 28, 28, 10, 10}}, + {m68k_op_move_32_al_pd , 0xfff8, 0x23e0, { 30, 30, 11, 11}}, + {m68k_op_move_32_al_di , 0xfff8, 0x23e8, { 32, 32, 11, 11}}, + {m68k_op_move_32_al_ix , 0xfff8, 0x23f0, { 34, 34, 13, 13}}, + {m68k_op_move_16_aw_d , 0xfff8, 0x31c0, { 12, 12, 4, 4}}, + {m68k_op_move_16_aw_a , 0xfff8, 0x31c8, { 12, 12, 4, 4}}, + {m68k_op_move_16_aw_ai , 0xfff8, 0x31d0, { 16, 16, 8, 8}}, + {m68k_op_move_16_aw_pi , 0xfff8, 0x31d8, { 16, 16, 8, 8}}, + {m68k_op_move_16_aw_pd , 0xfff8, 0x31e0, { 18, 18, 9, 9}}, + {m68k_op_move_16_aw_di , 0xfff8, 0x31e8, { 20, 20, 9, 9}}, + {m68k_op_move_16_aw_ix , 0xfff8, 0x31f0, { 22, 22, 11, 11}}, + {m68k_op_move_16_al_d , 0xfff8, 0x33c0, { 16, 16, 6, 6}}, + {m68k_op_move_16_al_a , 0xfff8, 0x33c8, { 16, 16, 6, 6}}, + {m68k_op_move_16_al_ai , 0xfff8, 0x33d0, { 20, 20, 10, 10}}, + {m68k_op_move_16_al_pi , 0xfff8, 0x33d8, { 20, 20, 10, 10}}, + {m68k_op_move_16_al_pd , 0xfff8, 0x33e0, { 22, 22, 11, 11}}, + {m68k_op_move_16_al_di , 0xfff8, 0x33e8, { 24, 24, 11, 11}}, + {m68k_op_move_16_al_ix , 0xfff8, 0x33f0, { 26, 26, 13, 13}}, + {m68k_op_negx_8_d , 0xfff8, 0x4000, { 4, 4, 2, 2}}, + {m68k_op_negx_8_ai , 0xfff8, 0x4010, { 12, 12, 8, 8}}, + {m68k_op_negx_8_pi , 0xfff8, 0x4018, { 12, 12, 8, 8}}, + {m68k_op_negx_8_pd , 0xfff8, 0x4020, { 14, 14, 9, 9}}, + {m68k_op_negx_8_di , 0xfff8, 0x4028, { 16, 16, 9, 9}}, + {m68k_op_negx_8_ix , 0xfff8, 0x4030, { 18, 18, 11, 11}}, + {m68k_op_negx_16_d , 0xfff8, 0x4040, { 4, 4, 2, 2}}, + {m68k_op_negx_16_ai , 0xfff8, 0x4050, { 12, 12, 8, 8}}, + {m68k_op_negx_16_pi , 0xfff8, 0x4058, { 12, 12, 8, 8}}, + {m68k_op_negx_16_pd , 0xfff8, 0x4060, { 14, 14, 9, 9}}, + {m68k_op_negx_16_di , 0xfff8, 0x4068, { 16, 16, 9, 9}}, + {m68k_op_negx_16_ix , 0xfff8, 0x4070, { 18, 18, 11, 11}}, + {m68k_op_negx_32_d , 0xfff8, 0x4080, { 6, 6, 2, 2}}, + {m68k_op_negx_32_ai , 0xfff8, 0x4090, { 20, 20, 8, 8}}, + {m68k_op_negx_32_pi , 0xfff8, 0x4098, { 20, 20, 8, 8}}, + {m68k_op_negx_32_pd , 0xfff8, 0x40a0, { 22, 22, 9, 9}}, + {m68k_op_negx_32_di , 0xfff8, 0x40a8, { 24, 24, 9, 9}}, + {m68k_op_negx_32_ix , 0xfff8, 0x40b0, { 26, 26, 11, 11}}, + {m68k_op_move_16_frs_d , 0xfff8, 0x40c0, { 6, 4, 8, 8}}, + {m68k_op_move_16_frs_ai , 0xfff8, 0x40d0, { 12, 12, 12, 12}}, + {m68k_op_move_16_frs_pi , 0xfff8, 0x40d8, { 12, 12, 12, 12}}, + {m68k_op_move_16_frs_pd , 0xfff8, 0x40e0, { 14, 14, 13, 13}}, + {m68k_op_move_16_frs_di , 0xfff8, 0x40e8, { 16, 16, 13, 13}}, + {m68k_op_move_16_frs_ix , 0xfff8, 0x40f0, { 18, 18, 15, 15}}, + {m68k_op_clr_8_d , 0xfff8, 0x4200, { 4, 4, 2, 2}}, + {m68k_op_clr_8_ai , 0xfff8, 0x4210, { 10, 8, 8, 8}}, + {m68k_op_clr_8_pi , 0xfff8, 0x4218, { 10, 8, 8, 8}}, + {m68k_op_clr_8_pd , 0xfff8, 0x4220, { 12, 10, 9, 9}}, + {m68k_op_clr_8_di , 0xfff8, 0x4228, { 14, 12, 9, 9}}, + {m68k_op_clr_8_ix , 0xfff8, 0x4230, { 16, 14, 11, 11}}, + {m68k_op_clr_16_d , 0xfff8, 0x4240, { 4, 4, 2, 2}}, + {m68k_op_clr_16_ai , 0xfff8, 0x4250, { 10, 8, 8, 8}}, + {m68k_op_clr_16_pi , 0xfff8, 0x4258, { 10, 8, 8, 8}}, + {m68k_op_clr_16_pd , 0xfff8, 0x4260, { 12, 10, 9, 9}}, + {m68k_op_clr_16_di , 0xfff8, 0x4268, { 14, 12, 9, 9}}, + {m68k_op_clr_16_ix , 0xfff8, 0x4270, { 16, 14, 11, 11}}, + {m68k_op_clr_32_d , 0xfff8, 0x4280, { 6, 6, 2, 2}}, + {m68k_op_clr_32_ai , 0xfff8, 0x4290, { 20, 12, 8, 8}}, + {m68k_op_clr_32_pi , 0xfff8, 0x4298, { 20, 12, 8, 8}}, + {m68k_op_clr_32_pd , 0xfff8, 0x42a0, { 22, 14, 9, 9}}, + {m68k_op_clr_32_di , 0xfff8, 0x42a8, { 24, 16, 9, 9}}, + {m68k_op_clr_32_ix , 0xfff8, 0x42b0, { 26, 20, 11, 11}}, + {m68k_op_move_16_frc_d , 0xfff8, 0x42c0, { 0, 4, 4, 4}}, + {m68k_op_move_16_frc_ai , 0xfff8, 0x42d0, { 0, 12, 8, 8}}, + {m68k_op_move_16_frc_pi , 0xfff8, 0x42d8, { 0, 12, 8, 8}}, + {m68k_op_move_16_frc_pd , 0xfff8, 0x42e0, { 0, 14, 9, 9}}, + {m68k_op_move_16_frc_di , 0xfff8, 0x42e8, { 0, 16, 9, 9}}, + {m68k_op_move_16_frc_ix , 0xfff8, 0x42f0, { 0, 18, 11, 11}}, + {m68k_op_neg_8_d , 0xfff8, 0x4400, { 4, 4, 2, 2}}, + {m68k_op_neg_8_ai , 0xfff8, 0x4410, { 12, 12, 8, 8}}, + {m68k_op_neg_8_pi , 0xfff8, 0x4418, { 12, 12, 8, 8}}, + {m68k_op_neg_8_pd , 0xfff8, 0x4420, { 14, 14, 9, 9}}, + {m68k_op_neg_8_di , 0xfff8, 0x4428, { 16, 16, 9, 9}}, + {m68k_op_neg_8_ix , 0xfff8, 0x4430, { 18, 18, 11, 11}}, + {m68k_op_neg_16_d , 0xfff8, 0x4440, { 4, 4, 2, 2}}, + {m68k_op_neg_16_ai , 0xfff8, 0x4450, { 12, 12, 8, 8}}, + {m68k_op_neg_16_pi , 0xfff8, 0x4458, { 12, 12, 8, 8}}, + {m68k_op_neg_16_pd , 0xfff8, 0x4460, { 14, 14, 9, 9}}, + {m68k_op_neg_16_di , 0xfff8, 0x4468, { 16, 16, 9, 9}}, + {m68k_op_neg_16_ix , 0xfff8, 0x4470, { 18, 18, 11, 11}}, + {m68k_op_neg_32_d , 0xfff8, 0x4480, { 6, 6, 2, 2}}, + {m68k_op_neg_32_ai , 0xfff8, 0x4490, { 20, 20, 8, 8}}, + {m68k_op_neg_32_pi , 0xfff8, 0x4498, { 20, 20, 8, 8}}, + {m68k_op_neg_32_pd , 0xfff8, 0x44a0, { 22, 22, 9, 9}}, + {m68k_op_neg_32_di , 0xfff8, 0x44a8, { 24, 24, 9, 9}}, + {m68k_op_neg_32_ix , 0xfff8, 0x44b0, { 26, 26, 11, 11}}, + {m68k_op_move_16_toc_d , 0xfff8, 0x44c0, { 12, 12, 4, 4}}, + {m68k_op_move_16_toc_ai , 0xfff8, 0x44d0, { 16, 16, 8, 8}}, + {m68k_op_move_16_toc_pi , 0xfff8, 0x44d8, { 16, 16, 8, 8}}, + {m68k_op_move_16_toc_pd , 0xfff8, 0x44e0, { 18, 18, 9, 9}}, + {m68k_op_move_16_toc_di , 0xfff8, 0x44e8, { 20, 20, 9, 9}}, + {m68k_op_move_16_toc_ix , 0xfff8, 0x44f0, { 22, 22, 11, 11}}, + {m68k_op_not_8_d , 0xfff8, 0x4600, { 4, 4, 2, 2}}, + {m68k_op_not_8_ai , 0xfff8, 0x4610, { 12, 12, 8, 8}}, + {m68k_op_not_8_pi , 0xfff8, 0x4618, { 12, 12, 8, 8}}, + {m68k_op_not_8_pd , 0xfff8, 0x4620, { 14, 14, 9, 9}}, + {m68k_op_not_8_di , 0xfff8, 0x4628, { 16, 16, 9, 9}}, + {m68k_op_not_8_ix , 0xfff8, 0x4630, { 18, 18, 11, 11}}, + {m68k_op_not_16_d , 0xfff8, 0x4640, { 4, 4, 2, 2}}, + {m68k_op_not_16_ai , 0xfff8, 0x4650, { 12, 12, 8, 8}}, + {m68k_op_not_16_pi , 0xfff8, 0x4658, { 12, 12, 8, 8}}, + {m68k_op_not_16_pd , 0xfff8, 0x4660, { 14, 14, 9, 9}}, + {m68k_op_not_16_di , 0xfff8, 0x4668, { 16, 16, 9, 9}}, + {m68k_op_not_16_ix , 0xfff8, 0x4670, { 18, 18, 11, 11}}, + {m68k_op_not_32_d , 0xfff8, 0x4680, { 6, 6, 2, 2}}, + {m68k_op_not_32_ai , 0xfff8, 0x4690, { 20, 20, 8, 8}}, + {m68k_op_not_32_pi , 0xfff8, 0x4698, { 20, 20, 8, 8}}, + {m68k_op_not_32_pd , 0xfff8, 0x46a0, { 22, 22, 9, 9}}, + {m68k_op_not_32_di , 0xfff8, 0x46a8, { 24, 24, 9, 9}}, + {m68k_op_not_32_ix , 0xfff8, 0x46b0, { 26, 26, 11, 11}}, + {m68k_op_move_16_tos_d , 0xfff8, 0x46c0, { 12, 12, 8, 8}}, + {m68k_op_move_16_tos_ai , 0xfff8, 0x46d0, { 16, 16, 12, 12}}, + {m68k_op_move_16_tos_pi , 0xfff8, 0x46d8, { 16, 16, 12, 12}}, + {m68k_op_move_16_tos_pd , 0xfff8, 0x46e0, { 18, 18, 13, 13}}, + {m68k_op_move_16_tos_di , 0xfff8, 0x46e8, { 20, 20, 13, 13}}, + {m68k_op_move_16_tos_ix , 0xfff8, 0x46f0, { 22, 22, 15, 15}}, + {m68k_op_nbcd_8_d , 0xfff8, 0x4800, { 6, 6, 6, 6}}, + {m68k_op_link_32 , 0xfff8, 0x4808, { 0, 0, 6, 6}}, + {m68k_op_nbcd_8_ai , 0xfff8, 0x4810, { 12, 12, 10, 10}}, + {m68k_op_nbcd_8_pi , 0xfff8, 0x4818, { 12, 12, 10, 10}}, + {m68k_op_nbcd_8_pd , 0xfff8, 0x4820, { 14, 14, 11, 11}}, + {m68k_op_nbcd_8_di , 0xfff8, 0x4828, { 16, 16, 11, 11}}, + {m68k_op_nbcd_8_ix , 0xfff8, 0x4830, { 18, 18, 13, 13}}, + {m68k_op_swap_32 , 0xfff8, 0x4840, { 4, 4, 4, 4}}, + {m68k_op_bkpt , 0xfff8, 0x4848, { 0, 10, 10, 10}}, + {m68k_op_pea_32_ai , 0xfff8, 0x4850, { 12, 12, 9, 9}}, + {m68k_op_pea_32_di , 0xfff8, 0x4868, { 16, 16, 10, 10}}, + {m68k_op_pea_32_ix , 0xfff8, 0x4870, { 20, 20, 12, 12}}, + {m68k_op_ext_16 , 0xfff8, 0x4880, { 4, 4, 4, 4}}, + {m68k_op_movem_16_re_ai , 0xfff8, 0x4890, { 8, 8, 8, 8}}, + {m68k_op_movem_16_re_pd , 0xfff8, 0x48a0, { 8, 8, 4, 4}}, + {m68k_op_movem_16_re_di , 0xfff8, 0x48a8, { 12, 12, 9, 9}}, + {m68k_op_movem_16_re_ix , 0xfff8, 0x48b0, { 14, 14, 11, 11}}, + {m68k_op_ext_32 , 0xfff8, 0x48c0, { 4, 4, 4, 4}}, + {m68k_op_movem_32_re_ai , 0xfff8, 0x48d0, { 8, 8, 8, 8}}, + {m68k_op_movem_32_re_pd , 0xfff8, 0x48e0, { 8, 8, 4, 4}}, + {m68k_op_movem_32_re_di , 0xfff8, 0x48e8, { 12, 12, 9, 9}}, + {m68k_op_movem_32_re_ix , 0xfff8, 0x48f0, { 14, 14, 11, 11}}, + {m68k_op_extb_32 , 0xfff8, 0x49c0, { 0, 0, 4, 4}}, + {m68k_op_tst_8_d , 0xfff8, 0x4a00, { 4, 4, 2, 2}}, + {m68k_op_tst_8_ai , 0xfff8, 0x4a10, { 8, 8, 6, 6}}, + {m68k_op_tst_8_pi , 0xfff8, 0x4a18, { 8, 8, 6, 6}}, + {m68k_op_tst_8_pd , 0xfff8, 0x4a20, { 10, 10, 7, 7}}, + {m68k_op_tst_8_di , 0xfff8, 0x4a28, { 12, 12, 7, 7}}, + {m68k_op_tst_8_ix , 0xfff8, 0x4a30, { 14, 14, 9, 9}}, + {m68k_op_tst_16_d , 0xfff8, 0x4a40, { 4, 4, 2, 2}}, + {m68k_op_tst_16_a , 0xfff8, 0x4a48, { 0, 0, 2, 2}}, + {m68k_op_tst_16_ai , 0xfff8, 0x4a50, { 8, 8, 6, 6}}, + {m68k_op_tst_16_pi , 0xfff8, 0x4a58, { 8, 8, 6, 6}}, + {m68k_op_tst_16_pd , 0xfff8, 0x4a60, { 10, 10, 7, 7}}, + {m68k_op_tst_16_di , 0xfff8, 0x4a68, { 12, 12, 7, 7}}, + {m68k_op_tst_16_ix , 0xfff8, 0x4a70, { 14, 14, 9, 9}}, + {m68k_op_tst_32_d , 0xfff8, 0x4a80, { 4, 4, 2, 2}}, + {m68k_op_tst_32_a , 0xfff8, 0x4a88, { 0, 0, 2, 2}}, + {m68k_op_tst_32_ai , 0xfff8, 0x4a90, { 12, 12, 6, 6}}, + {m68k_op_tst_32_pi , 0xfff8, 0x4a98, { 12, 12, 6, 6}}, + {m68k_op_tst_32_pd , 0xfff8, 0x4aa0, { 14, 14, 7, 7}}, + {m68k_op_tst_32_di , 0xfff8, 0x4aa8, { 16, 16, 7, 7}}, + {m68k_op_tst_32_ix , 0xfff8, 0x4ab0, { 18, 18, 9, 9}}, + {m68k_op_tas_8_d , 0xfff8, 0x4ac0, { 4, 4, 4, 4}}, + {m68k_op_tas_8_ai , 0xfff8, 0x4ad0, { 18, 18, 16, 16}}, + {m68k_op_tas_8_pi , 0xfff8, 0x4ad8, { 18, 18, 16, 16}}, + {m68k_op_tas_8_pd , 0xfff8, 0x4ae0, { 20, 20, 17, 17}}, + {m68k_op_tas_8_di , 0xfff8, 0x4ae8, { 22, 22, 17, 17}}, + {m68k_op_tas_8_ix , 0xfff8, 0x4af0, { 24, 24, 19, 19}}, + {m68k_op_mull_32_d , 0xfff8, 0x4c00, { 0, 0, 43, 43}}, + {m68k_op_mull_32_ai , 0xfff8, 0x4c10, { 0, 0, 47, 47}}, + {m68k_op_mull_32_pi , 0xfff8, 0x4c18, { 0, 0, 47, 47}}, + {m68k_op_mull_32_pd , 0xfff8, 0x4c20, { 0, 0, 48, 48}}, + {m68k_op_mull_32_di , 0xfff8, 0x4c28, { 0, 0, 48, 48}}, + {m68k_op_mull_32_ix , 0xfff8, 0x4c30, { 0, 0, 50, 50}}, + {m68k_op_divl_32_d , 0xfff8, 0x4c40, { 0, 0, 84, 84}}, + {m68k_op_divl_32_ai , 0xfff8, 0x4c50, { 0, 0, 88, 88}}, + {m68k_op_divl_32_pi , 0xfff8, 0x4c58, { 0, 0, 88, 88}}, + {m68k_op_divl_32_pd , 0xfff8, 0x4c60, { 0, 0, 89, 89}}, + {m68k_op_divl_32_di , 0xfff8, 0x4c68, { 0, 0, 89, 89}}, + {m68k_op_divl_32_ix , 0xfff8, 0x4c70, { 0, 0, 91, 91}}, + {m68k_op_movem_16_er_ai , 0xfff8, 0x4c90, { 12, 12, 12, 12}}, + {m68k_op_movem_16_er_pi , 0xfff8, 0x4c98, { 12, 12, 8, 8}}, + {m68k_op_movem_16_er_di , 0xfff8, 0x4ca8, { 16, 16, 13, 13}}, + {m68k_op_movem_16_er_ix , 0xfff8, 0x4cb0, { 18, 18, 15, 15}}, + {m68k_op_movem_32_er_ai , 0xfff8, 0x4cd0, { 12, 12, 12, 12}}, + {m68k_op_movem_32_er_pi , 0xfff8, 0x4cd8, { 12, 12, 8, 8}}, + {m68k_op_movem_32_er_di , 0xfff8, 0x4ce8, { 16, 16, 13, 13}}, + {m68k_op_movem_32_er_ix , 0xfff8, 0x4cf0, { 18, 18, 15, 15}}, + {m68k_op_link_16 , 0xfff8, 0x4e50, { 16, 16, 5, 5}}, + {m68k_op_unlk_32 , 0xfff8, 0x4e58, { 12, 12, 6, 6}}, + {m68k_op_move_32_tou , 0xfff8, 0x4e60, { 4, 6, 2, 2}}, + {m68k_op_move_32_fru , 0xfff8, 0x4e68, { 4, 6, 2, 2}}, + {m68k_op_jsr_32_ai , 0xfff8, 0x4e90, { 16, 16, 4, 4}}, + {m68k_op_jsr_32_di , 0xfff8, 0x4ea8, { 18, 18, 5, 5}}, + {m68k_op_jsr_32_ix , 0xfff8, 0x4eb0, { 22, 22, 7, 7}}, + {m68k_op_jmp_32_ai , 0xfff8, 0x4ed0, { 8, 8, 4, 4}}, + {m68k_op_jmp_32_di , 0xfff8, 0x4ee8, { 10, 10, 5, 5}}, + {m68k_op_jmp_32_ix , 0xfff8, 0x4ef0, { 14, 14, 7, 7}}, + {m68k_op_st_8_d , 0xfff8, 0x50c0, { 6, 4, 4, 4}}, + {m68k_op_dbt_16 , 0xfff8, 0x50c8, { 12, 12, 6, 6}}, + {m68k_op_st_8_ai , 0xfff8, 0x50d0, { 12, 12, 10, 10}}, + {m68k_op_st_8_pi , 0xfff8, 0x50d8, { 12, 12, 10, 10}}, + {m68k_op_st_8_pd , 0xfff8, 0x50e0, { 14, 14, 11, 11}}, + {m68k_op_st_8_di , 0xfff8, 0x50e8, { 16, 16, 11, 11}}, + {m68k_op_st_8_ix , 0xfff8, 0x50f0, { 18, 18, 13, 13}}, + {m68k_op_sf_8_d , 0xfff8, 0x51c0, { 4, 4, 4, 4}}, + {m68k_op_dbf_16 , 0xfff8, 0x51c8, { 12, 12, 6, 6}}, + {m68k_op_sf_8_ai , 0xfff8, 0x51d0, { 12, 12, 10, 10}}, + {m68k_op_sf_8_pi , 0xfff8, 0x51d8, { 12, 12, 10, 10}}, + {m68k_op_sf_8_pd , 0xfff8, 0x51e0, { 14, 14, 11, 11}}, + {m68k_op_sf_8_di , 0xfff8, 0x51e8, { 16, 16, 11, 11}}, + {m68k_op_sf_8_ix , 0xfff8, 0x51f0, { 18, 18, 13, 13}}, + {m68k_op_shi_8_d , 0xfff8, 0x52c0, { 4, 4, 4, 4}}, + {m68k_op_dbhi_16 , 0xfff8, 0x52c8, { 12, 12, 6, 6}}, + {m68k_op_shi_8_ai , 0xfff8, 0x52d0, { 12, 12, 10, 10}}, + {m68k_op_shi_8_pi , 0xfff8, 0x52d8, { 12, 12, 10, 10}}, + {m68k_op_shi_8_pd , 0xfff8, 0x52e0, { 14, 14, 11, 11}}, + {m68k_op_shi_8_di , 0xfff8, 0x52e8, { 16, 16, 11, 11}}, + {m68k_op_shi_8_ix , 0xfff8, 0x52f0, { 18, 18, 13, 13}}, + {m68k_op_sls_8_d , 0xfff8, 0x53c0, { 4, 4, 4, 4}}, + {m68k_op_dbls_16 , 0xfff8, 0x53c8, { 12, 12, 6, 6}}, + {m68k_op_sls_8_ai , 0xfff8, 0x53d0, { 12, 12, 10, 10}}, + {m68k_op_sls_8_pi , 0xfff8, 0x53d8, { 12, 12, 10, 10}}, + {m68k_op_sls_8_pd , 0xfff8, 0x53e0, { 14, 14, 11, 11}}, + {m68k_op_sls_8_di , 0xfff8, 0x53e8, { 16, 16, 11, 11}}, + {m68k_op_sls_8_ix , 0xfff8, 0x53f0, { 18, 18, 13, 13}}, + {m68k_op_scc_8_d , 0xfff8, 0x54c0, { 4, 4, 4, 4}}, + {m68k_op_dbcc_16 , 0xfff8, 0x54c8, { 12, 12, 6, 6}}, + {m68k_op_scc_8_ai , 0xfff8, 0x54d0, { 12, 12, 10, 10}}, + {m68k_op_scc_8_pi , 0xfff8, 0x54d8, { 12, 12, 10, 10}}, + {m68k_op_scc_8_pd , 0xfff8, 0x54e0, { 14, 14, 11, 11}}, + {m68k_op_scc_8_di , 0xfff8, 0x54e8, { 16, 16, 11, 11}}, + {m68k_op_scc_8_ix , 0xfff8, 0x54f0, { 18, 18, 13, 13}}, + {m68k_op_scs_8_d , 0xfff8, 0x55c0, { 4, 4, 4, 4}}, + {m68k_op_dbcs_16 , 0xfff8, 0x55c8, { 12, 12, 6, 6}}, + {m68k_op_scs_8_ai , 0xfff8, 0x55d0, { 12, 12, 10, 10}}, + {m68k_op_scs_8_pi , 0xfff8, 0x55d8, { 12, 12, 10, 10}}, + {m68k_op_scs_8_pd , 0xfff8, 0x55e0, { 14, 14, 11, 11}}, + {m68k_op_scs_8_di , 0xfff8, 0x55e8, { 16, 16, 11, 11}}, + {m68k_op_scs_8_ix , 0xfff8, 0x55f0, { 18, 18, 13, 13}}, + {m68k_op_sne_8_d , 0xfff8, 0x56c0, { 4, 4, 4, 4}}, + {m68k_op_dbne_16 , 0xfff8, 0x56c8, { 12, 12, 6, 6}}, + {m68k_op_sne_8_ai , 0xfff8, 0x56d0, { 12, 12, 10, 10}}, + {m68k_op_sne_8_pi , 0xfff8, 0x56d8, { 12, 12, 10, 10}}, + {m68k_op_sne_8_pd , 0xfff8, 0x56e0, { 14, 14, 11, 11}}, + {m68k_op_sne_8_di , 0xfff8, 0x56e8, { 16, 16, 11, 11}}, + {m68k_op_sne_8_ix , 0xfff8, 0x56f0, { 18, 18, 13, 13}}, + {m68k_op_seq_8_d , 0xfff8, 0x57c0, { 4, 4, 4, 4}}, + {m68k_op_dbeq_16 , 0xfff8, 0x57c8, { 12, 12, 6, 6}}, + {m68k_op_seq_8_ai , 0xfff8, 0x57d0, { 12, 12, 10, 10}}, + {m68k_op_seq_8_pi , 0xfff8, 0x57d8, { 12, 12, 10, 10}}, + {m68k_op_seq_8_pd , 0xfff8, 0x57e0, { 14, 14, 11, 11}}, + {m68k_op_seq_8_di , 0xfff8, 0x57e8, { 16, 16, 11, 11}}, + {m68k_op_seq_8_ix , 0xfff8, 0x57f0, { 18, 18, 13, 13}}, + {m68k_op_svc_8_d , 0xfff8, 0x58c0, { 4, 4, 4, 4}}, + {m68k_op_dbvc_16 , 0xfff8, 0x58c8, { 12, 12, 6, 6}}, + {m68k_op_svc_8_ai , 0xfff8, 0x58d0, { 12, 12, 10, 10}}, + {m68k_op_svc_8_pi , 0xfff8, 0x58d8, { 12, 12, 10, 10}}, + {m68k_op_svc_8_pd , 0xfff8, 0x58e0, { 14, 14, 11, 11}}, + {m68k_op_svc_8_di , 0xfff8, 0x58e8, { 16, 16, 11, 11}}, + {m68k_op_svc_8_ix , 0xfff8, 0x58f0, { 18, 18, 13, 13}}, + {m68k_op_svs_8_d , 0xfff8, 0x59c0, { 4, 4, 4, 4}}, + {m68k_op_dbvs_16 , 0xfff8, 0x59c8, { 12, 12, 6, 6}}, + {m68k_op_svs_8_ai , 0xfff8, 0x59d0, { 12, 12, 10, 10}}, + {m68k_op_svs_8_pi , 0xfff8, 0x59d8, { 12, 12, 10, 10}}, + {m68k_op_svs_8_pd , 0xfff8, 0x59e0, { 14, 14, 11, 11}}, + {m68k_op_svs_8_di , 0xfff8, 0x59e8, { 16, 16, 11, 11}}, + {m68k_op_svs_8_ix , 0xfff8, 0x59f0, { 18, 18, 13, 13}}, + {m68k_op_spl_8_d , 0xfff8, 0x5ac0, { 4, 4, 4, 4}}, + {m68k_op_dbpl_16 , 0xfff8, 0x5ac8, { 12, 12, 6, 6}}, + {m68k_op_spl_8_ai , 0xfff8, 0x5ad0, { 12, 12, 10, 10}}, + {m68k_op_spl_8_pi , 0xfff8, 0x5ad8, { 12, 12, 10, 10}}, + {m68k_op_spl_8_pd , 0xfff8, 0x5ae0, { 14, 14, 11, 11}}, + {m68k_op_spl_8_di , 0xfff8, 0x5ae8, { 16, 16, 11, 11}}, + {m68k_op_spl_8_ix , 0xfff8, 0x5af0, { 18, 18, 13, 13}}, + {m68k_op_smi_8_d , 0xfff8, 0x5bc0, { 4, 4, 4, 4}}, + {m68k_op_dbmi_16 , 0xfff8, 0x5bc8, { 12, 12, 6, 6}}, + {m68k_op_smi_8_ai , 0xfff8, 0x5bd0, { 12, 12, 10, 10}}, + {m68k_op_smi_8_pi , 0xfff8, 0x5bd8, { 12, 12, 10, 10}}, + {m68k_op_smi_8_pd , 0xfff8, 0x5be0, { 14, 14, 11, 11}}, + {m68k_op_smi_8_di , 0xfff8, 0x5be8, { 16, 16, 11, 11}}, + {m68k_op_smi_8_ix , 0xfff8, 0x5bf0, { 18, 18, 13, 13}}, + {m68k_op_sge_8_d , 0xfff8, 0x5cc0, { 4, 4, 4, 4}}, + {m68k_op_dbge_16 , 0xfff8, 0x5cc8, { 12, 12, 6, 6}}, + {m68k_op_sge_8_ai , 0xfff8, 0x5cd0, { 12, 12, 10, 10}}, + {m68k_op_sge_8_pi , 0xfff8, 0x5cd8, { 12, 12, 10, 10}}, + {m68k_op_sge_8_pd , 0xfff8, 0x5ce0, { 14, 14, 11, 11}}, + {m68k_op_sge_8_di , 0xfff8, 0x5ce8, { 16, 16, 11, 11}}, + {m68k_op_sge_8_ix , 0xfff8, 0x5cf0, { 18, 18, 13, 13}}, + {m68k_op_slt_8_d , 0xfff8, 0x5dc0, { 4, 4, 4, 4}}, + {m68k_op_dblt_16 , 0xfff8, 0x5dc8, { 12, 12, 6, 6}}, + {m68k_op_slt_8_ai , 0xfff8, 0x5dd0, { 12, 12, 10, 10}}, + {m68k_op_slt_8_pi , 0xfff8, 0x5dd8, { 12, 12, 10, 10}}, + {m68k_op_slt_8_pd , 0xfff8, 0x5de0, { 14, 14, 11, 11}}, + {m68k_op_slt_8_di , 0xfff8, 0x5de8, { 16, 16, 11, 11}}, + {m68k_op_slt_8_ix , 0xfff8, 0x5df0, { 18, 18, 13, 13}}, + {m68k_op_sgt_8_d , 0xfff8, 0x5ec0, { 4, 4, 4, 4}}, + {m68k_op_dbgt_16 , 0xfff8, 0x5ec8, { 12, 12, 6, 6}}, + {m68k_op_sgt_8_ai , 0xfff8, 0x5ed0, { 12, 12, 10, 10}}, + {m68k_op_sgt_8_pi , 0xfff8, 0x5ed8, { 12, 12, 10, 10}}, + {m68k_op_sgt_8_pd , 0xfff8, 0x5ee0, { 14, 14, 11, 11}}, + {m68k_op_sgt_8_di , 0xfff8, 0x5ee8, { 16, 16, 11, 11}}, + {m68k_op_sgt_8_ix , 0xfff8, 0x5ef0, { 18, 18, 13, 13}}, + {m68k_op_sle_8_d , 0xfff8, 0x5fc0, { 4, 4, 4, 4}}, + {m68k_op_dble_16 , 0xfff8, 0x5fc8, { 12, 12, 6, 6}}, + {m68k_op_sle_8_ai , 0xfff8, 0x5fd0, { 12, 12, 10, 10}}, + {m68k_op_sle_8_pi , 0xfff8, 0x5fd8, { 12, 12, 10, 10}}, + {m68k_op_sle_8_pd , 0xfff8, 0x5fe0, { 14, 14, 11, 11}}, + {m68k_op_sle_8_di , 0xfff8, 0x5fe8, { 16, 16, 11, 11}}, + {m68k_op_sle_8_ix , 0xfff8, 0x5ff0, { 18, 18, 13, 13}}, + {m68k_op_sbcd_8_mm_ax7 , 0xfff8, 0x8f08, { 18, 18, 16, 16}}, + {m68k_op_pack_16_mm_ax7 , 0xfff8, 0x8f48, { 0, 0, 13, 13}}, + {m68k_op_unpk_16_mm_ax7 , 0xfff8, 0x8f88, { 0, 0, 13, 13}}, + {m68k_op_subx_8_mm_ax7 , 0xfff8, 0x9f08, { 18, 18, 12, 12}}, + {m68k_op_cmpm_8_ax7 , 0xfff8, 0xbf08, { 12, 12, 9, 9}}, + {m68k_op_abcd_8_mm_ax7 , 0xfff8, 0xcf08, { 18, 18, 16, 16}}, + {m68k_op_addx_8_mm_ax7 , 0xfff8, 0xdf08, { 18, 18, 12, 12}}, + {m68k_op_asr_16_ai , 0xfff8, 0xe0d0, { 12, 12, 9, 9}}, + {m68k_op_asr_16_pi , 0xfff8, 0xe0d8, { 12, 12, 9, 9}}, + {m68k_op_asr_16_pd , 0xfff8, 0xe0e0, { 14, 14, 10, 10}}, + {m68k_op_asr_16_di , 0xfff8, 0xe0e8, { 16, 16, 10, 10}}, + {m68k_op_asr_16_ix , 0xfff8, 0xe0f0, { 18, 18, 12, 12}}, + {m68k_op_asl_16_ai , 0xfff8, 0xe1d0, { 12, 12, 10, 10}}, + {m68k_op_asl_16_pi , 0xfff8, 0xe1d8, { 12, 12, 10, 10}}, + {m68k_op_asl_16_pd , 0xfff8, 0xe1e0, { 14, 14, 11, 11}}, + {m68k_op_asl_16_di , 0xfff8, 0xe1e8, { 16, 16, 11, 11}}, + {m68k_op_asl_16_ix , 0xfff8, 0xe1f0, { 18, 18, 13, 13}}, + {m68k_op_lsr_16_ai , 0xfff8, 0xe2d0, { 12, 12, 9, 9}}, + {m68k_op_lsr_16_pi , 0xfff8, 0xe2d8, { 12, 12, 9, 9}}, + {m68k_op_lsr_16_pd , 0xfff8, 0xe2e0, { 14, 14, 10, 10}}, + {m68k_op_lsr_16_di , 0xfff8, 0xe2e8, { 16, 16, 10, 10}}, + {m68k_op_lsr_16_ix , 0xfff8, 0xe2f0, { 18, 18, 12, 12}}, + {m68k_op_lsl_16_ai , 0xfff8, 0xe3d0, { 12, 12, 9, 9}}, + {m68k_op_lsl_16_pi , 0xfff8, 0xe3d8, { 12, 12, 9, 9}}, + {m68k_op_lsl_16_pd , 0xfff8, 0xe3e0, { 14, 14, 10, 10}}, + {m68k_op_lsl_16_di , 0xfff8, 0xe3e8, { 16, 16, 10, 10}}, + {m68k_op_lsl_16_ix , 0xfff8, 0xe3f0, { 18, 18, 12, 12}}, + {m68k_op_roxr_16_ai , 0xfff8, 0xe4d0, { 12, 12, 9, 9}}, + {m68k_op_roxr_16_pi , 0xfff8, 0xe4d8, { 12, 12, 9, 9}}, + {m68k_op_roxr_16_pd , 0xfff8, 0xe4e0, { 14, 14, 10, 10}}, + {m68k_op_roxr_16_di , 0xfff8, 0xe4e8, { 16, 16, 10, 10}}, + {m68k_op_roxr_16_ix , 0xfff8, 0xe4f0, { 18, 18, 12, 12}}, + {m68k_op_roxl_16_ai , 0xfff8, 0xe5d0, { 12, 12, 9, 9}}, + {m68k_op_roxl_16_pi , 0xfff8, 0xe5d8, { 12, 12, 9, 9}}, + {m68k_op_roxl_16_pd , 0xfff8, 0xe5e0, { 14, 14, 10, 10}}, + {m68k_op_roxl_16_di , 0xfff8, 0xe5e8, { 16, 16, 10, 10}}, + {m68k_op_roxl_16_ix , 0xfff8, 0xe5f0, { 18, 18, 12, 12}}, + {m68k_op_ror_16_ai , 0xfff8, 0xe6d0, { 12, 12, 11, 11}}, + {m68k_op_ror_16_pi , 0xfff8, 0xe6d8, { 12, 12, 11, 11}}, + {m68k_op_ror_16_pd , 0xfff8, 0xe6e0, { 14, 14, 12, 12}}, + {m68k_op_ror_16_di , 0xfff8, 0xe6e8, { 16, 16, 12, 12}}, + {m68k_op_ror_16_ix , 0xfff8, 0xe6f0, { 18, 18, 14, 14}}, + {m68k_op_rol_16_ai , 0xfff8, 0xe7d0, { 12, 12, 11, 11}}, + {m68k_op_rol_16_pi , 0xfff8, 0xe7d8, { 12, 12, 11, 11}}, + {m68k_op_rol_16_pd , 0xfff8, 0xe7e0, { 14, 14, 12, 12}}, + {m68k_op_rol_16_di , 0xfff8, 0xe7e8, { 16, 16, 12, 12}}, + {m68k_op_rol_16_ix , 0xfff8, 0xe7f0, { 18, 18, 14, 14}}, + {m68k_op_bftst_32_d , 0xfff8, 0xe8c0, { 0, 0, 6, 6}}, + {m68k_op_bftst_32_ai , 0xfff8, 0xe8d0, { 0, 0, 17, 17}}, + {m68k_op_bftst_32_di , 0xfff8, 0xe8e8, { 0, 0, 18, 18}}, + {m68k_op_bftst_32_ix , 0xfff8, 0xe8f0, { 0, 0, 20, 20}}, + {m68k_op_bfextu_32_d , 0xfff8, 0xe9c0, { 0, 0, 8, 8}}, + {m68k_op_bfextu_32_ai , 0xfff8, 0xe9d0, { 0, 0, 19, 19}}, + {m68k_op_bfextu_32_di , 0xfff8, 0xe9e8, { 0, 0, 20, 20}}, + {m68k_op_bfextu_32_ix , 0xfff8, 0xe9f0, { 0, 0, 22, 22}}, + {m68k_op_bfchg_32_d , 0xfff8, 0xeac0, { 0, 0, 12, 12}}, + {m68k_op_bfchg_32_ai , 0xfff8, 0xead0, { 0, 0, 24, 24}}, + {m68k_op_bfchg_32_di , 0xfff8, 0xeae8, { 0, 0, 25, 25}}, + {m68k_op_bfchg_32_ix , 0xfff8, 0xeaf0, { 0, 0, 27, 27}}, + {m68k_op_bfexts_32_d , 0xfff8, 0xebc0, { 0, 0, 8, 8}}, + {m68k_op_bfexts_32_ai , 0xfff8, 0xebd0, { 0, 0, 19, 19}}, + {m68k_op_bfexts_32_di , 0xfff8, 0xebe8, { 0, 0, 20, 20}}, + {m68k_op_bfexts_32_ix , 0xfff8, 0xebf0, { 0, 0, 22, 22}}, + {m68k_op_bfclr_32_d , 0xfff8, 0xecc0, { 0, 0, 12, 12}}, + {m68k_op_bfclr_32_ai , 0xfff8, 0xecd0, { 0, 0, 24, 24}}, + {m68k_op_bfclr_32_di , 0xfff8, 0xece8, { 0, 0, 25, 25}}, + {m68k_op_bfclr_32_ix , 0xfff8, 0xecf0, { 0, 0, 27, 27}}, + {m68k_op_bfffo_32_d , 0xfff8, 0xedc0, { 0, 0, 18, 18}}, + {m68k_op_bfffo_32_ai , 0xfff8, 0xedd0, { 0, 0, 32, 32}}, + {m68k_op_bfffo_32_di , 0xfff8, 0xede8, { 0, 0, 33, 33}}, + {m68k_op_bfffo_32_ix , 0xfff8, 0xedf0, { 0, 0, 35, 35}}, + {m68k_op_bfset_32_d , 0xfff8, 0xeec0, { 0, 0, 12, 12}}, + {m68k_op_bfset_32_ai , 0xfff8, 0xeed0, { 0, 0, 24, 24}}, + {m68k_op_bfset_32_di , 0xfff8, 0xeee8, { 0, 0, 25, 25}}, + {m68k_op_bfset_32_ix , 0xfff8, 0xeef0, { 0, 0, 27, 27}}, + {m68k_op_bfins_32_d , 0xfff8, 0xefc0, { 0, 0, 10, 10}}, + {m68k_op_bfins_32_ai , 0xfff8, 0xefd0, { 0, 0, 21, 21}}, + {m68k_op_bfins_32_di , 0xfff8, 0xefe8, { 0, 0, 22, 22}}, + {m68k_op_bfins_32_ix , 0xfff8, 0xeff0, { 0, 0, 24, 24}}, + {m68k_op_move16_32 , 0xfff8, 0xf620, { 0, 0, 0, 4}}, + {m68k_op_ori_8_pi7 , 0xffff, 0x001f, { 16, 16, 8, 8}}, + {m68k_op_ori_8_pd7 , 0xffff, 0x0027, { 18, 18, 9, 9}}, + {m68k_op_ori_8_aw , 0xffff, 0x0038, { 20, 20, 8, 8}}, + {m68k_op_ori_8_al , 0xffff, 0x0039, { 24, 24, 8, 8}}, + {m68k_op_ori_16_toc , 0xffff, 0x003c, { 20, 16, 12, 12}}, + {m68k_op_ori_16_aw , 0xffff, 0x0078, { 20, 20, 8, 8}}, + {m68k_op_ori_16_al , 0xffff, 0x0079, { 24, 24, 8, 8}}, + {m68k_op_ori_16_tos , 0xffff, 0x007c, { 20, 16, 12, 12}}, + {m68k_op_ori_32_aw , 0xffff, 0x00b8, { 32, 32, 8, 8}}, + {m68k_op_ori_32_al , 0xffff, 0x00b9, { 36, 36, 8, 8}}, + {m68k_op_chk2cmp2_8_aw , 0xffff, 0x00f8, { 0, 0, 22, 22}}, + {m68k_op_chk2cmp2_8_al , 0xffff, 0x00f9, { 0, 0, 22, 22}}, + {m68k_op_chk2cmp2_8_pcdi , 0xffff, 0x00fa, { 0, 0, 23, 23}}, + {m68k_op_chk2cmp2_8_pcix , 0xffff, 0x00fb, { 0, 0, 23, 23}}, + {m68k_op_andi_8_pi7 , 0xffff, 0x021f, { 16, 16, 8, 8}}, + {m68k_op_andi_8_pd7 , 0xffff, 0x0227, { 18, 18, 9, 9}}, + {m68k_op_andi_8_aw , 0xffff, 0x0238, { 20, 20, 8, 8}}, + {m68k_op_andi_8_al , 0xffff, 0x0239, { 24, 24, 8, 8}}, + {m68k_op_andi_16_toc , 0xffff, 0x023c, { 20, 16, 12, 12}}, + {m68k_op_andi_16_aw , 0xffff, 0x0278, { 20, 20, 8, 8}}, + {m68k_op_andi_16_al , 0xffff, 0x0279, { 24, 24, 8, 8}}, + {m68k_op_andi_16_tos , 0xffff, 0x027c, { 20, 16, 12, 12}}, + {m68k_op_andi_32_aw , 0xffff, 0x02b8, { 32, 32, 8, 8}}, + {m68k_op_andi_32_al , 0xffff, 0x02b9, { 36, 36, 8, 8}}, + {m68k_op_chk2cmp2_16_aw , 0xffff, 0x02f8, { 0, 0, 22, 22}}, + {m68k_op_chk2cmp2_16_al , 0xffff, 0x02f9, { 0, 0, 22, 22}}, + {m68k_op_chk2cmp2_16_pcdi , 0xffff, 0x02fa, { 0, 0, 23, 23}}, + {m68k_op_chk2cmp2_16_pcix , 0xffff, 0x02fb, { 0, 0, 23, 23}}, + {m68k_op_subi_8_pi7 , 0xffff, 0x041f, { 16, 16, 8, 8}}, + {m68k_op_subi_8_pd7 , 0xffff, 0x0427, { 18, 18, 9, 9}}, + {m68k_op_subi_8_aw , 0xffff, 0x0438, { 20, 20, 8, 8}}, + {m68k_op_subi_8_al , 0xffff, 0x0439, { 24, 24, 8, 8}}, + {m68k_op_subi_16_aw , 0xffff, 0x0478, { 20, 20, 8, 8}}, + {m68k_op_subi_16_al , 0xffff, 0x0479, { 24, 24, 8, 8}}, + {m68k_op_subi_32_aw , 0xffff, 0x04b8, { 32, 32, 8, 8}}, + {m68k_op_subi_32_al , 0xffff, 0x04b9, { 36, 36, 8, 8}}, + {m68k_op_chk2cmp2_32_aw , 0xffff, 0x04f8, { 0, 0, 22, 22}}, + {m68k_op_chk2cmp2_32_al , 0xffff, 0x04f9, { 0, 0, 22, 22}}, + {m68k_op_chk2cmp2_32_pcdi , 0xffff, 0x04fa, { 0, 0, 23, 23}}, + {m68k_op_chk2cmp2_32_pcix , 0xffff, 0x04fb, { 0, 0, 23, 23}}, + {m68k_op_addi_8_pi7 , 0xffff, 0x061f, { 16, 16, 8, 8}}, + {m68k_op_addi_8_pd7 , 0xffff, 0x0627, { 18, 18, 9, 9}}, + {m68k_op_addi_8_aw , 0xffff, 0x0638, { 20, 20, 8, 8}}, + {m68k_op_addi_8_al , 0xffff, 0x0639, { 24, 24, 8, 8}}, + {m68k_op_addi_16_aw , 0xffff, 0x0678, { 20, 20, 8, 8}}, + {m68k_op_addi_16_al , 0xffff, 0x0679, { 24, 24, 8, 8}}, + {m68k_op_addi_32_aw , 0xffff, 0x06b8, { 32, 32, 8, 8}}, + {m68k_op_addi_32_al , 0xffff, 0x06b9, { 36, 36, 8, 8}}, + {m68k_op_callm_32_aw , 0xffff, 0x06f8, { 0, 0, 64, 64}}, + {m68k_op_callm_32_al , 0xffff, 0x06f9, { 0, 0, 64, 64}}, + {m68k_op_callm_32_pcdi , 0xffff, 0x06fa, { 0, 0, 65, 65}}, + {m68k_op_callm_32_pcix , 0xffff, 0x06fb, { 0, 0, 67, 67}}, + {m68k_op_btst_8_s_pi7 , 0xffff, 0x081f, { 12, 12, 8, 8}}, + {m68k_op_btst_8_s_pd7 , 0xffff, 0x0827, { 14, 14, 9, 9}}, + {m68k_op_btst_8_s_aw , 0xffff, 0x0838, { 16, 16, 8, 8}}, + {m68k_op_btst_8_s_al , 0xffff, 0x0839, { 20, 20, 8, 8}}, + {m68k_op_btst_8_s_pcdi , 0xffff, 0x083a, { 16, 16, 9, 9}}, + {m68k_op_btst_8_s_pcix , 0xffff, 0x083b, { 18, 18, 11, 11}}, + {m68k_op_bchg_8_s_pi7 , 0xffff, 0x085f, { 16, 16, 8, 8}}, + {m68k_op_bchg_8_s_pd7 , 0xffff, 0x0867, { 18, 18, 9, 9}}, + {m68k_op_bchg_8_s_aw , 0xffff, 0x0878, { 20, 20, 8, 8}}, + {m68k_op_bchg_8_s_al , 0xffff, 0x0879, { 24, 24, 8, 8}}, + {m68k_op_bclr_8_s_pi7 , 0xffff, 0x089f, { 16, 16, 8, 8}}, + {m68k_op_bclr_8_s_pd7 , 0xffff, 0x08a7, { 18, 18, 9, 9}}, + {m68k_op_bclr_8_s_aw , 0xffff, 0x08b8, { 20, 20, 8, 8}}, + {m68k_op_bclr_8_s_al , 0xffff, 0x08b9, { 24, 24, 8, 8}}, + {m68k_op_bset_8_s_pi7 , 0xffff, 0x08df, { 16, 16, 8, 8}}, + {m68k_op_bset_8_s_pd7 , 0xffff, 0x08e7, { 18, 18, 9, 9}}, + {m68k_op_bset_8_s_aw , 0xffff, 0x08f8, { 20, 20, 8, 8}}, + {m68k_op_bset_8_s_al , 0xffff, 0x08f9, { 24, 24, 8, 8}}, + {m68k_op_eori_8_pi7 , 0xffff, 0x0a1f, { 16, 16, 8, 8}}, + {m68k_op_eori_8_pd7 , 0xffff, 0x0a27, { 18, 18, 9, 9}}, + {m68k_op_eori_8_aw , 0xffff, 0x0a38, { 20, 20, 8, 8}}, + {m68k_op_eori_8_al , 0xffff, 0x0a39, { 24, 24, 8, 8}}, + {m68k_op_eori_16_toc , 0xffff, 0x0a3c, { 20, 16, 12, 12}}, + {m68k_op_eori_16_aw , 0xffff, 0x0a78, { 20, 20, 8, 8}}, + {m68k_op_eori_16_al , 0xffff, 0x0a79, { 24, 24, 8, 8}}, + {m68k_op_eori_16_tos , 0xffff, 0x0a7c, { 20, 16, 12, 12}}, + {m68k_op_eori_32_aw , 0xffff, 0x0ab8, { 32, 32, 8, 8}}, + {m68k_op_eori_32_al , 0xffff, 0x0ab9, { 36, 36, 8, 8}}, + {m68k_op_cas_8_pi7 , 0xffff, 0x0adf, { 0, 0, 16, 16}}, + {m68k_op_cas_8_pd7 , 0xffff, 0x0ae7, { 0, 0, 17, 17}}, + {m68k_op_cas_8_aw , 0xffff, 0x0af8, { 0, 0, 16, 16}}, + {m68k_op_cas_8_al , 0xffff, 0x0af9, { 0, 0, 16, 16}}, + {m68k_op_cmpi_8_pi7 , 0xffff, 0x0c1f, { 12, 12, 6, 6}}, + {m68k_op_cmpi_8_pd7 , 0xffff, 0x0c27, { 14, 14, 7, 7}}, + {m68k_op_cmpi_8_aw , 0xffff, 0x0c38, { 16, 16, 6, 6}}, + {m68k_op_cmpi_8_al , 0xffff, 0x0c39, { 20, 20, 6, 6}}, + {m68k_op_cmpi_8_pcdi , 0xffff, 0x0c3a, { 0, 0, 7, 7}}, + {m68k_op_cmpi_8_pcix , 0xffff, 0x0c3b, { 0, 0, 9, 9}}, + {m68k_op_cmpi_16_aw , 0xffff, 0x0c78, { 16, 16, 6, 6}}, + {m68k_op_cmpi_16_al , 0xffff, 0x0c79, { 20, 20, 6, 6}}, + {m68k_op_cmpi_16_pcdi , 0xffff, 0x0c7a, { 0, 0, 7, 7}}, + {m68k_op_cmpi_16_pcix , 0xffff, 0x0c7b, { 0, 0, 9, 9}}, + {m68k_op_cmpi_32_aw , 0xffff, 0x0cb8, { 24, 24, 6, 6}}, + {m68k_op_cmpi_32_al , 0xffff, 0x0cb9, { 28, 28, 6, 6}}, + {m68k_op_cmpi_32_pcdi , 0xffff, 0x0cba, { 0, 0, 7, 7}}, + {m68k_op_cmpi_32_pcix , 0xffff, 0x0cbb, { 0, 0, 9, 9}}, + {m68k_op_cas_16_aw , 0xffff, 0x0cf8, { 0, 0, 16, 16}}, + {m68k_op_cas_16_al , 0xffff, 0x0cf9, { 0, 0, 16, 16}}, + {m68k_op_cas2_16 , 0xffff, 0x0cfc, { 0, 0, 12, 12}}, + {m68k_op_moves_8_pi7 , 0xffff, 0x0e1f, { 0, 18, 9, 9}}, + {m68k_op_moves_8_pd7 , 0xffff, 0x0e27, { 0, 20, 10, 10}}, + {m68k_op_moves_8_aw , 0xffff, 0x0e38, { 0, 26, 9, 9}}, + {m68k_op_moves_8_al , 0xffff, 0x0e39, { 0, 30, 9, 9}}, + {m68k_op_moves_16_aw , 0xffff, 0x0e78, { 0, 26, 9, 9}}, + {m68k_op_moves_16_al , 0xffff, 0x0e79, { 0, 30, 9, 9}}, + {m68k_op_moves_32_aw , 0xffff, 0x0eb8, { 0, 32, 9, 9}}, + {m68k_op_moves_32_al , 0xffff, 0x0eb9, { 0, 36, 9, 9}}, + {m68k_op_cas_32_aw , 0xffff, 0x0ef8, { 0, 0, 16, 16}}, + {m68k_op_cas_32_al , 0xffff, 0x0ef9, { 0, 0, 16, 16}}, + {m68k_op_cas2_32 , 0xffff, 0x0efc, { 0, 0, 12, 12}}, + {m68k_op_move_8_aw_pi7 , 0xffff, 0x11df, { 16, 16, 8, 8}}, + {m68k_op_move_8_aw_pd7 , 0xffff, 0x11e7, { 18, 18, 9, 9}}, + {m68k_op_move_8_aw_aw , 0xffff, 0x11f8, { 20, 20, 8, 8}}, + {m68k_op_move_8_aw_al , 0xffff, 0x11f9, { 24, 24, 8, 8}}, + {m68k_op_move_8_aw_pcdi , 0xffff, 0x11fa, { 20, 20, 9, 9}}, + {m68k_op_move_8_aw_pcix , 0xffff, 0x11fb, { 22, 22, 11, 11}}, + {m68k_op_move_8_aw_i , 0xffff, 0x11fc, { 16, 16, 6, 6}}, + {m68k_op_move_8_al_pi7 , 0xffff, 0x13df, { 20, 20, 10, 10}}, + {m68k_op_move_8_al_pd7 , 0xffff, 0x13e7, { 22, 22, 11, 11}}, + {m68k_op_move_8_al_aw , 0xffff, 0x13f8, { 24, 24, 10, 10}}, + {m68k_op_move_8_al_al , 0xffff, 0x13f9, { 28, 28, 10, 10}}, + {m68k_op_move_8_al_pcdi , 0xffff, 0x13fa, { 24, 24, 11, 11}}, + {m68k_op_move_8_al_pcix , 0xffff, 0x13fb, { 26, 26, 13, 13}}, + {m68k_op_move_8_al_i , 0xffff, 0x13fc, { 20, 20, 8, 8}}, + {m68k_op_move_8_pi7_pi7 , 0xffff, 0x1edf, { 12, 12, 8, 8}}, + {m68k_op_move_8_pi7_pd7 , 0xffff, 0x1ee7, { 14, 14, 9, 9}}, + {m68k_op_move_8_pi7_aw , 0xffff, 0x1ef8, { 16, 16, 8, 8}}, + {m68k_op_move_8_pi7_al , 0xffff, 0x1ef9, { 20, 20, 8, 8}}, + {m68k_op_move_8_pi7_pcdi , 0xffff, 0x1efa, { 16, 16, 9, 9}}, + {m68k_op_move_8_pi7_pcix , 0xffff, 0x1efb, { 18, 18, 11, 11}}, + {m68k_op_move_8_pi7_i , 0xffff, 0x1efc, { 12, 12, 6, 6}}, + {m68k_op_move_8_pd7_pi7 , 0xffff, 0x1f1f, { 12, 12, 9, 9}}, + {m68k_op_move_8_pd7_pd7 , 0xffff, 0x1f27, { 14, 14, 10, 10}}, + {m68k_op_move_8_pd7_aw , 0xffff, 0x1f38, { 16, 16, 9, 9}}, + {m68k_op_move_8_pd7_al , 0xffff, 0x1f39, { 20, 20, 9, 9}}, + {m68k_op_move_8_pd7_pcdi , 0xffff, 0x1f3a, { 16, 16, 10, 10}}, + {m68k_op_move_8_pd7_pcix , 0xffff, 0x1f3b, { 18, 18, 12, 12}}, + {m68k_op_move_8_pd7_i , 0xffff, 0x1f3c, { 12, 12, 7, 7}}, + {m68k_op_move_32_aw_aw , 0xffff, 0x21f8, { 28, 28, 8, 8}}, + {m68k_op_move_32_aw_al , 0xffff, 0x21f9, { 32, 32, 8, 8}}, + {m68k_op_move_32_aw_pcdi , 0xffff, 0x21fa, { 28, 28, 9, 9}}, + {m68k_op_move_32_aw_pcix , 0xffff, 0x21fb, { 30, 30, 11, 11}}, + {m68k_op_move_32_aw_i , 0xffff, 0x21fc, { 24, 24, 8, 8}}, + {m68k_op_move_32_al_aw , 0xffff, 0x23f8, { 32, 32, 10, 10}}, + {m68k_op_move_32_al_al , 0xffff, 0x23f9, { 36, 36, 10, 10}}, + {m68k_op_move_32_al_pcdi , 0xffff, 0x23fa, { 32, 32, 11, 11}}, + {m68k_op_move_32_al_pcix , 0xffff, 0x23fb, { 34, 34, 13, 13}}, + {m68k_op_move_32_al_i , 0xffff, 0x23fc, { 28, 28, 10, 10}}, + {m68k_op_move_16_aw_aw , 0xffff, 0x31f8, { 20, 20, 8, 8}}, + {m68k_op_move_16_aw_al , 0xffff, 0x31f9, { 24, 24, 8, 8}}, + {m68k_op_move_16_aw_pcdi , 0xffff, 0x31fa, { 20, 20, 9, 9}}, + {m68k_op_move_16_aw_pcix , 0xffff, 0x31fb, { 22, 22, 11, 11}}, + {m68k_op_move_16_aw_i , 0xffff, 0x31fc, { 16, 16, 6, 6}}, + {m68k_op_move_16_al_aw , 0xffff, 0x33f8, { 24, 24, 10, 10}}, + {m68k_op_move_16_al_al , 0xffff, 0x33f9, { 28, 28, 10, 10}}, + {m68k_op_move_16_al_pcdi , 0xffff, 0x33fa, { 24, 24, 11, 11}}, + {m68k_op_move_16_al_pcix , 0xffff, 0x33fb, { 26, 26, 13, 13}}, + {m68k_op_move_16_al_i , 0xffff, 0x33fc, { 20, 20, 8, 8}}, + {m68k_op_negx_8_pi7 , 0xffff, 0x401f, { 12, 12, 8, 8}}, + {m68k_op_negx_8_pd7 , 0xffff, 0x4027, { 14, 14, 9, 9}}, + {m68k_op_negx_8_aw , 0xffff, 0x4038, { 16, 16, 8, 8}}, + {m68k_op_negx_8_al , 0xffff, 0x4039, { 20, 20, 8, 8}}, + {m68k_op_negx_16_aw , 0xffff, 0x4078, { 16, 16, 8, 8}}, + {m68k_op_negx_16_al , 0xffff, 0x4079, { 20, 20, 8, 8}}, + {m68k_op_negx_32_aw , 0xffff, 0x40b8, { 24, 24, 8, 8}}, + {m68k_op_negx_32_al , 0xffff, 0x40b9, { 28, 28, 8, 8}}, + {m68k_op_move_16_frs_aw , 0xffff, 0x40f8, { 16, 16, 12, 12}}, + {m68k_op_move_16_frs_al , 0xffff, 0x40f9, { 20, 20, 12, 12}}, + {m68k_op_clr_8_pi7 , 0xffff, 0x421f, { 10, 8, 8, 8}}, + {m68k_op_clr_8_pd7 , 0xffff, 0x4227, { 12, 10, 9, 9}}, + {m68k_op_clr_8_aw , 0xffff, 0x4238, { 14, 12, 8, 8}}, + {m68k_op_clr_8_al , 0xffff, 0x4239, { 18, 14, 8, 8}}, + {m68k_op_clr_16_aw , 0xffff, 0x4278, { 14, 12, 8, 8}}, + {m68k_op_clr_16_al , 0xffff, 0x4279, { 18, 14, 8, 8}}, + {m68k_op_clr_32_aw , 0xffff, 0x42b8, { 24, 16, 8, 8}}, + {m68k_op_clr_32_al , 0xffff, 0x42b9, { 28, 20, 8, 8}}, + {m68k_op_move_16_frc_aw , 0xffff, 0x42f8, { 0, 16, 8, 8}}, + {m68k_op_move_16_frc_al , 0xffff, 0x42f9, { 0, 20, 8, 8}}, + {m68k_op_neg_8_pi7 , 0xffff, 0x441f, { 12, 12, 8, 8}}, + {m68k_op_neg_8_pd7 , 0xffff, 0x4427, { 14, 14, 9, 9}}, + {m68k_op_neg_8_aw , 0xffff, 0x4438, { 16, 16, 8, 8}}, + {m68k_op_neg_8_al , 0xffff, 0x4439, { 20, 20, 8, 8}}, + {m68k_op_neg_16_aw , 0xffff, 0x4478, { 16, 16, 8, 8}}, + {m68k_op_neg_16_al , 0xffff, 0x4479, { 20, 20, 8, 8}}, + {m68k_op_neg_32_aw , 0xffff, 0x44b8, { 24, 24, 8, 8}}, + {m68k_op_neg_32_al , 0xffff, 0x44b9, { 28, 28, 8, 8}}, + {m68k_op_move_16_toc_aw , 0xffff, 0x44f8, { 20, 20, 8, 8}}, + {m68k_op_move_16_toc_al , 0xffff, 0x44f9, { 24, 24, 8, 8}}, + {m68k_op_move_16_toc_pcdi , 0xffff, 0x44fa, { 20, 20, 9, 9}}, + {m68k_op_move_16_toc_pcix , 0xffff, 0x44fb, { 22, 22, 11, 11}}, + {m68k_op_move_16_toc_i , 0xffff, 0x44fc, { 16, 16, 6, 6}}, + {m68k_op_not_8_pi7 , 0xffff, 0x461f, { 12, 12, 8, 8}}, + {m68k_op_not_8_pd7 , 0xffff, 0x4627, { 14, 14, 9, 9}}, + {m68k_op_not_8_aw , 0xffff, 0x4638, { 16, 16, 8, 8}}, + {m68k_op_not_8_al , 0xffff, 0x4639, { 20, 20, 8, 8}}, + {m68k_op_not_16_aw , 0xffff, 0x4678, { 16, 16, 8, 8}}, + {m68k_op_not_16_al , 0xffff, 0x4679, { 20, 20, 8, 8}}, + {m68k_op_not_32_aw , 0xffff, 0x46b8, { 24, 24, 8, 8}}, + {m68k_op_not_32_al , 0xffff, 0x46b9, { 28, 28, 8, 8}}, + {m68k_op_move_16_tos_aw , 0xffff, 0x46f8, { 20, 20, 12, 12}}, + {m68k_op_move_16_tos_al , 0xffff, 0x46f9, { 24, 24, 12, 12}}, + {m68k_op_move_16_tos_pcdi , 0xffff, 0x46fa, { 20, 20, 13, 13}}, + {m68k_op_move_16_tos_pcix , 0xffff, 0x46fb, { 22, 22, 15, 15}}, + {m68k_op_move_16_tos_i , 0xffff, 0x46fc, { 16, 16, 10, 10}}, + {m68k_op_link_32_a7 , 0xffff, 0x480f, { 0, 0, 6, 6}}, + {m68k_op_nbcd_8_pi7 , 0xffff, 0x481f, { 12, 12, 10, 10}}, + {m68k_op_nbcd_8_pd7 , 0xffff, 0x4827, { 14, 14, 11, 11}}, + {m68k_op_nbcd_8_aw , 0xffff, 0x4838, { 16, 16, 10, 10}}, + {m68k_op_nbcd_8_al , 0xffff, 0x4839, { 20, 20, 10, 10}}, + {m68k_op_pea_32_aw , 0xffff, 0x4878, { 16, 16, 9, 9}}, + {m68k_op_pea_32_al , 0xffff, 0x4879, { 20, 20, 9, 9}}, + {m68k_op_pea_32_pcdi , 0xffff, 0x487a, { 16, 16, 10, 10}}, + {m68k_op_pea_32_pcix , 0xffff, 0x487b, { 20, 20, 12, 12}}, + {m68k_op_movem_16_re_aw , 0xffff, 0x48b8, { 12, 12, 8, 8}}, + {m68k_op_movem_16_re_al , 0xffff, 0x48b9, { 16, 16, 8, 8}}, + {m68k_op_movem_32_re_aw , 0xffff, 0x48f8, { 12, 12, 8, 8}}, + {m68k_op_movem_32_re_al , 0xffff, 0x48f9, { 16, 16, 8, 8}}, + {m68k_op_tst_8_pi7 , 0xffff, 0x4a1f, { 8, 8, 6, 6}}, + {m68k_op_tst_8_pd7 , 0xffff, 0x4a27, { 10, 10, 7, 7}}, + {m68k_op_tst_8_aw , 0xffff, 0x4a38, { 12, 12, 6, 6}}, + {m68k_op_tst_8_al , 0xffff, 0x4a39, { 16, 16, 6, 6}}, + {m68k_op_tst_8_pcdi , 0xffff, 0x4a3a, { 0, 0, 7, 7}}, + {m68k_op_tst_8_pcix , 0xffff, 0x4a3b, { 0, 0, 9, 9}}, + {m68k_op_tst_8_i , 0xffff, 0x4a3c, { 0, 0, 6, 6}}, + {m68k_op_tst_16_aw , 0xffff, 0x4a78, { 12, 12, 6, 6}}, + {m68k_op_tst_16_al , 0xffff, 0x4a79, { 16, 16, 6, 6}}, + {m68k_op_tst_16_pcdi , 0xffff, 0x4a7a, { 0, 0, 7, 7}}, + {m68k_op_tst_16_pcix , 0xffff, 0x4a7b, { 0, 0, 9, 9}}, + {m68k_op_tst_16_i , 0xffff, 0x4a7c, { 0, 0, 6, 6}}, + {m68k_op_tst_32_aw , 0xffff, 0x4ab8, { 16, 16, 6, 6}}, + {m68k_op_tst_32_al , 0xffff, 0x4ab9, { 20, 20, 6, 6}}, + {m68k_op_tst_32_pcdi , 0xffff, 0x4aba, { 0, 0, 7, 7}}, + {m68k_op_tst_32_pcix , 0xffff, 0x4abb, { 0, 0, 9, 9}}, + {m68k_op_tst_32_i , 0xffff, 0x4abc, { 0, 0, 6, 6}}, + {m68k_op_tas_8_pi7 , 0xffff, 0x4adf, { 18, 18, 16, 16}}, + {m68k_op_tas_8_pd7 , 0xffff, 0x4ae7, { 20, 20, 17, 17}}, + {m68k_op_tas_8_aw , 0xffff, 0x4af8, { 22, 22, 16, 16}}, + {m68k_op_tas_8_al , 0xffff, 0x4af9, { 26, 26, 16, 16}}, + {m68k_op_illegal , 0xffff, 0x4afc, { 4, 4, 4, 4}}, + {m68k_op_mull_32_aw , 0xffff, 0x4c38, { 0, 0, 47, 47}}, + {m68k_op_mull_32_al , 0xffff, 0x4c39, { 0, 0, 47, 47}}, + {m68k_op_mull_32_pcdi , 0xffff, 0x4c3a, { 0, 0, 48, 48}}, + {m68k_op_mull_32_pcix , 0xffff, 0x4c3b, { 0, 0, 50, 50}}, + {m68k_op_mull_32_i , 0xffff, 0x4c3c, { 0, 0, 47, 47}}, + {m68k_op_divl_32_aw , 0xffff, 0x4c78, { 0, 0, 88, 88}}, + {m68k_op_divl_32_al , 0xffff, 0x4c79, { 0, 0, 88, 88}}, + {m68k_op_divl_32_pcdi , 0xffff, 0x4c7a, { 0, 0, 89, 89}}, + {m68k_op_divl_32_pcix , 0xffff, 0x4c7b, { 0, 0, 91, 91}}, + {m68k_op_divl_32_i , 0xffff, 0x4c7c, { 0, 0, 88, 88}}, + {m68k_op_movem_16_er_aw , 0xffff, 0x4cb8, { 16, 16, 12, 12}}, + {m68k_op_movem_16_er_al , 0xffff, 0x4cb9, { 20, 20, 12, 12}}, + {m68k_op_movem_16_er_pcdi , 0xffff, 0x4cba, { 16, 16, 9, 9}}, + {m68k_op_movem_16_er_pcix , 0xffff, 0x4cbb, { 18, 18, 11, 11}}, + {m68k_op_movem_32_er_aw , 0xffff, 0x4cf8, { 16, 16, 12, 12}}, + {m68k_op_movem_32_er_al , 0xffff, 0x4cf9, { 20, 20, 12, 12}}, + {m68k_op_movem_32_er_pcdi , 0xffff, 0x4cfa, { 16, 16, 9, 9}}, + {m68k_op_movem_32_er_pcix , 0xffff, 0x4cfb, { 18, 18, 11, 11}}, + {m68k_op_link_16_a7 , 0xffff, 0x4e57, { 16, 16, 5, 5}}, + {m68k_op_unlk_32_a7 , 0xffff, 0x4e5f, { 12, 12, 6, 6}}, + {m68k_op_reset , 0xffff, 0x4e70, { 0, 0, 0, 0}}, + {m68k_op_nop , 0xffff, 0x4e71, { 4, 4, 2, 2}}, + {m68k_op_stop , 0xffff, 0x4e72, { 4, 4, 8, 8}}, + {m68k_op_rte_32 , 0xffff, 0x4e73, { 20, 24, 20, 20}}, + {m68k_op_rtd_32 , 0xffff, 0x4e74, { 0, 16, 10, 10}}, + {m68k_op_rts_32 , 0xffff, 0x4e75, { 16, 16, 10, 10}}, + {m68k_op_trapv , 0xffff, 0x4e76, { 4, 4, 4, 4}}, + {m68k_op_rtr_32 , 0xffff, 0x4e77, { 20, 20, 14, 14}}, + {m68k_op_movec_32_cr , 0xffff, 0x4e7a, { 0, 12, 6, 6}}, + {m68k_op_movec_32_rc , 0xffff, 0x4e7b, { 0, 10, 12, 12}}, + {m68k_op_jsr_32_aw , 0xffff, 0x4eb8, { 18, 18, 4, 4}}, + {m68k_op_jsr_32_al , 0xffff, 0x4eb9, { 20, 20, 4, 4}}, + {m68k_op_jsr_32_pcdi , 0xffff, 0x4eba, { 18, 18, 5, 5}}, + {m68k_op_jsr_32_pcix , 0xffff, 0x4ebb, { 22, 22, 7, 7}}, + {m68k_op_jmp_32_aw , 0xffff, 0x4ef8, { 10, 10, 4, 4}}, + {m68k_op_jmp_32_al , 0xffff, 0x4ef9, { 12, 12, 4, 4}}, + {m68k_op_jmp_32_pcdi , 0xffff, 0x4efa, { 10, 10, 5, 5}}, + {m68k_op_jmp_32_pcix , 0xffff, 0x4efb, { 14, 14, 7, 7}}, + {m68k_op_st_8_pi7 , 0xffff, 0x50df, { 12, 12, 10, 10}}, + {m68k_op_st_8_pd7 , 0xffff, 0x50e7, { 14, 14, 11, 11}}, + {m68k_op_st_8_aw , 0xffff, 0x50f8, { 16, 16, 10, 10}}, + {m68k_op_st_8_al , 0xffff, 0x50f9, { 20, 20, 10, 10}}, + {m68k_op_trapt_16 , 0xffff, 0x50fa, { 0, 0, 6, 6}}, + {m68k_op_trapt_32 , 0xffff, 0x50fb, { 0, 0, 8, 8}}, + {m68k_op_trapt , 0xffff, 0x50fc, { 0, 0, 4, 4}}, + {m68k_op_sf_8_pi7 , 0xffff, 0x51df, { 12, 12, 10, 10}}, + {m68k_op_sf_8_pd7 , 0xffff, 0x51e7, { 14, 14, 11, 11}}, + {m68k_op_sf_8_aw , 0xffff, 0x51f8, { 16, 16, 10, 10}}, + {m68k_op_sf_8_al , 0xffff, 0x51f9, { 20, 20, 10, 10}}, + {m68k_op_trapf_16 , 0xffff, 0x51fa, { 0, 0, 6, 6}}, + {m68k_op_trapf_32 , 0xffff, 0x51fb, { 0, 0, 8, 8}}, + {m68k_op_trapf , 0xffff, 0x51fc, { 0, 0, 4, 4}}, + {m68k_op_shi_8_pi7 , 0xffff, 0x52df, { 12, 12, 10, 10}}, + {m68k_op_shi_8_pd7 , 0xffff, 0x52e7, { 14, 14, 11, 11}}, + {m68k_op_shi_8_aw , 0xffff, 0x52f8, { 16, 16, 10, 10}}, + {m68k_op_shi_8_al , 0xffff, 0x52f9, { 20, 20, 10, 10}}, + {m68k_op_traphi_16 , 0xffff, 0x52fa, { 0, 0, 6, 6}}, + {m68k_op_traphi_32 , 0xffff, 0x52fb, { 0, 0, 8, 8}}, + {m68k_op_traphi , 0xffff, 0x52fc, { 0, 0, 4, 4}}, + {m68k_op_sls_8_pi7 , 0xffff, 0x53df, { 12, 12, 10, 10}}, + {m68k_op_sls_8_pd7 , 0xffff, 0x53e7, { 14, 14, 11, 11}}, + {m68k_op_sls_8_aw , 0xffff, 0x53f8, { 16, 16, 10, 10}}, + {m68k_op_sls_8_al , 0xffff, 0x53f9, { 20, 20, 10, 10}}, + {m68k_op_trapls_16 , 0xffff, 0x53fa, { 0, 0, 6, 6}}, + {m68k_op_trapls_32 , 0xffff, 0x53fb, { 0, 0, 8, 8}}, + {m68k_op_trapls , 0xffff, 0x53fc, { 0, 0, 4, 4}}, + {m68k_op_scc_8_pi7 , 0xffff, 0x54df, { 12, 12, 10, 10}}, + {m68k_op_scc_8_pd7 , 0xffff, 0x54e7, { 14, 14, 11, 11}}, + {m68k_op_scc_8_aw , 0xffff, 0x54f8, { 16, 16, 10, 10}}, + {m68k_op_scc_8_al , 0xffff, 0x54f9, { 20, 20, 10, 10}}, + {m68k_op_trapcc_16 , 0xffff, 0x54fa, { 0, 0, 6, 6}}, + {m68k_op_trapcc_32 , 0xffff, 0x54fb, { 0, 0, 8, 8}}, + {m68k_op_trapcc , 0xffff, 0x54fc, { 0, 0, 4, 4}}, + {m68k_op_scs_8_pi7 , 0xffff, 0x55df, { 12, 12, 10, 10}}, + {m68k_op_scs_8_pd7 , 0xffff, 0x55e7, { 14, 14, 11, 11}}, + {m68k_op_scs_8_aw , 0xffff, 0x55f8, { 16, 16, 10, 10}}, + {m68k_op_scs_8_al , 0xffff, 0x55f9, { 20, 20, 10, 10}}, + {m68k_op_trapcs_16 , 0xffff, 0x55fa, { 0, 0, 6, 6}}, + {m68k_op_trapcs_32 , 0xffff, 0x55fb, { 0, 0, 8, 8}}, + {m68k_op_trapcs , 0xffff, 0x55fc, { 0, 0, 4, 4}}, + {m68k_op_sne_8_pi7 , 0xffff, 0x56df, { 12, 12, 10, 10}}, + {m68k_op_sne_8_pd7 , 0xffff, 0x56e7, { 14, 14, 11, 11}}, + {m68k_op_sne_8_aw , 0xffff, 0x56f8, { 16, 16, 10, 10}}, + {m68k_op_sne_8_al , 0xffff, 0x56f9, { 20, 20, 10, 10}}, + {m68k_op_trapne_16 , 0xffff, 0x56fa, { 0, 0, 6, 6}}, + {m68k_op_trapne_32 , 0xffff, 0x56fb, { 0, 0, 8, 8}}, + {m68k_op_trapne , 0xffff, 0x56fc, { 0, 0, 4, 4}}, + {m68k_op_seq_8_pi7 , 0xffff, 0x57df, { 12, 12, 10, 10}}, + {m68k_op_seq_8_pd7 , 0xffff, 0x57e7, { 14, 14, 11, 11}}, + {m68k_op_seq_8_aw , 0xffff, 0x57f8, { 16, 16, 10, 10}}, + {m68k_op_seq_8_al , 0xffff, 0x57f9, { 20, 20, 10, 10}}, + {m68k_op_trapeq_16 , 0xffff, 0x57fa, { 0, 0, 6, 6}}, + {m68k_op_trapeq_32 , 0xffff, 0x57fb, { 0, 0, 8, 8}}, + {m68k_op_trapeq , 0xffff, 0x57fc, { 0, 0, 4, 4}}, + {m68k_op_svc_8_pi7 , 0xffff, 0x58df, { 12, 12, 10, 10}}, + {m68k_op_svc_8_pd7 , 0xffff, 0x58e7, { 14, 14, 11, 11}}, + {m68k_op_svc_8_aw , 0xffff, 0x58f8, { 16, 16, 10, 10}}, + {m68k_op_svc_8_al , 0xffff, 0x58f9, { 20, 20, 10, 10}}, + {m68k_op_trapvc_16 , 0xffff, 0x58fa, { 0, 0, 6, 6}}, + {m68k_op_trapvc_32 , 0xffff, 0x58fb, { 0, 0, 8, 8}}, + {m68k_op_trapvc , 0xffff, 0x58fc, { 0, 0, 4, 4}}, + {m68k_op_svs_8_pi7 , 0xffff, 0x59df, { 12, 12, 10, 10}}, + {m68k_op_svs_8_pd7 , 0xffff, 0x59e7, { 14, 14, 11, 11}}, + {m68k_op_svs_8_aw , 0xffff, 0x59f8, { 16, 16, 10, 10}}, + {m68k_op_svs_8_al , 0xffff, 0x59f9, { 20, 20, 10, 10}}, + {m68k_op_trapvs_16 , 0xffff, 0x59fa, { 0, 0, 6, 6}}, + {m68k_op_trapvs_32 , 0xffff, 0x59fb, { 0, 0, 8, 8}}, + {m68k_op_trapvs , 0xffff, 0x59fc, { 0, 0, 4, 4}}, + {m68k_op_spl_8_pi7 , 0xffff, 0x5adf, { 12, 12, 10, 10}}, + {m68k_op_spl_8_pd7 , 0xffff, 0x5ae7, { 14, 14, 11, 11}}, + {m68k_op_spl_8_aw , 0xffff, 0x5af8, { 16, 16, 10, 10}}, + {m68k_op_spl_8_al , 0xffff, 0x5af9, { 20, 20, 10, 10}}, + {m68k_op_trappl_16 , 0xffff, 0x5afa, { 0, 0, 6, 6}}, + {m68k_op_trappl_32 , 0xffff, 0x5afb, { 0, 0, 8, 8}}, + {m68k_op_trappl , 0xffff, 0x5afc, { 0, 0, 4, 4}}, + {m68k_op_smi_8_pi7 , 0xffff, 0x5bdf, { 12, 12, 10, 10}}, + {m68k_op_smi_8_pd7 , 0xffff, 0x5be7, { 14, 14, 11, 11}}, + {m68k_op_smi_8_aw , 0xffff, 0x5bf8, { 16, 16, 10, 10}}, + {m68k_op_smi_8_al , 0xffff, 0x5bf9, { 20, 20, 10, 10}}, + {m68k_op_trapmi_16 , 0xffff, 0x5bfa, { 0, 0, 6, 6}}, + {m68k_op_trapmi_32 , 0xffff, 0x5bfb, { 0, 0, 8, 8}}, + {m68k_op_trapmi , 0xffff, 0x5bfc, { 0, 0, 4, 4}}, + {m68k_op_sge_8_pi7 , 0xffff, 0x5cdf, { 12, 12, 10, 10}}, + {m68k_op_sge_8_pd7 , 0xffff, 0x5ce7, { 14, 14, 11, 11}}, + {m68k_op_sge_8_aw , 0xffff, 0x5cf8, { 16, 16, 10, 10}}, + {m68k_op_sge_8_al , 0xffff, 0x5cf9, { 20, 20, 10, 10}}, + {m68k_op_trapge_16 , 0xffff, 0x5cfa, { 0, 0, 6, 6}}, + {m68k_op_trapge_32 , 0xffff, 0x5cfb, { 0, 0, 8, 8}}, + {m68k_op_trapge , 0xffff, 0x5cfc, { 0, 0, 4, 4}}, + {m68k_op_slt_8_pi7 , 0xffff, 0x5ddf, { 12, 12, 10, 10}}, + {m68k_op_slt_8_pd7 , 0xffff, 0x5de7, { 14, 14, 11, 11}}, + {m68k_op_slt_8_aw , 0xffff, 0x5df8, { 16, 16, 10, 10}}, + {m68k_op_slt_8_al , 0xffff, 0x5df9, { 20, 20, 10, 10}}, + {m68k_op_traplt_16 , 0xffff, 0x5dfa, { 0, 0, 6, 6}}, + {m68k_op_traplt_32 , 0xffff, 0x5dfb, { 0, 0, 8, 8}}, + {m68k_op_traplt , 0xffff, 0x5dfc, { 0, 0, 4, 4}}, + {m68k_op_sgt_8_pi7 , 0xffff, 0x5edf, { 12, 12, 10, 10}}, + {m68k_op_sgt_8_pd7 , 0xffff, 0x5ee7, { 14, 14, 11, 11}}, + {m68k_op_sgt_8_aw , 0xffff, 0x5ef8, { 16, 16, 10, 10}}, + {m68k_op_sgt_8_al , 0xffff, 0x5ef9, { 20, 20, 10, 10}}, + {m68k_op_trapgt_16 , 0xffff, 0x5efa, { 0, 0, 6, 6}}, + {m68k_op_trapgt_32 , 0xffff, 0x5efb, { 0, 0, 8, 8}}, + {m68k_op_trapgt , 0xffff, 0x5efc, { 0, 0, 4, 4}}, + {m68k_op_sle_8_pi7 , 0xffff, 0x5fdf, { 12, 12, 10, 10}}, + {m68k_op_sle_8_pd7 , 0xffff, 0x5fe7, { 14, 14, 11, 11}}, + {m68k_op_sle_8_aw , 0xffff, 0x5ff8, { 16, 16, 10, 10}}, + {m68k_op_sle_8_al , 0xffff, 0x5ff9, { 20, 20, 10, 10}}, + {m68k_op_traple_16 , 0xffff, 0x5ffa, { 0, 0, 6, 6}}, + {m68k_op_traple_32 , 0xffff, 0x5ffb, { 0, 0, 8, 8}}, + {m68k_op_traple , 0xffff, 0x5ffc, { 0, 0, 4, 4}}, + {m68k_op_bra_16 , 0xffff, 0x6000, { 10, 10, 10, 10}}, + {m68k_op_bra_32 , 0xffff, 0x60ff, { 10, 10, 10, 10}}, + {m68k_op_bsr_16 , 0xffff, 0x6100, { 18, 18, 7, 7}}, + {m68k_op_bsr_32 , 0xffff, 0x61ff, { 18, 18, 7, 7}}, + {m68k_op_bhi_16 , 0xffff, 0x6200, { 10, 10, 6, 6}}, + {m68k_op_bhi_32 , 0xffff, 0x62ff, { 10, 10, 6, 6}}, + {m68k_op_bls_16 , 0xffff, 0x6300, { 10, 10, 6, 6}}, + {m68k_op_bls_32 , 0xffff, 0x63ff, { 10, 10, 6, 6}}, + {m68k_op_bcc_16 , 0xffff, 0x6400, { 10, 10, 6, 6}}, + {m68k_op_bcc_32 , 0xffff, 0x64ff, { 10, 10, 6, 6}}, + {m68k_op_bcs_16 , 0xffff, 0x6500, { 10, 10, 6, 6}}, + {m68k_op_bcs_32 , 0xffff, 0x65ff, { 10, 10, 6, 6}}, + {m68k_op_bne_16 , 0xffff, 0x6600, { 10, 10, 6, 6}}, + {m68k_op_bne_32 , 0xffff, 0x66ff, { 10, 10, 6, 6}}, + {m68k_op_beq_16 , 0xffff, 0x6700, { 10, 10, 6, 6}}, + {m68k_op_beq_32 , 0xffff, 0x67ff, { 10, 10, 6, 6}}, + {m68k_op_bvc_16 , 0xffff, 0x6800, { 10, 10, 6, 6}}, + {m68k_op_bvc_32 , 0xffff, 0x68ff, { 10, 10, 6, 6}}, + {m68k_op_bvs_16 , 0xffff, 0x6900, { 10, 10, 6, 6}}, + {m68k_op_bvs_32 , 0xffff, 0x69ff, { 10, 10, 6, 6}}, + {m68k_op_bpl_16 , 0xffff, 0x6a00, { 10, 10, 6, 6}}, + {m68k_op_bpl_32 , 0xffff, 0x6aff, { 10, 10, 6, 6}}, + {m68k_op_bmi_16 , 0xffff, 0x6b00, { 10, 10, 6, 6}}, + {m68k_op_bmi_32 , 0xffff, 0x6bff, { 10, 10, 6, 6}}, + {m68k_op_bge_16 , 0xffff, 0x6c00, { 10, 10, 6, 6}}, + {m68k_op_bge_32 , 0xffff, 0x6cff, { 10, 10, 6, 6}}, + {m68k_op_blt_16 , 0xffff, 0x6d00, { 10, 10, 6, 6}}, + {m68k_op_blt_32 , 0xffff, 0x6dff, { 10, 10, 6, 6}}, + {m68k_op_bgt_16 , 0xffff, 0x6e00, { 10, 10, 6, 6}}, + {m68k_op_bgt_32 , 0xffff, 0x6eff, { 10, 10, 6, 6}}, + {m68k_op_ble_16 , 0xffff, 0x6f00, { 10, 10, 6, 6}}, + {m68k_op_ble_32 , 0xffff, 0x6fff, { 10, 10, 6, 6}}, + {m68k_op_sbcd_8_mm_axy7 , 0xffff, 0x8f0f, { 18, 18, 16, 16}}, + {m68k_op_pack_16_mm_axy7 , 0xffff, 0x8f4f, { 0, 0, 13, 13}}, + {m68k_op_unpk_16_mm_axy7 , 0xffff, 0x8f8f, { 0, 0, 13, 13}}, + {m68k_op_subx_8_mm_axy7 , 0xffff, 0x9f0f, { 18, 18, 12, 12}}, + {m68k_op_cmpm_8_axy7 , 0xffff, 0xbf0f, { 12, 12, 9, 9}}, + {m68k_op_abcd_8_mm_axy7 , 0xffff, 0xcf0f, { 18, 18, 16, 16}}, + {m68k_op_addx_8_mm_axy7 , 0xffff, 0xdf0f, { 18, 18, 12, 12}}, + {m68k_op_asr_16_aw , 0xffff, 0xe0f8, { 16, 16, 9, 9}}, + {m68k_op_asr_16_al , 0xffff, 0xe0f9, { 20, 20, 9, 9}}, + {m68k_op_asl_16_aw , 0xffff, 0xe1f8, { 16, 16, 10, 10}}, + {m68k_op_asl_16_al , 0xffff, 0xe1f9, { 20, 20, 10, 10}}, + {m68k_op_lsr_16_aw , 0xffff, 0xe2f8, { 16, 16, 9, 9}}, + {m68k_op_lsr_16_al , 0xffff, 0xe2f9, { 20, 20, 9, 9}}, + {m68k_op_lsl_16_aw , 0xffff, 0xe3f8, { 16, 16, 9, 9}}, + {m68k_op_lsl_16_al , 0xffff, 0xe3f9, { 20, 20, 9, 9}}, + {m68k_op_roxr_16_aw , 0xffff, 0xe4f8, { 16, 16, 9, 9}}, + {m68k_op_roxr_16_al , 0xffff, 0xe4f9, { 20, 20, 9, 9}}, + {m68k_op_roxl_16_aw , 0xffff, 0xe5f8, { 16, 16, 9, 9}}, + {m68k_op_roxl_16_al , 0xffff, 0xe5f9, { 20, 20, 9, 9}}, + {m68k_op_ror_16_aw , 0xffff, 0xe6f8, { 16, 16, 11, 11}}, + {m68k_op_ror_16_al , 0xffff, 0xe6f9, { 20, 20, 11, 11}}, + {m68k_op_rol_16_aw , 0xffff, 0xe7f8, { 16, 16, 11, 11}}, + {m68k_op_rol_16_al , 0xffff, 0xe7f9, { 20, 20, 11, 11}}, + {m68k_op_bftst_32_aw , 0xffff, 0xe8f8, { 0, 0, 17, 17}}, + {m68k_op_bftst_32_al , 0xffff, 0xe8f9, { 0, 0, 17, 17}}, + {m68k_op_bftst_32_pcdi , 0xffff, 0xe8fa, { 0, 0, 18, 18}}, + {m68k_op_bftst_32_pcix , 0xffff, 0xe8fb, { 0, 0, 20, 20}}, + {m68k_op_bfextu_32_aw , 0xffff, 0xe9f8, { 0, 0, 19, 19}}, + {m68k_op_bfextu_32_al , 0xffff, 0xe9f9, { 0, 0, 19, 19}}, + {m68k_op_bfextu_32_pcdi , 0xffff, 0xe9fa, { 0, 0, 20, 20}}, + {m68k_op_bfextu_32_pcix , 0xffff, 0xe9fb, { 0, 0, 22, 22}}, + {m68k_op_bfchg_32_aw , 0xffff, 0xeaf8, { 0, 0, 24, 24}}, + {m68k_op_bfchg_32_al , 0xffff, 0xeaf9, { 0, 0, 24, 24}}, + {m68k_op_bfexts_32_aw , 0xffff, 0xebf8, { 0, 0, 19, 19}}, + {m68k_op_bfexts_32_al , 0xffff, 0xebf9, { 0, 0, 19, 19}}, + {m68k_op_bfexts_32_pcdi , 0xffff, 0xebfa, { 0, 0, 20, 20}}, + {m68k_op_bfexts_32_pcix , 0xffff, 0xebfb, { 0, 0, 22, 22}}, + {m68k_op_bfclr_32_aw , 0xffff, 0xecf8, { 0, 0, 24, 24}}, + {m68k_op_bfclr_32_al , 0xffff, 0xecf9, { 0, 0, 24, 24}}, + {m68k_op_bfffo_32_aw , 0xffff, 0xedf8, { 0, 0, 32, 32}}, + {m68k_op_bfffo_32_al , 0xffff, 0xedf9, { 0, 0, 32, 32}}, + {m68k_op_bfffo_32_pcdi , 0xffff, 0xedfa, { 0, 0, 33, 33}}, + {m68k_op_bfffo_32_pcix , 0xffff, 0xedfb, { 0, 0, 35, 35}}, + {m68k_op_bfset_32_aw , 0xffff, 0xeef8, { 0, 0, 24, 24}}, + {m68k_op_bfset_32_al , 0xffff, 0xeef9, { 0, 0, 24, 24}}, + {m68k_op_bfins_32_aw , 0xffff, 0xeff8, { 0, 0, 21, 21}}, + {m68k_op_bfins_32_al , 0xffff, 0xeff9, { 0, 0, 21, 21}}, + {m68k_op_pflush_32 , 0xffff, 0xf518, { 0, 0, 0, 4}}, + {0, 0, 0, {0, 0, 0, 0}} +}; + + +/* Build the opcode handler jump table */ +void m68ki_build_opcode_table(void) +{ + opcode_handler_struct *ostruct; + int instr; + int i; + int j; + int k; + + for(i = 0; i < 0x10000; i++) + { + /* default to illegal */ + m68ki_instruction_jump_table[i] = m68k_op_illegal; + for(k=0;kmask != 0xff00) + { + for(i = 0;i < 0x10000;i++) + { + if((i & ostruct->mask) == ostruct->match) + { + m68ki_instruction_jump_table[i] = ostruct->opcode_handler; + for(k=0;kcycles[k]; + } + } + ostruct++; + } + while(ostruct->mask == 0xff00) + { + for(i = 0;i <= 0xff;i++) + { + m68ki_instruction_jump_table[ostruct->match | i] = ostruct->opcode_handler; + for(k=0;kmatch | i] = ostruct->cycles[k]; + } + ostruct++; + } + while(ostruct->mask == 0xf1f8) + { + for(i = 0;i < 8;i++) + { + for(j = 0;j < 8;j++) + { + instr = ostruct->match | (i << 9) | j; + m68ki_instruction_jump_table[instr] = ostruct->opcode_handler; + for(k=0;kcycles[k]; + } + } + ostruct++; + } + while(ostruct->mask == 0xfff0) + { + for(i = 0;i <= 0x0f;i++) + { + m68ki_instruction_jump_table[ostruct->match | i] = ostruct->opcode_handler; + for(k=0;kmatch | i] = ostruct->cycles[k]; + } + ostruct++; + } + while(ostruct->mask == 0xf1ff) + { + for(i = 0;i <= 0x07;i++) + { + m68ki_instruction_jump_table[ostruct->match | (i << 9)] = ostruct->opcode_handler; + for(k=0;kmatch | (i << 9)] = ostruct->cycles[k]; + } + ostruct++; + } + while(ostruct->mask == 0xfff8) + { + for(i = 0;i <= 0x07;i++) + { + m68ki_instruction_jump_table[ostruct->match | i] = ostruct->opcode_handler; + for(k=0;kmatch | i] = ostruct->cycles[k]; + } + ostruct++; + } + while(ostruct->mask == 0xffff) + { + m68ki_instruction_jump_table[ostruct->match] = ostruct->opcode_handler; + for(k=0;kmatch] = ostruct->cycles[k]; + ostruct++; + } +} + + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ + + diff --git a/cpu/musashi/m68kops.h b/cpu/musashi/m68kops.h new file mode 100644 index 00000000..b3a2d5b3 --- /dev/null +++ b/cpu/musashi/m68kops.h @@ -0,0 +1,1986 @@ +#ifndef M68KOPS__HEADER +#define M68KOPS__HEADER + +/* ======================================================================== */ +/* ============================ OPCODE HANDLERS =========================== */ +/* ======================================================================== */ + + +void m68k_op_1010(void); +void m68k_op_1111(void); +void m68k_op_abcd_8_rr(void); +void m68k_op_abcd_8_mm_ax7(void); +void m68k_op_abcd_8_mm_ay7(void); +void m68k_op_abcd_8_mm_axy7(void); +void m68k_op_abcd_8_mm(void); +void m68k_op_add_8_er_d(void); +void m68k_op_add_8_er_ai(void); +void m68k_op_add_8_er_pi(void); +void m68k_op_add_8_er_pi7(void); +void m68k_op_add_8_er_pd(void); +void m68k_op_add_8_er_pd7(void); +void m68k_op_add_8_er_di(void); +void m68k_op_add_8_er_ix(void); +void m68k_op_add_8_er_aw(void); +void m68k_op_add_8_er_al(void); +void m68k_op_add_8_er_pcdi(void); +void m68k_op_add_8_er_pcix(void); +void m68k_op_add_8_er_i(void); +void m68k_op_add_16_er_d(void); +void m68k_op_add_16_er_a(void); +void m68k_op_add_16_er_ai(void); +void m68k_op_add_16_er_pi(void); +void m68k_op_add_16_er_pd(void); +void m68k_op_add_16_er_di(void); +void m68k_op_add_16_er_ix(void); +void m68k_op_add_16_er_aw(void); +void m68k_op_add_16_er_al(void); +void m68k_op_add_16_er_pcdi(void); +void m68k_op_add_16_er_pcix(void); +void m68k_op_add_16_er_i(void); +void m68k_op_add_32_er_d(void); +void m68k_op_add_32_er_a(void); +void m68k_op_add_32_er_ai(void); +void m68k_op_add_32_er_pi(void); +void m68k_op_add_32_er_pd(void); +void m68k_op_add_32_er_di(void); +void m68k_op_add_32_er_ix(void); +void m68k_op_add_32_er_aw(void); +void m68k_op_add_32_er_al(void); +void m68k_op_add_32_er_pcdi(void); +void m68k_op_add_32_er_pcix(void); +void m68k_op_add_32_er_i(void); +void m68k_op_add_8_re_ai(void); +void m68k_op_add_8_re_pi(void); +void m68k_op_add_8_re_pi7(void); +void m68k_op_add_8_re_pd(void); +void m68k_op_add_8_re_pd7(void); +void m68k_op_add_8_re_di(void); +void m68k_op_add_8_re_ix(void); +void m68k_op_add_8_re_aw(void); +void m68k_op_add_8_re_al(void); +void m68k_op_add_16_re_ai(void); +void m68k_op_add_16_re_pi(void); +void m68k_op_add_16_re_pd(void); +void m68k_op_add_16_re_di(void); +void m68k_op_add_16_re_ix(void); +void m68k_op_add_16_re_aw(void); +void m68k_op_add_16_re_al(void); +void m68k_op_add_32_re_ai(void); +void m68k_op_add_32_re_pi(void); +void m68k_op_add_32_re_pd(void); +void m68k_op_add_32_re_di(void); +void m68k_op_add_32_re_ix(void); +void m68k_op_add_32_re_aw(void); +void m68k_op_add_32_re_al(void); +void m68k_op_adda_16_d(void); +void m68k_op_adda_16_a(void); +void m68k_op_adda_16_ai(void); +void m68k_op_adda_16_pi(void); +void m68k_op_adda_16_pd(void); +void m68k_op_adda_16_di(void); +void m68k_op_adda_16_ix(void); +void m68k_op_adda_16_aw(void); +void m68k_op_adda_16_al(void); +void m68k_op_adda_16_pcdi(void); +void m68k_op_adda_16_pcix(void); +void m68k_op_adda_16_i(void); +void m68k_op_adda_32_d(void); +void m68k_op_adda_32_a(void); +void m68k_op_adda_32_ai(void); +void m68k_op_adda_32_pi(void); +void m68k_op_adda_32_pd(void); +void m68k_op_adda_32_di(void); +void m68k_op_adda_32_ix(void); +void m68k_op_adda_32_aw(void); +void m68k_op_adda_32_al(void); +void m68k_op_adda_32_pcdi(void); +void m68k_op_adda_32_pcix(void); +void m68k_op_adda_32_i(void); +void m68k_op_addi_8_d(void); +void m68k_op_addi_8_ai(void); +void m68k_op_addi_8_pi(void); +void m68k_op_addi_8_pi7(void); +void m68k_op_addi_8_pd(void); +void m68k_op_addi_8_pd7(void); +void m68k_op_addi_8_di(void); +void m68k_op_addi_8_ix(void); +void m68k_op_addi_8_aw(void); +void m68k_op_addi_8_al(void); +void m68k_op_addi_16_d(void); +void m68k_op_addi_16_ai(void); +void m68k_op_addi_16_pi(void); +void m68k_op_addi_16_pd(void); +void m68k_op_addi_16_di(void); +void m68k_op_addi_16_ix(void); +void m68k_op_addi_16_aw(void); +void m68k_op_addi_16_al(void); +void m68k_op_addi_32_d(void); +void m68k_op_addi_32_ai(void); +void m68k_op_addi_32_pi(void); +void m68k_op_addi_32_pd(void); +void m68k_op_addi_32_di(void); +void m68k_op_addi_32_ix(void); +void m68k_op_addi_32_aw(void); +void m68k_op_addi_32_al(void); +void m68k_op_addq_8_d(void); +void m68k_op_addq_8_ai(void); +void m68k_op_addq_8_pi(void); +void m68k_op_addq_8_pi7(void); +void m68k_op_addq_8_pd(void); +void m68k_op_addq_8_pd7(void); +void m68k_op_addq_8_di(void); +void m68k_op_addq_8_ix(void); +void m68k_op_addq_8_aw(void); +void m68k_op_addq_8_al(void); +void m68k_op_addq_16_d(void); +void m68k_op_addq_16_a(void); +void m68k_op_addq_16_ai(void); +void m68k_op_addq_16_pi(void); +void m68k_op_addq_16_pd(void); +void m68k_op_addq_16_di(void); +void m68k_op_addq_16_ix(void); +void m68k_op_addq_16_aw(void); +void m68k_op_addq_16_al(void); +void m68k_op_addq_32_d(void); +void m68k_op_addq_32_a(void); +void m68k_op_addq_32_ai(void); +void m68k_op_addq_32_pi(void); +void m68k_op_addq_32_pd(void); +void m68k_op_addq_32_di(void); +void m68k_op_addq_32_ix(void); +void m68k_op_addq_32_aw(void); +void m68k_op_addq_32_al(void); +void m68k_op_addx_8_rr(void); +void m68k_op_addx_16_rr(void); +void m68k_op_addx_32_rr(void); +void m68k_op_addx_8_mm_ax7(void); +void m68k_op_addx_8_mm_ay7(void); +void m68k_op_addx_8_mm_axy7(void); +void m68k_op_addx_8_mm(void); +void m68k_op_addx_16_mm(void); +void m68k_op_addx_32_mm(void); +void m68k_op_and_8_er_d(void); +void m68k_op_and_8_er_ai(void); +void m68k_op_and_8_er_pi(void); +void m68k_op_and_8_er_pi7(void); +void m68k_op_and_8_er_pd(void); +void m68k_op_and_8_er_pd7(void); +void m68k_op_and_8_er_di(void); +void m68k_op_and_8_er_ix(void); +void m68k_op_and_8_er_aw(void); +void m68k_op_and_8_er_al(void); +void m68k_op_and_8_er_pcdi(void); +void m68k_op_and_8_er_pcix(void); +void m68k_op_and_8_er_i(void); +void m68k_op_and_16_er_d(void); +void m68k_op_and_16_er_ai(void); +void m68k_op_and_16_er_pi(void); +void m68k_op_and_16_er_pd(void); +void m68k_op_and_16_er_di(void); +void m68k_op_and_16_er_ix(void); +void m68k_op_and_16_er_aw(void); +void m68k_op_and_16_er_al(void); +void m68k_op_and_16_er_pcdi(void); +void m68k_op_and_16_er_pcix(void); +void m68k_op_and_16_er_i(void); +void m68k_op_and_32_er_d(void); +void m68k_op_and_32_er_ai(void); +void m68k_op_and_32_er_pi(void); +void m68k_op_and_32_er_pd(void); +void m68k_op_and_32_er_di(void); +void m68k_op_and_32_er_ix(void); +void m68k_op_and_32_er_aw(void); +void m68k_op_and_32_er_al(void); +void m68k_op_and_32_er_pcdi(void); +void m68k_op_and_32_er_pcix(void); +void m68k_op_and_32_er_i(void); +void m68k_op_and_8_re_ai(void); +void m68k_op_and_8_re_pi(void); +void m68k_op_and_8_re_pi7(void); +void m68k_op_and_8_re_pd(void); +void m68k_op_and_8_re_pd7(void); +void m68k_op_and_8_re_di(void); +void m68k_op_and_8_re_ix(void); +void m68k_op_and_8_re_aw(void); +void m68k_op_and_8_re_al(void); +void m68k_op_and_16_re_ai(void); +void m68k_op_and_16_re_pi(void); +void m68k_op_and_16_re_pd(void); +void m68k_op_and_16_re_di(void); +void m68k_op_and_16_re_ix(void); +void m68k_op_and_16_re_aw(void); +void m68k_op_and_16_re_al(void); +void m68k_op_and_32_re_ai(void); +void m68k_op_and_32_re_pi(void); +void m68k_op_and_32_re_pd(void); +void m68k_op_and_32_re_di(void); +void m68k_op_and_32_re_ix(void); +void m68k_op_and_32_re_aw(void); +void m68k_op_and_32_re_al(void); +void m68k_op_andi_8_d(void); +void m68k_op_andi_8_ai(void); +void m68k_op_andi_8_pi(void); +void m68k_op_andi_8_pi7(void); +void m68k_op_andi_8_pd(void); +void m68k_op_andi_8_pd7(void); +void m68k_op_andi_8_di(void); +void m68k_op_andi_8_ix(void); +void m68k_op_andi_8_aw(void); +void m68k_op_andi_8_al(void); +void m68k_op_andi_16_d(void); +void m68k_op_andi_16_ai(void); +void m68k_op_andi_16_pi(void); +void m68k_op_andi_16_pd(void); +void m68k_op_andi_16_di(void); +void m68k_op_andi_16_ix(void); +void m68k_op_andi_16_aw(void); +void m68k_op_andi_16_al(void); +void m68k_op_andi_32_d(void); +void m68k_op_andi_32_ai(void); +void m68k_op_andi_32_pi(void); +void m68k_op_andi_32_pd(void); +void m68k_op_andi_32_di(void); +void m68k_op_andi_32_ix(void); +void m68k_op_andi_32_aw(void); +void m68k_op_andi_32_al(void); +void m68k_op_andi_16_toc(void); +void m68k_op_andi_16_tos(void); +void m68k_op_asr_8_s(void); +void m68k_op_asr_16_s(void); +void m68k_op_asr_32_s(void); +void m68k_op_asr_8_r(void); +void m68k_op_asr_16_r(void); +void m68k_op_asr_32_r(void); +void m68k_op_asr_16_ai(void); +void m68k_op_asr_16_pi(void); +void m68k_op_asr_16_pd(void); +void m68k_op_asr_16_di(void); +void m68k_op_asr_16_ix(void); +void m68k_op_asr_16_aw(void); +void m68k_op_asr_16_al(void); +void m68k_op_asl_8_s(void); +void m68k_op_asl_16_s(void); +void m68k_op_asl_32_s(void); +void m68k_op_asl_8_r(void); +void m68k_op_asl_16_r(void); +void m68k_op_asl_32_r(void); +void m68k_op_asl_16_ai(void); +void m68k_op_asl_16_pi(void); +void m68k_op_asl_16_pd(void); +void m68k_op_asl_16_di(void); +void m68k_op_asl_16_ix(void); +void m68k_op_asl_16_aw(void); +void m68k_op_asl_16_al(void); +void m68k_op_bhi_8(void); +void m68k_op_bls_8(void); +void m68k_op_bcc_8(void); +void m68k_op_bcs_8(void); +void m68k_op_bne_8(void); +void m68k_op_beq_8(void); +void m68k_op_bvc_8(void); +void m68k_op_bvs_8(void); +void m68k_op_bpl_8(void); +void m68k_op_bmi_8(void); +void m68k_op_bge_8(void); +void m68k_op_blt_8(void); +void m68k_op_bgt_8(void); +void m68k_op_ble_8(void); +void m68k_op_bhi_16(void); +void m68k_op_bls_16(void); +void m68k_op_bcc_16(void); +void m68k_op_bcs_16(void); +void m68k_op_bne_16(void); +void m68k_op_beq_16(void); +void m68k_op_bvc_16(void); +void m68k_op_bvs_16(void); +void m68k_op_bpl_16(void); +void m68k_op_bmi_16(void); +void m68k_op_bge_16(void); +void m68k_op_blt_16(void); +void m68k_op_bgt_16(void); +void m68k_op_ble_16(void); +void m68k_op_bhi_32(void); +void m68k_op_bls_32(void); +void m68k_op_bcc_32(void); +void m68k_op_bcs_32(void); +void m68k_op_bne_32(void); +void m68k_op_beq_32(void); +void m68k_op_bvc_32(void); +void m68k_op_bvs_32(void); +void m68k_op_bpl_32(void); +void m68k_op_bmi_32(void); +void m68k_op_bge_32(void); +void m68k_op_blt_32(void); +void m68k_op_bgt_32(void); +void m68k_op_ble_32(void); +void m68k_op_bchg_32_r_d(void); +void m68k_op_bchg_8_r_ai(void); +void m68k_op_bchg_8_r_pi(void); +void m68k_op_bchg_8_r_pi7(void); +void m68k_op_bchg_8_r_pd(void); +void m68k_op_bchg_8_r_pd7(void); +void m68k_op_bchg_8_r_di(void); +void m68k_op_bchg_8_r_ix(void); +void m68k_op_bchg_8_r_aw(void); +void m68k_op_bchg_8_r_al(void); +void m68k_op_bchg_32_s_d(void); +void m68k_op_bchg_8_s_ai(void); +void m68k_op_bchg_8_s_pi(void); +void m68k_op_bchg_8_s_pi7(void); +void m68k_op_bchg_8_s_pd(void); +void m68k_op_bchg_8_s_pd7(void); +void m68k_op_bchg_8_s_di(void); +void m68k_op_bchg_8_s_ix(void); +void m68k_op_bchg_8_s_aw(void); +void m68k_op_bchg_8_s_al(void); +void m68k_op_bclr_32_r_d(void); +void m68k_op_bclr_8_r_ai(void); +void m68k_op_bclr_8_r_pi(void); +void m68k_op_bclr_8_r_pi7(void); +void m68k_op_bclr_8_r_pd(void); +void m68k_op_bclr_8_r_pd7(void); +void m68k_op_bclr_8_r_di(void); +void m68k_op_bclr_8_r_ix(void); +void m68k_op_bclr_8_r_aw(void); +void m68k_op_bclr_8_r_al(void); +void m68k_op_bclr_32_s_d(void); +void m68k_op_bclr_8_s_ai(void); +void m68k_op_bclr_8_s_pi(void); +void m68k_op_bclr_8_s_pi7(void); +void m68k_op_bclr_8_s_pd(void); +void m68k_op_bclr_8_s_pd7(void); +void m68k_op_bclr_8_s_di(void); +void m68k_op_bclr_8_s_ix(void); +void m68k_op_bclr_8_s_aw(void); +void m68k_op_bclr_8_s_al(void); +void m68k_op_bfchg_32_d(void); +void m68k_op_bfchg_32_ai(void); +void m68k_op_bfchg_32_di(void); +void m68k_op_bfchg_32_ix(void); +void m68k_op_bfchg_32_aw(void); +void m68k_op_bfchg_32_al(void); +void m68k_op_bfclr_32_d(void); +void m68k_op_bfclr_32_ai(void); +void m68k_op_bfclr_32_di(void); +void m68k_op_bfclr_32_ix(void); +void m68k_op_bfclr_32_aw(void); +void m68k_op_bfclr_32_al(void); +void m68k_op_bfexts_32_d(void); +void m68k_op_bfexts_32_ai(void); +void m68k_op_bfexts_32_di(void); +void m68k_op_bfexts_32_ix(void); +void m68k_op_bfexts_32_aw(void); +void m68k_op_bfexts_32_al(void); +void m68k_op_bfexts_32_pcdi(void); +void m68k_op_bfexts_32_pcix(void); +void m68k_op_bfextu_32_d(void); +void m68k_op_bfextu_32_ai(void); +void m68k_op_bfextu_32_di(void); +void m68k_op_bfextu_32_ix(void); +void m68k_op_bfextu_32_aw(void); +void m68k_op_bfextu_32_al(void); +void m68k_op_bfextu_32_pcdi(void); +void m68k_op_bfextu_32_pcix(void); +void m68k_op_bfffo_32_d(void); +void m68k_op_bfffo_32_ai(void); +void m68k_op_bfffo_32_di(void); +void m68k_op_bfffo_32_ix(void); +void m68k_op_bfffo_32_aw(void); +void m68k_op_bfffo_32_al(void); +void m68k_op_bfffo_32_pcdi(void); +void m68k_op_bfffo_32_pcix(void); +void m68k_op_bfins_32_d(void); +void m68k_op_bfins_32_ai(void); +void m68k_op_bfins_32_di(void); +void m68k_op_bfins_32_ix(void); +void m68k_op_bfins_32_aw(void); +void m68k_op_bfins_32_al(void); +void m68k_op_bfset_32_d(void); +void m68k_op_bfset_32_ai(void); +void m68k_op_bfset_32_di(void); +void m68k_op_bfset_32_ix(void); +void m68k_op_bfset_32_aw(void); +void m68k_op_bfset_32_al(void); +void m68k_op_bftst_32_d(void); +void m68k_op_bftst_32_ai(void); +void m68k_op_bftst_32_di(void); +void m68k_op_bftst_32_ix(void); +void m68k_op_bftst_32_aw(void); +void m68k_op_bftst_32_al(void); +void m68k_op_bftst_32_pcdi(void); +void m68k_op_bftst_32_pcix(void); +void m68k_op_bkpt(void); +void m68k_op_bra_8(void); +void m68k_op_bra_16(void); +void m68k_op_bra_32(void); +void m68k_op_bset_32_r_d(void); +void m68k_op_bset_8_r_ai(void); +void m68k_op_bset_8_r_pi(void); +void m68k_op_bset_8_r_pi7(void); +void m68k_op_bset_8_r_pd(void); +void m68k_op_bset_8_r_pd7(void); +void m68k_op_bset_8_r_di(void); +void m68k_op_bset_8_r_ix(void); +void m68k_op_bset_8_r_aw(void); +void m68k_op_bset_8_r_al(void); +void m68k_op_bset_32_s_d(void); +void m68k_op_bset_8_s_ai(void); +void m68k_op_bset_8_s_pi(void); +void m68k_op_bset_8_s_pi7(void); +void m68k_op_bset_8_s_pd(void); +void m68k_op_bset_8_s_pd7(void); +void m68k_op_bset_8_s_di(void); +void m68k_op_bset_8_s_ix(void); +void m68k_op_bset_8_s_aw(void); +void m68k_op_bset_8_s_al(void); +void m68k_op_bsr_8(void); +void m68k_op_bsr_16(void); +void m68k_op_bsr_32(void); +void m68k_op_btst_32_r_d(void); +void m68k_op_btst_8_r_ai(void); +void m68k_op_btst_8_r_pi(void); +void m68k_op_btst_8_r_pi7(void); +void m68k_op_btst_8_r_pd(void); +void m68k_op_btst_8_r_pd7(void); +void m68k_op_btst_8_r_di(void); +void m68k_op_btst_8_r_ix(void); +void m68k_op_btst_8_r_aw(void); +void m68k_op_btst_8_r_al(void); +void m68k_op_btst_8_r_pcdi(void); +void m68k_op_btst_8_r_pcix(void); +void m68k_op_btst_8_r_i(void); +void m68k_op_btst_32_s_d(void); +void m68k_op_btst_8_s_ai(void); +void m68k_op_btst_8_s_pi(void); +void m68k_op_btst_8_s_pi7(void); +void m68k_op_btst_8_s_pd(void); +void m68k_op_btst_8_s_pd7(void); +void m68k_op_btst_8_s_di(void); +void m68k_op_btst_8_s_ix(void); +void m68k_op_btst_8_s_aw(void); +void m68k_op_btst_8_s_al(void); +void m68k_op_btst_8_s_pcdi(void); +void m68k_op_btst_8_s_pcix(void); +void m68k_op_callm_32_ai(void); +void m68k_op_callm_32_di(void); +void m68k_op_callm_32_ix(void); +void m68k_op_callm_32_aw(void); +void m68k_op_callm_32_al(void); +void m68k_op_callm_32_pcdi(void); +void m68k_op_callm_32_pcix(void); +void m68k_op_cas_8_ai(void); +void m68k_op_cas_8_pi(void); +void m68k_op_cas_8_pi7(void); +void m68k_op_cas_8_pd(void); +void m68k_op_cas_8_pd7(void); +void m68k_op_cas_8_di(void); +void m68k_op_cas_8_ix(void); +void m68k_op_cas_8_aw(void); +void m68k_op_cas_8_al(void); +void m68k_op_cas_16_ai(void); +void m68k_op_cas_16_pi(void); +void m68k_op_cas_16_pd(void); +void m68k_op_cas_16_di(void); +void m68k_op_cas_16_ix(void); +void m68k_op_cas_16_aw(void); +void m68k_op_cas_16_al(void); +void m68k_op_cas_32_ai(void); +void m68k_op_cas_32_pi(void); +void m68k_op_cas_32_pd(void); +void m68k_op_cas_32_di(void); +void m68k_op_cas_32_ix(void); +void m68k_op_cas_32_aw(void); +void m68k_op_cas_32_al(void); +void m68k_op_cas2_16(void); +void m68k_op_cas2_32(void); +void m68k_op_chk_16_d(void); +void m68k_op_chk_16_ai(void); +void m68k_op_chk_16_pi(void); +void m68k_op_chk_16_pd(void); +void m68k_op_chk_16_di(void); +void m68k_op_chk_16_ix(void); +void m68k_op_chk_16_aw(void); +void m68k_op_chk_16_al(void); +void m68k_op_chk_16_pcdi(void); +void m68k_op_chk_16_pcix(void); +void m68k_op_chk_16_i(void); +void m68k_op_chk_32_d(void); +void m68k_op_chk_32_ai(void); +void m68k_op_chk_32_pi(void); +void m68k_op_chk_32_pd(void); +void m68k_op_chk_32_di(void); +void m68k_op_chk_32_ix(void); +void m68k_op_chk_32_aw(void); +void m68k_op_chk_32_al(void); +void m68k_op_chk_32_pcdi(void); +void m68k_op_chk_32_pcix(void); +void m68k_op_chk_32_i(void); +void m68k_op_chk2cmp2_8_pcdi(void); +void m68k_op_chk2cmp2_8_pcix(void); +void m68k_op_chk2cmp2_8_ai(void); +void m68k_op_chk2cmp2_8_di(void); +void m68k_op_chk2cmp2_8_ix(void); +void m68k_op_chk2cmp2_8_aw(void); +void m68k_op_chk2cmp2_8_al(void); +void m68k_op_chk2cmp2_16_pcdi(void); +void m68k_op_chk2cmp2_16_pcix(void); +void m68k_op_chk2cmp2_16_ai(void); +void m68k_op_chk2cmp2_16_di(void); +void m68k_op_chk2cmp2_16_ix(void); +void m68k_op_chk2cmp2_16_aw(void); +void m68k_op_chk2cmp2_16_al(void); +void m68k_op_chk2cmp2_32_pcdi(void); +void m68k_op_chk2cmp2_32_pcix(void); +void m68k_op_chk2cmp2_32_ai(void); +void m68k_op_chk2cmp2_32_di(void); +void m68k_op_chk2cmp2_32_ix(void); +void m68k_op_chk2cmp2_32_aw(void); +void m68k_op_chk2cmp2_32_al(void); +void m68k_op_clr_8_d(void); +void m68k_op_clr_8_ai(void); +void m68k_op_clr_8_pi(void); +void m68k_op_clr_8_pi7(void); +void m68k_op_clr_8_pd(void); +void m68k_op_clr_8_pd7(void); +void m68k_op_clr_8_di(void); +void m68k_op_clr_8_ix(void); +void m68k_op_clr_8_aw(void); +void m68k_op_clr_8_al(void); +void m68k_op_clr_16_d(void); +void m68k_op_clr_16_ai(void); +void m68k_op_clr_16_pi(void); +void m68k_op_clr_16_pd(void); +void m68k_op_clr_16_di(void); +void m68k_op_clr_16_ix(void); +void m68k_op_clr_16_aw(void); +void m68k_op_clr_16_al(void); +void m68k_op_clr_32_d(void); +void m68k_op_clr_32_ai(void); +void m68k_op_clr_32_pi(void); +void m68k_op_clr_32_pd(void); +void m68k_op_clr_32_di(void); +void m68k_op_clr_32_ix(void); +void m68k_op_clr_32_aw(void); +void m68k_op_clr_32_al(void); +void m68k_op_cmp_8_d(void); +void m68k_op_cmp_8_ai(void); +void m68k_op_cmp_8_pi(void); +void m68k_op_cmp_8_pi7(void); +void m68k_op_cmp_8_pd(void); +void m68k_op_cmp_8_pd7(void); +void m68k_op_cmp_8_di(void); +void m68k_op_cmp_8_ix(void); +void m68k_op_cmp_8_aw(void); +void m68k_op_cmp_8_al(void); +void m68k_op_cmp_8_pcdi(void); +void m68k_op_cmp_8_pcix(void); +void m68k_op_cmp_8_i(void); +void m68k_op_cmp_16_d(void); +void m68k_op_cmp_16_a(void); +void m68k_op_cmp_16_ai(void); +void m68k_op_cmp_16_pi(void); +void m68k_op_cmp_16_pd(void); +void m68k_op_cmp_16_di(void); +void m68k_op_cmp_16_ix(void); +void m68k_op_cmp_16_aw(void); +void m68k_op_cmp_16_al(void); +void m68k_op_cmp_16_pcdi(void); +void m68k_op_cmp_16_pcix(void); +void m68k_op_cmp_16_i(void); +void m68k_op_cmp_32_d(void); +void m68k_op_cmp_32_a(void); +void m68k_op_cmp_32_ai(void); +void m68k_op_cmp_32_pi(void); +void m68k_op_cmp_32_pd(void); +void m68k_op_cmp_32_di(void); +void m68k_op_cmp_32_ix(void); +void m68k_op_cmp_32_aw(void); +void m68k_op_cmp_32_al(void); +void m68k_op_cmp_32_pcdi(void); +void m68k_op_cmp_32_pcix(void); +void m68k_op_cmp_32_i(void); +void m68k_op_cmpa_16_d(void); +void m68k_op_cmpa_16_a(void); +void m68k_op_cmpa_16_ai(void); +void m68k_op_cmpa_16_pi(void); +void m68k_op_cmpa_16_pd(void); +void m68k_op_cmpa_16_di(void); +void m68k_op_cmpa_16_ix(void); +void m68k_op_cmpa_16_aw(void); +void m68k_op_cmpa_16_al(void); +void m68k_op_cmpa_16_pcdi(void); +void m68k_op_cmpa_16_pcix(void); +void m68k_op_cmpa_16_i(void); +void m68k_op_cmpa_32_d(void); +void m68k_op_cmpa_32_a(void); +void m68k_op_cmpa_32_ai(void); +void m68k_op_cmpa_32_pi(void); +void m68k_op_cmpa_32_pd(void); +void m68k_op_cmpa_32_di(void); +void m68k_op_cmpa_32_ix(void); +void m68k_op_cmpa_32_aw(void); +void m68k_op_cmpa_32_al(void); +void m68k_op_cmpa_32_pcdi(void); +void m68k_op_cmpa_32_pcix(void); +void m68k_op_cmpa_32_i(void); +void m68k_op_cmpi_8_d(void); +void m68k_op_cmpi_8_ai(void); +void m68k_op_cmpi_8_pi(void); +void m68k_op_cmpi_8_pi7(void); +void m68k_op_cmpi_8_pd(void); +void m68k_op_cmpi_8_pd7(void); +void m68k_op_cmpi_8_di(void); +void m68k_op_cmpi_8_ix(void); +void m68k_op_cmpi_8_aw(void); +void m68k_op_cmpi_8_al(void); +void m68k_op_cmpi_8_pcdi(void); +void m68k_op_cmpi_8_pcix(void); +void m68k_op_cmpi_16_d(void); +void m68k_op_cmpi_16_ai(void); +void m68k_op_cmpi_16_pi(void); +void m68k_op_cmpi_16_pd(void); +void m68k_op_cmpi_16_di(void); +void m68k_op_cmpi_16_ix(void); +void m68k_op_cmpi_16_aw(void); +void m68k_op_cmpi_16_al(void); +void m68k_op_cmpi_16_pcdi(void); +void m68k_op_cmpi_16_pcix(void); +void m68k_op_cmpi_32_d(void); +void m68k_op_cmpi_32_ai(void); +void m68k_op_cmpi_32_pi(void); +void m68k_op_cmpi_32_pd(void); +void m68k_op_cmpi_32_di(void); +void m68k_op_cmpi_32_ix(void); +void m68k_op_cmpi_32_aw(void); +void m68k_op_cmpi_32_al(void); +void m68k_op_cmpi_32_pcdi(void); +void m68k_op_cmpi_32_pcix(void); +void m68k_op_cmpm_8_ax7(void); +void m68k_op_cmpm_8_ay7(void); +void m68k_op_cmpm_8_axy7(void); +void m68k_op_cmpm_8(void); +void m68k_op_cmpm_16(void); +void m68k_op_cmpm_32(void); +void m68k_op_cpbcc_32(void); +void m68k_op_cpdbcc_32(void); +void m68k_op_cpgen_32(void); +void m68k_op_cpscc_32(void); +void m68k_op_cptrapcc_32(void); +void m68k_op_dbt_16(void); +void m68k_op_dbf_16(void); +void m68k_op_dbhi_16(void); +void m68k_op_dbls_16(void); +void m68k_op_dbcc_16(void); +void m68k_op_dbcs_16(void); +void m68k_op_dbne_16(void); +void m68k_op_dbeq_16(void); +void m68k_op_dbvc_16(void); +void m68k_op_dbvs_16(void); +void m68k_op_dbpl_16(void); +void m68k_op_dbmi_16(void); +void m68k_op_dbge_16(void); +void m68k_op_dblt_16(void); +void m68k_op_dbgt_16(void); +void m68k_op_dble_16(void); +void m68k_op_divs_16_d(void); +void m68k_op_divs_16_ai(void); +void m68k_op_divs_16_pi(void); +void m68k_op_divs_16_pd(void); +void m68k_op_divs_16_di(void); +void m68k_op_divs_16_ix(void); +void m68k_op_divs_16_aw(void); +void m68k_op_divs_16_al(void); +void m68k_op_divs_16_pcdi(void); +void m68k_op_divs_16_pcix(void); +void m68k_op_divs_16_i(void); +void m68k_op_divu_16_d(void); +void m68k_op_divu_16_ai(void); +void m68k_op_divu_16_pi(void); +void m68k_op_divu_16_pd(void); +void m68k_op_divu_16_di(void); +void m68k_op_divu_16_ix(void); +void m68k_op_divu_16_aw(void); +void m68k_op_divu_16_al(void); +void m68k_op_divu_16_pcdi(void); +void m68k_op_divu_16_pcix(void); +void m68k_op_divu_16_i(void); +void m68k_op_divl_32_d(void); +void m68k_op_divl_32_ai(void); +void m68k_op_divl_32_pi(void); +void m68k_op_divl_32_pd(void); +void m68k_op_divl_32_di(void); +void m68k_op_divl_32_ix(void); +void m68k_op_divl_32_aw(void); +void m68k_op_divl_32_al(void); +void m68k_op_divl_32_pcdi(void); +void m68k_op_divl_32_pcix(void); +void m68k_op_divl_32_i(void); +void m68k_op_eor_8_d(void); +void m68k_op_eor_8_ai(void); +void m68k_op_eor_8_pi(void); +void m68k_op_eor_8_pi7(void); +void m68k_op_eor_8_pd(void); +void m68k_op_eor_8_pd7(void); +void m68k_op_eor_8_di(void); +void m68k_op_eor_8_ix(void); +void m68k_op_eor_8_aw(void); +void m68k_op_eor_8_al(void); +void m68k_op_eor_16_d(void); +void m68k_op_eor_16_ai(void); +void m68k_op_eor_16_pi(void); +void m68k_op_eor_16_pd(void); +void m68k_op_eor_16_di(void); +void m68k_op_eor_16_ix(void); +void m68k_op_eor_16_aw(void); +void m68k_op_eor_16_al(void); +void m68k_op_eor_32_d(void); +void m68k_op_eor_32_ai(void); +void m68k_op_eor_32_pi(void); +void m68k_op_eor_32_pd(void); +void m68k_op_eor_32_di(void); +void m68k_op_eor_32_ix(void); +void m68k_op_eor_32_aw(void); +void m68k_op_eor_32_al(void); +void m68k_op_eori_8_d(void); +void m68k_op_eori_8_ai(void); +void m68k_op_eori_8_pi(void); +void m68k_op_eori_8_pi7(void); +void m68k_op_eori_8_pd(void); +void m68k_op_eori_8_pd7(void); +void m68k_op_eori_8_di(void); +void m68k_op_eori_8_ix(void); +void m68k_op_eori_8_aw(void); +void m68k_op_eori_8_al(void); +void m68k_op_eori_16_d(void); +void m68k_op_eori_16_ai(void); +void m68k_op_eori_16_pi(void); +void m68k_op_eori_16_pd(void); +void m68k_op_eori_16_di(void); +void m68k_op_eori_16_ix(void); +void m68k_op_eori_16_aw(void); +void m68k_op_eori_16_al(void); +void m68k_op_eori_32_d(void); +void m68k_op_eori_32_ai(void); +void m68k_op_eori_32_pi(void); +void m68k_op_eori_32_pd(void); +void m68k_op_eori_32_di(void); +void m68k_op_eori_32_ix(void); +void m68k_op_eori_32_aw(void); +void m68k_op_eori_32_al(void); +void m68k_op_eori_16_toc(void); +void m68k_op_eori_16_tos(void); +void m68k_op_exg_32_dd(void); +void m68k_op_exg_32_aa(void); +void m68k_op_exg_32_da(void); +void m68k_op_ext_16(void); +void m68k_op_ext_32(void); +void m68k_op_extb_32(void); +void m68k_op_illegal(void); +void m68k_op_jmp_32_ai(void); +void m68k_op_jmp_32_di(void); +void m68k_op_jmp_32_ix(void); +void m68k_op_jmp_32_aw(void); +void m68k_op_jmp_32_al(void); +void m68k_op_jmp_32_pcdi(void); +void m68k_op_jmp_32_pcix(void); +void m68k_op_jsr_32_ai(void); +void m68k_op_jsr_32_di(void); +void m68k_op_jsr_32_ix(void); +void m68k_op_jsr_32_aw(void); +void m68k_op_jsr_32_al(void); +void m68k_op_jsr_32_pcdi(void); +void m68k_op_jsr_32_pcix(void); +void m68k_op_lea_32_ai(void); +void m68k_op_lea_32_di(void); +void m68k_op_lea_32_ix(void); +void m68k_op_lea_32_aw(void); +void m68k_op_lea_32_al(void); +void m68k_op_lea_32_pcdi(void); +void m68k_op_lea_32_pcix(void); +void m68k_op_link_16_a7(void); +void m68k_op_link_16(void); +void m68k_op_link_32_a7(void); +void m68k_op_link_32(void); +void m68k_op_lsr_8_s(void); +void m68k_op_lsr_16_s(void); +void m68k_op_lsr_32_s(void); +void m68k_op_lsr_8_r(void); +void m68k_op_lsr_16_r(void); +void m68k_op_lsr_32_r(void); +void m68k_op_lsr_16_ai(void); +void m68k_op_lsr_16_pi(void); +void m68k_op_lsr_16_pd(void); +void m68k_op_lsr_16_di(void); +void m68k_op_lsr_16_ix(void); +void m68k_op_lsr_16_aw(void); +void m68k_op_lsr_16_al(void); +void m68k_op_lsl_8_s(void); +void m68k_op_lsl_16_s(void); +void m68k_op_lsl_32_s(void); +void m68k_op_lsl_8_r(void); +void m68k_op_lsl_16_r(void); +void m68k_op_lsl_32_r(void); +void m68k_op_lsl_16_ai(void); +void m68k_op_lsl_16_pi(void); +void m68k_op_lsl_16_pd(void); +void m68k_op_lsl_16_di(void); +void m68k_op_lsl_16_ix(void); +void m68k_op_lsl_16_aw(void); +void m68k_op_lsl_16_al(void); +void m68k_op_move_8_d_d(void); +void m68k_op_move_8_d_ai(void); +void m68k_op_move_8_d_pi(void); +void m68k_op_move_8_d_pi7(void); +void m68k_op_move_8_d_pd(void); +void m68k_op_move_8_d_pd7(void); +void m68k_op_move_8_d_di(void); +void m68k_op_move_8_d_ix(void); +void m68k_op_move_8_d_aw(void); +void m68k_op_move_8_d_al(void); +void m68k_op_move_8_d_pcdi(void); +void m68k_op_move_8_d_pcix(void); +void m68k_op_move_8_d_i(void); +void m68k_op_move_8_ai_d(void); +void m68k_op_move_8_ai_ai(void); +void m68k_op_move_8_ai_pi(void); +void m68k_op_move_8_ai_pi7(void); +void m68k_op_move_8_ai_pd(void); +void m68k_op_move_8_ai_pd7(void); +void m68k_op_move_8_ai_di(void); +void m68k_op_move_8_ai_ix(void); +void m68k_op_move_8_ai_aw(void); +void m68k_op_move_8_ai_al(void); +void m68k_op_move_8_ai_pcdi(void); +void m68k_op_move_8_ai_pcix(void); +void m68k_op_move_8_ai_i(void); +void m68k_op_move_8_pi7_d(void); +void m68k_op_move_8_pi_d(void); +void m68k_op_move_8_pi7_ai(void); +void m68k_op_move_8_pi7_pi(void); +void m68k_op_move_8_pi7_pi7(void); +void m68k_op_move_8_pi7_pd(void); +void m68k_op_move_8_pi7_pd7(void); +void m68k_op_move_8_pi7_di(void); +void m68k_op_move_8_pi7_ix(void); +void m68k_op_move_8_pi7_aw(void); +void m68k_op_move_8_pi7_al(void); +void m68k_op_move_8_pi7_pcdi(void); +void m68k_op_move_8_pi7_pcix(void); +void m68k_op_move_8_pi7_i(void); +void m68k_op_move_8_pi_ai(void); +void m68k_op_move_8_pi_pi(void); +void m68k_op_move_8_pi_pi7(void); +void m68k_op_move_8_pi_pd(void); +void m68k_op_move_8_pi_pd7(void); +void m68k_op_move_8_pi_di(void); +void m68k_op_move_8_pi_ix(void); +void m68k_op_move_8_pi_aw(void); +void m68k_op_move_8_pi_al(void); +void m68k_op_move_8_pi_pcdi(void); +void m68k_op_move_8_pi_pcix(void); +void m68k_op_move_8_pi_i(void); +void m68k_op_move_8_pd7_d(void); +void m68k_op_move_8_pd_d(void); +void m68k_op_move_8_pd7_ai(void); +void m68k_op_move_8_pd7_pi(void); +void m68k_op_move_8_pd7_pi7(void); +void m68k_op_move_8_pd7_pd(void); +void m68k_op_move_8_pd7_pd7(void); +void m68k_op_move_8_pd7_di(void); +void m68k_op_move_8_pd7_ix(void); +void m68k_op_move_8_pd7_aw(void); +void m68k_op_move_8_pd7_al(void); +void m68k_op_move_8_pd7_pcdi(void); +void m68k_op_move_8_pd7_pcix(void); +void m68k_op_move_8_pd7_i(void); +void m68k_op_move_8_pd_ai(void); +void m68k_op_move_8_pd_pi(void); +void m68k_op_move_8_pd_pi7(void); +void m68k_op_move_8_pd_pd(void); +void m68k_op_move_8_pd_pd7(void); +void m68k_op_move_8_pd_di(void); +void m68k_op_move_8_pd_ix(void); +void m68k_op_move_8_pd_aw(void); +void m68k_op_move_8_pd_al(void); +void m68k_op_move_8_pd_pcdi(void); +void m68k_op_move_8_pd_pcix(void); +void m68k_op_move_8_pd_i(void); +void m68k_op_move_8_di_d(void); +void m68k_op_move_8_di_ai(void); +void m68k_op_move_8_di_pi(void); +void m68k_op_move_8_di_pi7(void); +void m68k_op_move_8_di_pd(void); +void m68k_op_move_8_di_pd7(void); +void m68k_op_move_8_di_di(void); +void m68k_op_move_8_di_ix(void); +void m68k_op_move_8_di_aw(void); +void m68k_op_move_8_di_al(void); +void m68k_op_move_8_di_pcdi(void); +void m68k_op_move_8_di_pcix(void); +void m68k_op_move_8_di_i(void); +void m68k_op_move_8_ix_d(void); +void m68k_op_move_8_ix_ai(void); +void m68k_op_move_8_ix_pi(void); +void m68k_op_move_8_ix_pi7(void); +void m68k_op_move_8_ix_pd(void); +void m68k_op_move_8_ix_pd7(void); +void m68k_op_move_8_ix_di(void); +void m68k_op_move_8_ix_ix(void); +void m68k_op_move_8_ix_aw(void); +void m68k_op_move_8_ix_al(void); +void m68k_op_move_8_ix_pcdi(void); +void m68k_op_move_8_ix_pcix(void); +void m68k_op_move_8_ix_i(void); +void m68k_op_move_8_aw_d(void); +void m68k_op_move_8_aw_ai(void); +void m68k_op_move_8_aw_pi(void); +void m68k_op_move_8_aw_pi7(void); +void m68k_op_move_8_aw_pd(void); +void m68k_op_move_8_aw_pd7(void); +void m68k_op_move_8_aw_di(void); +void m68k_op_move_8_aw_ix(void); +void m68k_op_move_8_aw_aw(void); +void m68k_op_move_8_aw_al(void); +void m68k_op_move_8_aw_pcdi(void); +void m68k_op_move_8_aw_pcix(void); +void m68k_op_move_8_aw_i(void); +void m68k_op_move_8_al_d(void); +void m68k_op_move_8_al_ai(void); +void m68k_op_move_8_al_pi(void); +void m68k_op_move_8_al_pi7(void); +void m68k_op_move_8_al_pd(void); +void m68k_op_move_8_al_pd7(void); +void m68k_op_move_8_al_di(void); +void m68k_op_move_8_al_ix(void); +void m68k_op_move_8_al_aw(void); +void m68k_op_move_8_al_al(void); +void m68k_op_move_8_al_pcdi(void); +void m68k_op_move_8_al_pcix(void); +void m68k_op_move_8_al_i(void); +void m68k_op_move_16_d_d(void); +void m68k_op_move_16_d_a(void); +void m68k_op_move_16_d_ai(void); +void m68k_op_move_16_d_pi(void); +void m68k_op_move_16_d_pd(void); +void m68k_op_move_16_d_di(void); +void m68k_op_move_16_d_ix(void); +void m68k_op_move_16_d_aw(void); +void m68k_op_move_16_d_al(void); +void m68k_op_move_16_d_pcdi(void); +void m68k_op_move_16_d_pcix(void); +void m68k_op_move_16_d_i(void); +void m68k_op_move_16_ai_d(void); +void m68k_op_move_16_ai_a(void); +void m68k_op_move_16_ai_ai(void); +void m68k_op_move_16_ai_pi(void); +void m68k_op_move_16_ai_pd(void); +void m68k_op_move_16_ai_di(void); +void m68k_op_move_16_ai_ix(void); +void m68k_op_move_16_ai_aw(void); +void m68k_op_move_16_ai_al(void); +void m68k_op_move_16_ai_pcdi(void); +void m68k_op_move_16_ai_pcix(void); +void m68k_op_move_16_ai_i(void); +void m68k_op_move_16_pi_d(void); +void m68k_op_move_16_pi_a(void); +void m68k_op_move_16_pi_ai(void); +void m68k_op_move_16_pi_pi(void); +void m68k_op_move_16_pi_pd(void); +void m68k_op_move_16_pi_di(void); +void m68k_op_move_16_pi_ix(void); +void m68k_op_move_16_pi_aw(void); +void m68k_op_move_16_pi_al(void); +void m68k_op_move_16_pi_pcdi(void); +void m68k_op_move_16_pi_pcix(void); +void m68k_op_move_16_pi_i(void); +void m68k_op_move_16_pd_d(void); +void m68k_op_move_16_pd_a(void); +void m68k_op_move_16_pd_ai(void); +void m68k_op_move_16_pd_pi(void); +void m68k_op_move_16_pd_pd(void); +void m68k_op_move_16_pd_di(void); +void m68k_op_move_16_pd_ix(void); +void m68k_op_move_16_pd_aw(void); +void m68k_op_move_16_pd_al(void); +void m68k_op_move_16_pd_pcdi(void); +void m68k_op_move_16_pd_pcix(void); +void m68k_op_move_16_pd_i(void); +void m68k_op_move_16_di_d(void); +void m68k_op_move_16_di_a(void); +void m68k_op_move_16_di_ai(void); +void m68k_op_move_16_di_pi(void); +void m68k_op_move_16_di_pd(void); +void m68k_op_move_16_di_di(void); +void m68k_op_move_16_di_ix(void); +void m68k_op_move_16_di_aw(void); +void m68k_op_move_16_di_al(void); +void m68k_op_move_16_di_pcdi(void); +void m68k_op_move_16_di_pcix(void); +void m68k_op_move_16_di_i(void); +void m68k_op_move_16_ix_d(void); +void m68k_op_move_16_ix_a(void); +void m68k_op_move_16_ix_ai(void); +void m68k_op_move_16_ix_pi(void); +void m68k_op_move_16_ix_pd(void); +void m68k_op_move_16_ix_di(void); +void m68k_op_move_16_ix_ix(void); +void m68k_op_move_16_ix_aw(void); +void m68k_op_move_16_ix_al(void); +void m68k_op_move_16_ix_pcdi(void); +void m68k_op_move_16_ix_pcix(void); +void m68k_op_move_16_ix_i(void); +void m68k_op_move_16_aw_d(void); +void m68k_op_move_16_aw_a(void); +void m68k_op_move_16_aw_ai(void); +void m68k_op_move_16_aw_pi(void); +void m68k_op_move_16_aw_pd(void); +void m68k_op_move_16_aw_di(void); +void m68k_op_move_16_aw_ix(void); +void m68k_op_move_16_aw_aw(void); +void m68k_op_move_16_aw_al(void); +void m68k_op_move_16_aw_pcdi(void); +void m68k_op_move_16_aw_pcix(void); +void m68k_op_move_16_aw_i(void); +void m68k_op_move_16_al_d(void); +void m68k_op_move_16_al_a(void); +void m68k_op_move_16_al_ai(void); +void m68k_op_move_16_al_pi(void); +void m68k_op_move_16_al_pd(void); +void m68k_op_move_16_al_di(void); +void m68k_op_move_16_al_ix(void); +void m68k_op_move_16_al_aw(void); +void m68k_op_move_16_al_al(void); +void m68k_op_move_16_al_pcdi(void); +void m68k_op_move_16_al_pcix(void); +void m68k_op_move_16_al_i(void); +void m68k_op_move_32_d_d(void); +void m68k_op_move_32_d_a(void); +void m68k_op_move_32_d_ai(void); +void m68k_op_move_32_d_pi(void); +void m68k_op_move_32_d_pd(void); +void m68k_op_move_32_d_di(void); +void m68k_op_move_32_d_ix(void); +void m68k_op_move_32_d_aw(void); +void m68k_op_move_32_d_al(void); +void m68k_op_move_32_d_pcdi(void); +void m68k_op_move_32_d_pcix(void); +void m68k_op_move_32_d_i(void); +void m68k_op_move_32_ai_d(void); +void m68k_op_move_32_ai_a(void); +void m68k_op_move_32_ai_ai(void); +void m68k_op_move_32_ai_pi(void); +void m68k_op_move_32_ai_pd(void); +void m68k_op_move_32_ai_di(void); +void m68k_op_move_32_ai_ix(void); +void m68k_op_move_32_ai_aw(void); +void m68k_op_move_32_ai_al(void); +void m68k_op_move_32_ai_pcdi(void); +void m68k_op_move_32_ai_pcix(void); +void m68k_op_move_32_ai_i(void); +void m68k_op_move_32_pi_d(void); +void m68k_op_move_32_pi_a(void); +void m68k_op_move_32_pi_ai(void); +void m68k_op_move_32_pi_pi(void); +void m68k_op_move_32_pi_pd(void); +void m68k_op_move_32_pi_di(void); +void m68k_op_move_32_pi_ix(void); +void m68k_op_move_32_pi_aw(void); +void m68k_op_move_32_pi_al(void); +void m68k_op_move_32_pi_pcdi(void); +void m68k_op_move_32_pi_pcix(void); +void m68k_op_move_32_pi_i(void); +void m68k_op_move_32_pd_d(void); +void m68k_op_move_32_pd_a(void); +void m68k_op_move_32_pd_ai(void); +void m68k_op_move_32_pd_pi(void); +void m68k_op_move_32_pd_pd(void); +void m68k_op_move_32_pd_di(void); +void m68k_op_move_32_pd_ix(void); +void m68k_op_move_32_pd_aw(void); +void m68k_op_move_32_pd_al(void); +void m68k_op_move_32_pd_pcdi(void); +void m68k_op_move_32_pd_pcix(void); +void m68k_op_move_32_pd_i(void); +void m68k_op_move_32_di_d(void); +void m68k_op_move_32_di_a(void); +void m68k_op_move_32_di_ai(void); +void m68k_op_move_32_di_pi(void); +void m68k_op_move_32_di_pd(void); +void m68k_op_move_32_di_di(void); +void m68k_op_move_32_di_ix(void); +void m68k_op_move_32_di_aw(void); +void m68k_op_move_32_di_al(void); +void m68k_op_move_32_di_pcdi(void); +void m68k_op_move_32_di_pcix(void); +void m68k_op_move_32_di_i(void); +void m68k_op_move_32_ix_d(void); +void m68k_op_move_32_ix_a(void); +void m68k_op_move_32_ix_ai(void); +void m68k_op_move_32_ix_pi(void); +void m68k_op_move_32_ix_pd(void); +void m68k_op_move_32_ix_di(void); +void m68k_op_move_32_ix_ix(void); +void m68k_op_move_32_ix_aw(void); +void m68k_op_move_32_ix_al(void); +void m68k_op_move_32_ix_pcdi(void); +void m68k_op_move_32_ix_pcix(void); +void m68k_op_move_32_ix_i(void); +void m68k_op_move_32_aw_d(void); +void m68k_op_move_32_aw_a(void); +void m68k_op_move_32_aw_ai(void); +void m68k_op_move_32_aw_pi(void); +void m68k_op_move_32_aw_pd(void); +void m68k_op_move_32_aw_di(void); +void m68k_op_move_32_aw_ix(void); +void m68k_op_move_32_aw_aw(void); +void m68k_op_move_32_aw_al(void); +void m68k_op_move_32_aw_pcdi(void); +void m68k_op_move_32_aw_pcix(void); +void m68k_op_move_32_aw_i(void); +void m68k_op_move_32_al_d(void); +void m68k_op_move_32_al_a(void); +void m68k_op_move_32_al_ai(void); +void m68k_op_move_32_al_pi(void); +void m68k_op_move_32_al_pd(void); +void m68k_op_move_32_al_di(void); +void m68k_op_move_32_al_ix(void); +void m68k_op_move_32_al_aw(void); +void m68k_op_move_32_al_al(void); +void m68k_op_move_32_al_pcdi(void); +void m68k_op_move_32_al_pcix(void); +void m68k_op_move_32_al_i(void); +void m68k_op_movea_16_d(void); +void m68k_op_movea_16_a(void); +void m68k_op_movea_16_ai(void); +void m68k_op_movea_16_pi(void); +void m68k_op_movea_16_pd(void); +void m68k_op_movea_16_di(void); +void m68k_op_movea_16_ix(void); +void m68k_op_movea_16_aw(void); +void m68k_op_movea_16_al(void); +void m68k_op_movea_16_pcdi(void); +void m68k_op_movea_16_pcix(void); +void m68k_op_movea_16_i(void); +void m68k_op_movea_32_d(void); +void m68k_op_movea_32_a(void); +void m68k_op_movea_32_ai(void); +void m68k_op_movea_32_pi(void); +void m68k_op_movea_32_pd(void); +void m68k_op_movea_32_di(void); +void m68k_op_movea_32_ix(void); +void m68k_op_movea_32_aw(void); +void m68k_op_movea_32_al(void); +void m68k_op_movea_32_pcdi(void); +void m68k_op_movea_32_pcix(void); +void m68k_op_movea_32_i(void); +void m68k_op_move_16_frc_d(void); +void m68k_op_move_16_frc_ai(void); +void m68k_op_move_16_frc_pi(void); +void m68k_op_move_16_frc_pd(void); +void m68k_op_move_16_frc_di(void); +void m68k_op_move_16_frc_ix(void); +void m68k_op_move_16_frc_aw(void); +void m68k_op_move_16_frc_al(void); +void m68k_op_move_16_toc_d(void); +void m68k_op_move_16_toc_ai(void); +void m68k_op_move_16_toc_pi(void); +void m68k_op_move_16_toc_pd(void); +void m68k_op_move_16_toc_di(void); +void m68k_op_move_16_toc_ix(void); +void m68k_op_move_16_toc_aw(void); +void m68k_op_move_16_toc_al(void); +void m68k_op_move_16_toc_pcdi(void); +void m68k_op_move_16_toc_pcix(void); +void m68k_op_move_16_toc_i(void); +void m68k_op_move_16_frs_d(void); +void m68k_op_move_16_frs_ai(void); +void m68k_op_move_16_frs_pi(void); +void m68k_op_move_16_frs_pd(void); +void m68k_op_move_16_frs_di(void); +void m68k_op_move_16_frs_ix(void); +void m68k_op_move_16_frs_aw(void); +void m68k_op_move_16_frs_al(void); +void m68k_op_move_16_tos_d(void); +void m68k_op_move_16_tos_ai(void); +void m68k_op_move_16_tos_pi(void); +void m68k_op_move_16_tos_pd(void); +void m68k_op_move_16_tos_di(void); +void m68k_op_move_16_tos_ix(void); +void m68k_op_move_16_tos_aw(void); +void m68k_op_move_16_tos_al(void); +void m68k_op_move_16_tos_pcdi(void); +void m68k_op_move_16_tos_pcix(void); +void m68k_op_move_16_tos_i(void); +void m68k_op_move_32_fru(void); +void m68k_op_move_32_tou(void); +void m68k_op_movec_32_cr(void); +void m68k_op_movec_32_rc(void); +void m68k_op_movem_16_re_pd(void); +void m68k_op_movem_16_re_ai(void); +void m68k_op_movem_16_re_di(void); +void m68k_op_movem_16_re_ix(void); +void m68k_op_movem_16_re_aw(void); +void m68k_op_movem_16_re_al(void); +void m68k_op_movem_32_re_pd(void); +void m68k_op_movem_32_re_ai(void); +void m68k_op_movem_32_re_di(void); +void m68k_op_movem_32_re_ix(void); +void m68k_op_movem_32_re_aw(void); +void m68k_op_movem_32_re_al(void); +void m68k_op_movem_16_er_pi(void); +void m68k_op_movem_16_er_pcdi(void); +void m68k_op_movem_16_er_pcix(void); +void m68k_op_movem_16_er_ai(void); +void m68k_op_movem_16_er_di(void); +void m68k_op_movem_16_er_ix(void); +void m68k_op_movem_16_er_aw(void); +void m68k_op_movem_16_er_al(void); +void m68k_op_movem_32_er_pi(void); +void m68k_op_movem_32_er_pcdi(void); +void m68k_op_movem_32_er_pcix(void); +void m68k_op_movem_32_er_ai(void); +void m68k_op_movem_32_er_di(void); +void m68k_op_movem_32_er_ix(void); +void m68k_op_movem_32_er_aw(void); +void m68k_op_movem_32_er_al(void); +void m68k_op_movep_16_re(void); +void m68k_op_movep_32_re(void); +void m68k_op_movep_16_er(void); +void m68k_op_movep_32_er(void); +void m68k_op_moves_8_ai(void); +void m68k_op_moves_8_pi(void); +void m68k_op_moves_8_pi7(void); +void m68k_op_moves_8_pd(void); +void m68k_op_moves_8_pd7(void); +void m68k_op_moves_8_di(void); +void m68k_op_moves_8_ix(void); +void m68k_op_moves_8_aw(void); +void m68k_op_moves_8_al(void); +void m68k_op_moves_16_ai(void); +void m68k_op_moves_16_pi(void); +void m68k_op_moves_16_pd(void); +void m68k_op_moves_16_di(void); +void m68k_op_moves_16_ix(void); +void m68k_op_moves_16_aw(void); +void m68k_op_moves_16_al(void); +void m68k_op_moves_32_ai(void); +void m68k_op_moves_32_pi(void); +void m68k_op_moves_32_pd(void); +void m68k_op_moves_32_di(void); +void m68k_op_moves_32_ix(void); +void m68k_op_moves_32_aw(void); +void m68k_op_moves_32_al(void); +void m68k_op_moveq_32(void); +void m68k_op_move16_32(void); +void m68k_op_muls_16_d(void); +void m68k_op_muls_16_ai(void); +void m68k_op_muls_16_pi(void); +void m68k_op_muls_16_pd(void); +void m68k_op_muls_16_di(void); +void m68k_op_muls_16_ix(void); +void m68k_op_muls_16_aw(void); +void m68k_op_muls_16_al(void); +void m68k_op_muls_16_pcdi(void); +void m68k_op_muls_16_pcix(void); +void m68k_op_muls_16_i(void); +void m68k_op_mulu_16_d(void); +void m68k_op_mulu_16_ai(void); +void m68k_op_mulu_16_pi(void); +void m68k_op_mulu_16_pd(void); +void m68k_op_mulu_16_di(void); +void m68k_op_mulu_16_ix(void); +void m68k_op_mulu_16_aw(void); +void m68k_op_mulu_16_al(void); +void m68k_op_mulu_16_pcdi(void); +void m68k_op_mulu_16_pcix(void); +void m68k_op_mulu_16_i(void); +void m68k_op_mull_32_d(void); +void m68k_op_mull_32_ai(void); +void m68k_op_mull_32_pi(void); +void m68k_op_mull_32_pd(void); +void m68k_op_mull_32_di(void); +void m68k_op_mull_32_ix(void); +void m68k_op_mull_32_aw(void); +void m68k_op_mull_32_al(void); +void m68k_op_mull_32_pcdi(void); +void m68k_op_mull_32_pcix(void); +void m68k_op_mull_32_i(void); +void m68k_op_nbcd_8_d(void); +void m68k_op_nbcd_8_ai(void); +void m68k_op_nbcd_8_pi(void); +void m68k_op_nbcd_8_pi7(void); +void m68k_op_nbcd_8_pd(void); +void m68k_op_nbcd_8_pd7(void); +void m68k_op_nbcd_8_di(void); +void m68k_op_nbcd_8_ix(void); +void m68k_op_nbcd_8_aw(void); +void m68k_op_nbcd_8_al(void); +void m68k_op_neg_8_d(void); +void m68k_op_neg_8_ai(void); +void m68k_op_neg_8_pi(void); +void m68k_op_neg_8_pi7(void); +void m68k_op_neg_8_pd(void); +void m68k_op_neg_8_pd7(void); +void m68k_op_neg_8_di(void); +void m68k_op_neg_8_ix(void); +void m68k_op_neg_8_aw(void); +void m68k_op_neg_8_al(void); +void m68k_op_neg_16_d(void); +void m68k_op_neg_16_ai(void); +void m68k_op_neg_16_pi(void); +void m68k_op_neg_16_pd(void); +void m68k_op_neg_16_di(void); +void m68k_op_neg_16_ix(void); +void m68k_op_neg_16_aw(void); +void m68k_op_neg_16_al(void); +void m68k_op_neg_32_d(void); +void m68k_op_neg_32_ai(void); +void m68k_op_neg_32_pi(void); +void m68k_op_neg_32_pd(void); +void m68k_op_neg_32_di(void); +void m68k_op_neg_32_ix(void); +void m68k_op_neg_32_aw(void); +void m68k_op_neg_32_al(void); +void m68k_op_negx_8_d(void); +void m68k_op_negx_8_ai(void); +void m68k_op_negx_8_pi(void); +void m68k_op_negx_8_pi7(void); +void m68k_op_negx_8_pd(void); +void m68k_op_negx_8_pd7(void); +void m68k_op_negx_8_di(void); +void m68k_op_negx_8_ix(void); +void m68k_op_negx_8_aw(void); +void m68k_op_negx_8_al(void); +void m68k_op_negx_16_d(void); +void m68k_op_negx_16_ai(void); +void m68k_op_negx_16_pi(void); +void m68k_op_negx_16_pd(void); +void m68k_op_negx_16_di(void); +void m68k_op_negx_16_ix(void); +void m68k_op_negx_16_aw(void); +void m68k_op_negx_16_al(void); +void m68k_op_negx_32_d(void); +void m68k_op_negx_32_ai(void); +void m68k_op_negx_32_pi(void); +void m68k_op_negx_32_pd(void); +void m68k_op_negx_32_di(void); +void m68k_op_negx_32_ix(void); +void m68k_op_negx_32_aw(void); +void m68k_op_negx_32_al(void); +void m68k_op_nop(void); +void m68k_op_not_8_d(void); +void m68k_op_not_8_ai(void); +void m68k_op_not_8_pi(void); +void m68k_op_not_8_pi7(void); +void m68k_op_not_8_pd(void); +void m68k_op_not_8_pd7(void); +void m68k_op_not_8_di(void); +void m68k_op_not_8_ix(void); +void m68k_op_not_8_aw(void); +void m68k_op_not_8_al(void); +void m68k_op_not_16_d(void); +void m68k_op_not_16_ai(void); +void m68k_op_not_16_pi(void); +void m68k_op_not_16_pd(void); +void m68k_op_not_16_di(void); +void m68k_op_not_16_ix(void); +void m68k_op_not_16_aw(void); +void m68k_op_not_16_al(void); +void m68k_op_not_32_d(void); +void m68k_op_not_32_ai(void); +void m68k_op_not_32_pi(void); +void m68k_op_not_32_pd(void); +void m68k_op_not_32_di(void); +void m68k_op_not_32_ix(void); +void m68k_op_not_32_aw(void); +void m68k_op_not_32_al(void); +void m68k_op_or_8_er_d(void); +void m68k_op_or_8_er_ai(void); +void m68k_op_or_8_er_pi(void); +void m68k_op_or_8_er_pi7(void); +void m68k_op_or_8_er_pd(void); +void m68k_op_or_8_er_pd7(void); +void m68k_op_or_8_er_di(void); +void m68k_op_or_8_er_ix(void); +void m68k_op_or_8_er_aw(void); +void m68k_op_or_8_er_al(void); +void m68k_op_or_8_er_pcdi(void); +void m68k_op_or_8_er_pcix(void); +void m68k_op_or_8_er_i(void); +void m68k_op_or_16_er_d(void); +void m68k_op_or_16_er_ai(void); +void m68k_op_or_16_er_pi(void); +void m68k_op_or_16_er_pd(void); +void m68k_op_or_16_er_di(void); +void m68k_op_or_16_er_ix(void); +void m68k_op_or_16_er_aw(void); +void m68k_op_or_16_er_al(void); +void m68k_op_or_16_er_pcdi(void); +void m68k_op_or_16_er_pcix(void); +void m68k_op_or_16_er_i(void); +void m68k_op_or_32_er_d(void); +void m68k_op_or_32_er_ai(void); +void m68k_op_or_32_er_pi(void); +void m68k_op_or_32_er_pd(void); +void m68k_op_or_32_er_di(void); +void m68k_op_or_32_er_ix(void); +void m68k_op_or_32_er_aw(void); +void m68k_op_or_32_er_al(void); +void m68k_op_or_32_er_pcdi(void); +void m68k_op_or_32_er_pcix(void); +void m68k_op_or_32_er_i(void); +void m68k_op_or_8_re_ai(void); +void m68k_op_or_8_re_pi(void); +void m68k_op_or_8_re_pi7(void); +void m68k_op_or_8_re_pd(void); +void m68k_op_or_8_re_pd7(void); +void m68k_op_or_8_re_di(void); +void m68k_op_or_8_re_ix(void); +void m68k_op_or_8_re_aw(void); +void m68k_op_or_8_re_al(void); +void m68k_op_or_16_re_ai(void); +void m68k_op_or_16_re_pi(void); +void m68k_op_or_16_re_pd(void); +void m68k_op_or_16_re_di(void); +void m68k_op_or_16_re_ix(void); +void m68k_op_or_16_re_aw(void); +void m68k_op_or_16_re_al(void); +void m68k_op_or_32_re_ai(void); +void m68k_op_or_32_re_pi(void); +void m68k_op_or_32_re_pd(void); +void m68k_op_or_32_re_di(void); +void m68k_op_or_32_re_ix(void); +void m68k_op_or_32_re_aw(void); +void m68k_op_or_32_re_al(void); +void m68k_op_ori_8_d(void); +void m68k_op_ori_8_ai(void); +void m68k_op_ori_8_pi(void); +void m68k_op_ori_8_pi7(void); +void m68k_op_ori_8_pd(void); +void m68k_op_ori_8_pd7(void); +void m68k_op_ori_8_di(void); +void m68k_op_ori_8_ix(void); +void m68k_op_ori_8_aw(void); +void m68k_op_ori_8_al(void); +void m68k_op_ori_16_d(void); +void m68k_op_ori_16_ai(void); +void m68k_op_ori_16_pi(void); +void m68k_op_ori_16_pd(void); +void m68k_op_ori_16_di(void); +void m68k_op_ori_16_ix(void); +void m68k_op_ori_16_aw(void); +void m68k_op_ori_16_al(void); +void m68k_op_ori_32_d(void); +void m68k_op_ori_32_ai(void); +void m68k_op_ori_32_pi(void); +void m68k_op_ori_32_pd(void); +void m68k_op_ori_32_di(void); +void m68k_op_ori_32_ix(void); +void m68k_op_ori_32_aw(void); +void m68k_op_ori_32_al(void); +void m68k_op_ori_16_toc(void); +void m68k_op_ori_16_tos(void); +void m68k_op_pack_16_rr(void); +void m68k_op_pack_16_mm_ax7(void); +void m68k_op_pack_16_mm_ay7(void); +void m68k_op_pack_16_mm_axy7(void); +void m68k_op_pack_16_mm(void); +void m68k_op_pea_32_ai(void); +void m68k_op_pea_32_di(void); +void m68k_op_pea_32_ix(void); +void m68k_op_pea_32_aw(void); +void m68k_op_pea_32_al(void); +void m68k_op_pea_32_pcdi(void); +void m68k_op_pea_32_pcix(void); +void m68k_op_pflush_32(void); +void m68k_op_reset(void); +void m68k_op_ror_8_s(void); +void m68k_op_ror_16_s(void); +void m68k_op_ror_32_s(void); +void m68k_op_ror_8_r(void); +void m68k_op_ror_16_r(void); +void m68k_op_ror_32_r(void); +void m68k_op_ror_16_ai(void); +void m68k_op_ror_16_pi(void); +void m68k_op_ror_16_pd(void); +void m68k_op_ror_16_di(void); +void m68k_op_ror_16_ix(void); +void m68k_op_ror_16_aw(void); +void m68k_op_ror_16_al(void); +void m68k_op_rol_8_s(void); +void m68k_op_rol_16_s(void); +void m68k_op_rol_32_s(void); +void m68k_op_rol_8_r(void); +void m68k_op_rol_16_r(void); +void m68k_op_rol_32_r(void); +void m68k_op_rol_16_ai(void); +void m68k_op_rol_16_pi(void); +void m68k_op_rol_16_pd(void); +void m68k_op_rol_16_di(void); +void m68k_op_rol_16_ix(void); +void m68k_op_rol_16_aw(void); +void m68k_op_rol_16_al(void); +void m68k_op_roxr_8_s(void); +void m68k_op_roxr_16_s(void); +void m68k_op_roxr_32_s(void); +void m68k_op_roxr_8_r(void); +void m68k_op_roxr_16_r(void); +void m68k_op_roxr_32_r(void); +void m68k_op_roxr_16_ai(void); +void m68k_op_roxr_16_pi(void); +void m68k_op_roxr_16_pd(void); +void m68k_op_roxr_16_di(void); +void m68k_op_roxr_16_ix(void); +void m68k_op_roxr_16_aw(void); +void m68k_op_roxr_16_al(void); +void m68k_op_roxl_8_s(void); +void m68k_op_roxl_16_s(void); +void m68k_op_roxl_32_s(void); +void m68k_op_roxl_8_r(void); +void m68k_op_roxl_16_r(void); +void m68k_op_roxl_32_r(void); +void m68k_op_roxl_16_ai(void); +void m68k_op_roxl_16_pi(void); +void m68k_op_roxl_16_pd(void); +void m68k_op_roxl_16_di(void); +void m68k_op_roxl_16_ix(void); +void m68k_op_roxl_16_aw(void); +void m68k_op_roxl_16_al(void); +void m68k_op_rtd_32(void); +void m68k_op_rte_32(void); +void m68k_op_rtm_32(void); +void m68k_op_rtr_32(void); +void m68k_op_rts_32(void); +void m68k_op_sbcd_8_rr(void); +void m68k_op_sbcd_8_mm_ax7(void); +void m68k_op_sbcd_8_mm_ay7(void); +void m68k_op_sbcd_8_mm_axy7(void); +void m68k_op_sbcd_8_mm(void); +void m68k_op_st_8_d(void); +void m68k_op_st_8_ai(void); +void m68k_op_st_8_pi(void); +void m68k_op_st_8_pi7(void); +void m68k_op_st_8_pd(void); +void m68k_op_st_8_pd7(void); +void m68k_op_st_8_di(void); +void m68k_op_st_8_ix(void); +void m68k_op_st_8_aw(void); +void m68k_op_st_8_al(void); +void m68k_op_sf_8_d(void); +void m68k_op_sf_8_ai(void); +void m68k_op_sf_8_pi(void); +void m68k_op_sf_8_pi7(void); +void m68k_op_sf_8_pd(void); +void m68k_op_sf_8_pd7(void); +void m68k_op_sf_8_di(void); +void m68k_op_sf_8_ix(void); +void m68k_op_sf_8_aw(void); +void m68k_op_sf_8_al(void); +void m68k_op_shi_8_d(void); +void m68k_op_sls_8_d(void); +void m68k_op_scc_8_d(void); +void m68k_op_scs_8_d(void); +void m68k_op_sne_8_d(void); +void m68k_op_seq_8_d(void); +void m68k_op_svc_8_d(void); +void m68k_op_svs_8_d(void); +void m68k_op_spl_8_d(void); +void m68k_op_smi_8_d(void); +void m68k_op_sge_8_d(void); +void m68k_op_slt_8_d(void); +void m68k_op_sgt_8_d(void); +void m68k_op_sle_8_d(void); +void m68k_op_shi_8_ai(void); +void m68k_op_shi_8_pi(void); +void m68k_op_shi_8_pi7(void); +void m68k_op_shi_8_pd(void); +void m68k_op_shi_8_pd7(void); +void m68k_op_shi_8_di(void); +void m68k_op_shi_8_ix(void); +void m68k_op_shi_8_aw(void); +void m68k_op_shi_8_al(void); +void m68k_op_sls_8_ai(void); +void m68k_op_sls_8_pi(void); +void m68k_op_sls_8_pi7(void); +void m68k_op_sls_8_pd(void); +void m68k_op_sls_8_pd7(void); +void m68k_op_sls_8_di(void); +void m68k_op_sls_8_ix(void); +void m68k_op_sls_8_aw(void); +void m68k_op_sls_8_al(void); +void m68k_op_scc_8_ai(void); +void m68k_op_scc_8_pi(void); +void m68k_op_scc_8_pi7(void); +void m68k_op_scc_8_pd(void); +void m68k_op_scc_8_pd7(void); +void m68k_op_scc_8_di(void); +void m68k_op_scc_8_ix(void); +void m68k_op_scc_8_aw(void); +void m68k_op_scc_8_al(void); +void m68k_op_scs_8_ai(void); +void m68k_op_scs_8_pi(void); +void m68k_op_scs_8_pi7(void); +void m68k_op_scs_8_pd(void); +void m68k_op_scs_8_pd7(void); +void m68k_op_scs_8_di(void); +void m68k_op_scs_8_ix(void); +void m68k_op_scs_8_aw(void); +void m68k_op_scs_8_al(void); +void m68k_op_sne_8_ai(void); +void m68k_op_sne_8_pi(void); +void m68k_op_sne_8_pi7(void); +void m68k_op_sne_8_pd(void); +void m68k_op_sne_8_pd7(void); +void m68k_op_sne_8_di(void); +void m68k_op_sne_8_ix(void); +void m68k_op_sne_8_aw(void); +void m68k_op_sne_8_al(void); +void m68k_op_seq_8_ai(void); +void m68k_op_seq_8_pi(void); +void m68k_op_seq_8_pi7(void); +void m68k_op_seq_8_pd(void); +void m68k_op_seq_8_pd7(void); +void m68k_op_seq_8_di(void); +void m68k_op_seq_8_ix(void); +void m68k_op_seq_8_aw(void); +void m68k_op_seq_8_al(void); +void m68k_op_svc_8_ai(void); +void m68k_op_svc_8_pi(void); +void m68k_op_svc_8_pi7(void); +void m68k_op_svc_8_pd(void); +void m68k_op_svc_8_pd7(void); +void m68k_op_svc_8_di(void); +void m68k_op_svc_8_ix(void); +void m68k_op_svc_8_aw(void); +void m68k_op_svc_8_al(void); +void m68k_op_svs_8_ai(void); +void m68k_op_svs_8_pi(void); +void m68k_op_svs_8_pi7(void); +void m68k_op_svs_8_pd(void); +void m68k_op_svs_8_pd7(void); +void m68k_op_svs_8_di(void); +void m68k_op_svs_8_ix(void); +void m68k_op_svs_8_aw(void); +void m68k_op_svs_8_al(void); +void m68k_op_spl_8_ai(void); +void m68k_op_spl_8_pi(void); +void m68k_op_spl_8_pi7(void); +void m68k_op_spl_8_pd(void); +void m68k_op_spl_8_pd7(void); +void m68k_op_spl_8_di(void); +void m68k_op_spl_8_ix(void); +void m68k_op_spl_8_aw(void); +void m68k_op_spl_8_al(void); +void m68k_op_smi_8_ai(void); +void m68k_op_smi_8_pi(void); +void m68k_op_smi_8_pi7(void); +void m68k_op_smi_8_pd(void); +void m68k_op_smi_8_pd7(void); +void m68k_op_smi_8_di(void); +void m68k_op_smi_8_ix(void); +void m68k_op_smi_8_aw(void); +void m68k_op_smi_8_al(void); +void m68k_op_sge_8_ai(void); +void m68k_op_sge_8_pi(void); +void m68k_op_sge_8_pi7(void); +void m68k_op_sge_8_pd(void); +void m68k_op_sge_8_pd7(void); +void m68k_op_sge_8_di(void); +void m68k_op_sge_8_ix(void); +void m68k_op_sge_8_aw(void); +void m68k_op_sge_8_al(void); +void m68k_op_slt_8_ai(void); +void m68k_op_slt_8_pi(void); +void m68k_op_slt_8_pi7(void); +void m68k_op_slt_8_pd(void); +void m68k_op_slt_8_pd7(void); +void m68k_op_slt_8_di(void); +void m68k_op_slt_8_ix(void); +void m68k_op_slt_8_aw(void); +void m68k_op_slt_8_al(void); +void m68k_op_sgt_8_ai(void); +void m68k_op_sgt_8_pi(void); +void m68k_op_sgt_8_pi7(void); +void m68k_op_sgt_8_pd(void); +void m68k_op_sgt_8_pd7(void); +void m68k_op_sgt_8_di(void); +void m68k_op_sgt_8_ix(void); +void m68k_op_sgt_8_aw(void); +void m68k_op_sgt_8_al(void); +void m68k_op_sle_8_ai(void); +void m68k_op_sle_8_pi(void); +void m68k_op_sle_8_pi7(void); +void m68k_op_sle_8_pd(void); +void m68k_op_sle_8_pd7(void); +void m68k_op_sle_8_di(void); +void m68k_op_sle_8_ix(void); +void m68k_op_sle_8_aw(void); +void m68k_op_sle_8_al(void); +void m68k_op_stop(void); +void m68k_op_sub_8_er_d(void); +void m68k_op_sub_8_er_ai(void); +void m68k_op_sub_8_er_pi(void); +void m68k_op_sub_8_er_pi7(void); +void m68k_op_sub_8_er_pd(void); +void m68k_op_sub_8_er_pd7(void); +void m68k_op_sub_8_er_di(void); +void m68k_op_sub_8_er_ix(void); +void m68k_op_sub_8_er_aw(void); +void m68k_op_sub_8_er_al(void); +void m68k_op_sub_8_er_pcdi(void); +void m68k_op_sub_8_er_pcix(void); +void m68k_op_sub_8_er_i(void); +void m68k_op_sub_16_er_d(void); +void m68k_op_sub_16_er_a(void); +void m68k_op_sub_16_er_ai(void); +void m68k_op_sub_16_er_pi(void); +void m68k_op_sub_16_er_pd(void); +void m68k_op_sub_16_er_di(void); +void m68k_op_sub_16_er_ix(void); +void m68k_op_sub_16_er_aw(void); +void m68k_op_sub_16_er_al(void); +void m68k_op_sub_16_er_pcdi(void); +void m68k_op_sub_16_er_pcix(void); +void m68k_op_sub_16_er_i(void); +void m68k_op_sub_32_er_d(void); +void m68k_op_sub_32_er_a(void); +void m68k_op_sub_32_er_ai(void); +void m68k_op_sub_32_er_pi(void); +void m68k_op_sub_32_er_pd(void); +void m68k_op_sub_32_er_di(void); +void m68k_op_sub_32_er_ix(void); +void m68k_op_sub_32_er_aw(void); +void m68k_op_sub_32_er_al(void); +void m68k_op_sub_32_er_pcdi(void); +void m68k_op_sub_32_er_pcix(void); +void m68k_op_sub_32_er_i(void); +void m68k_op_sub_8_re_ai(void); +void m68k_op_sub_8_re_pi(void); +void m68k_op_sub_8_re_pi7(void); +void m68k_op_sub_8_re_pd(void); +void m68k_op_sub_8_re_pd7(void); +void m68k_op_sub_8_re_di(void); +void m68k_op_sub_8_re_ix(void); +void m68k_op_sub_8_re_aw(void); +void m68k_op_sub_8_re_al(void); +void m68k_op_sub_16_re_ai(void); +void m68k_op_sub_16_re_pi(void); +void m68k_op_sub_16_re_pd(void); +void m68k_op_sub_16_re_di(void); +void m68k_op_sub_16_re_ix(void); +void m68k_op_sub_16_re_aw(void); +void m68k_op_sub_16_re_al(void); +void m68k_op_sub_32_re_ai(void); +void m68k_op_sub_32_re_pi(void); +void m68k_op_sub_32_re_pd(void); +void m68k_op_sub_32_re_di(void); +void m68k_op_sub_32_re_ix(void); +void m68k_op_sub_32_re_aw(void); +void m68k_op_sub_32_re_al(void); +void m68k_op_suba_16_d(void); +void m68k_op_suba_16_a(void); +void m68k_op_suba_16_ai(void); +void m68k_op_suba_16_pi(void); +void m68k_op_suba_16_pd(void); +void m68k_op_suba_16_di(void); +void m68k_op_suba_16_ix(void); +void m68k_op_suba_16_aw(void); +void m68k_op_suba_16_al(void); +void m68k_op_suba_16_pcdi(void); +void m68k_op_suba_16_pcix(void); +void m68k_op_suba_16_i(void); +void m68k_op_suba_32_d(void); +void m68k_op_suba_32_a(void); +void m68k_op_suba_32_ai(void); +void m68k_op_suba_32_pi(void); +void m68k_op_suba_32_pd(void); +void m68k_op_suba_32_di(void); +void m68k_op_suba_32_ix(void); +void m68k_op_suba_32_aw(void); +void m68k_op_suba_32_al(void); +void m68k_op_suba_32_pcdi(void); +void m68k_op_suba_32_pcix(void); +void m68k_op_suba_32_i(void); +void m68k_op_subi_8_d(void); +void m68k_op_subi_8_ai(void); +void m68k_op_subi_8_pi(void); +void m68k_op_subi_8_pi7(void); +void m68k_op_subi_8_pd(void); +void m68k_op_subi_8_pd7(void); +void m68k_op_subi_8_di(void); +void m68k_op_subi_8_ix(void); +void m68k_op_subi_8_aw(void); +void m68k_op_subi_8_al(void); +void m68k_op_subi_16_d(void); +void m68k_op_subi_16_ai(void); +void m68k_op_subi_16_pi(void); +void m68k_op_subi_16_pd(void); +void m68k_op_subi_16_di(void); +void m68k_op_subi_16_ix(void); +void m68k_op_subi_16_aw(void); +void m68k_op_subi_16_al(void); +void m68k_op_subi_32_d(void); +void m68k_op_subi_32_ai(void); +void m68k_op_subi_32_pi(void); +void m68k_op_subi_32_pd(void); +void m68k_op_subi_32_di(void); +void m68k_op_subi_32_ix(void); +void m68k_op_subi_32_aw(void); +void m68k_op_subi_32_al(void); +void m68k_op_subq_8_d(void); +void m68k_op_subq_8_ai(void); +void m68k_op_subq_8_pi(void); +void m68k_op_subq_8_pi7(void); +void m68k_op_subq_8_pd(void); +void m68k_op_subq_8_pd7(void); +void m68k_op_subq_8_di(void); +void m68k_op_subq_8_ix(void); +void m68k_op_subq_8_aw(void); +void m68k_op_subq_8_al(void); +void m68k_op_subq_16_d(void); +void m68k_op_subq_16_a(void); +void m68k_op_subq_16_ai(void); +void m68k_op_subq_16_pi(void); +void m68k_op_subq_16_pd(void); +void m68k_op_subq_16_di(void); +void m68k_op_subq_16_ix(void); +void m68k_op_subq_16_aw(void); +void m68k_op_subq_16_al(void); +void m68k_op_subq_32_d(void); +void m68k_op_subq_32_a(void); +void m68k_op_subq_32_ai(void); +void m68k_op_subq_32_pi(void); +void m68k_op_subq_32_pd(void); +void m68k_op_subq_32_di(void); +void m68k_op_subq_32_ix(void); +void m68k_op_subq_32_aw(void); +void m68k_op_subq_32_al(void); +void m68k_op_subx_8_rr(void); +void m68k_op_subx_16_rr(void); +void m68k_op_subx_32_rr(void); +void m68k_op_subx_8_mm_ax7(void); +void m68k_op_subx_8_mm_ay7(void); +void m68k_op_subx_8_mm_axy7(void); +void m68k_op_subx_8_mm(void); +void m68k_op_subx_16_mm(void); +void m68k_op_subx_32_mm(void); +void m68k_op_swap_32(void); +void m68k_op_tas_8_d(void); +void m68k_op_tas_8_ai(void); +void m68k_op_tas_8_pi(void); +void m68k_op_tas_8_pi7(void); +void m68k_op_tas_8_pd(void); +void m68k_op_tas_8_pd7(void); +void m68k_op_tas_8_di(void); +void m68k_op_tas_8_ix(void); +void m68k_op_tas_8_aw(void); +void m68k_op_tas_8_al(void); +void m68k_op_trap(void); +void m68k_op_trapt(void); +void m68k_op_trapt_16(void); +void m68k_op_trapt_32(void); +void m68k_op_trapf(void); +void m68k_op_trapf_16(void); +void m68k_op_trapf_32(void); +void m68k_op_traphi(void); +void m68k_op_trapls(void); +void m68k_op_trapcc(void); +void m68k_op_trapcs(void); +void m68k_op_trapne(void); +void m68k_op_trapeq(void); +void m68k_op_trapvc(void); +void m68k_op_trapvs(void); +void m68k_op_trappl(void); +void m68k_op_trapmi(void); +void m68k_op_trapge(void); +void m68k_op_traplt(void); +void m68k_op_trapgt(void); +void m68k_op_traple(void); +void m68k_op_traphi_16(void); +void m68k_op_trapls_16(void); +void m68k_op_trapcc_16(void); +void m68k_op_trapcs_16(void); +void m68k_op_trapne_16(void); +void m68k_op_trapeq_16(void); +void m68k_op_trapvc_16(void); +void m68k_op_trapvs_16(void); +void m68k_op_trappl_16(void); +void m68k_op_trapmi_16(void); +void m68k_op_trapge_16(void); +void m68k_op_traplt_16(void); +void m68k_op_trapgt_16(void); +void m68k_op_traple_16(void); +void m68k_op_traphi_32(void); +void m68k_op_trapls_32(void); +void m68k_op_trapcc_32(void); +void m68k_op_trapcs_32(void); +void m68k_op_trapne_32(void); +void m68k_op_trapeq_32(void); +void m68k_op_trapvc_32(void); +void m68k_op_trapvs_32(void); +void m68k_op_trappl_32(void); +void m68k_op_trapmi_32(void); +void m68k_op_trapge_32(void); +void m68k_op_traplt_32(void); +void m68k_op_trapgt_32(void); +void m68k_op_traple_32(void); +void m68k_op_trapv(void); +void m68k_op_tst_8_d(void); +void m68k_op_tst_8_ai(void); +void m68k_op_tst_8_pi(void); +void m68k_op_tst_8_pi7(void); +void m68k_op_tst_8_pd(void); +void m68k_op_tst_8_pd7(void); +void m68k_op_tst_8_di(void); +void m68k_op_tst_8_ix(void); +void m68k_op_tst_8_aw(void); +void m68k_op_tst_8_al(void); +void m68k_op_tst_8_pcdi(void); +void m68k_op_tst_8_pcix(void); +void m68k_op_tst_8_i(void); +void m68k_op_tst_16_d(void); +void m68k_op_tst_16_a(void); +void m68k_op_tst_16_ai(void); +void m68k_op_tst_16_pi(void); +void m68k_op_tst_16_pd(void); +void m68k_op_tst_16_di(void); +void m68k_op_tst_16_ix(void); +void m68k_op_tst_16_aw(void); +void m68k_op_tst_16_al(void); +void m68k_op_tst_16_pcdi(void); +void m68k_op_tst_16_pcix(void); +void m68k_op_tst_16_i(void); +void m68k_op_tst_32_d(void); +void m68k_op_tst_32_a(void); +void m68k_op_tst_32_ai(void); +void m68k_op_tst_32_pi(void); +void m68k_op_tst_32_pd(void); +void m68k_op_tst_32_di(void); +void m68k_op_tst_32_ix(void); +void m68k_op_tst_32_aw(void); +void m68k_op_tst_32_al(void); +void m68k_op_tst_32_pcdi(void); +void m68k_op_tst_32_pcix(void); +void m68k_op_tst_32_i(void); +void m68k_op_unlk_32_a7(void); +void m68k_op_unlk_32(void); +void m68k_op_unpk_16_rr(void); +void m68k_op_unpk_16_mm_ax7(void); +void m68k_op_unpk_16_mm_ay7(void); +void m68k_op_unpk_16_mm_axy7(void); +void m68k_op_unpk_16_mm(void); +/* Build the opcode handler table */ +void m68ki_build_opcode_table(void); + +extern void (*m68ki_instruction_jump_table[0x10000])(void); /* opcode handler jump table */ +extern unsigned char m68ki_cycles[][0x10000]; + + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ + +#endif /* M68KOPS__HEADER */ + + diff --git a/cpu/musashi/readme.txt b/cpu/musashi/readme.txt new file mode 100644 index 00000000..48e603fa --- /dev/null +++ b/cpu/musashi/readme.txt @@ -0,0 +1,315 @@ + MUSASHI + ======= + + Version 3.3 + + A portable Motorola M680x0 processor emulation engine. + Copyright 1998-2001 Karl Stenerud. All rights reserved. + + + +INTRODUCTION: +------------ + +Musashi is a Motorola 68000, 68010, 68EC020, and 68020 emulator written in C. +This emulator was written with two goals in mind: portability and speed. + +The emulator is written to ANSI C specifications with the exception that I use +inline functions. This is not compliant to the ANSI spec, but will be +compliant to the ANSI C9X spec. + +It has been successfully running in the MAME project (www.mame.net) for over 2 +years and so has had time to mature. + + + +LICENSE AND COPYRIGHT: +--------------------- + +The Musashi M680x0 emulator is copyright 1998-2001 Karl Stenerud. + +The source code included in this archive is provided AS-IS, free for any +non-commercial purpose. + +If you build a program using this core, please give credit to the author. + +If you wish to use this core in a commercial environment, please contact +the author to discuss commercial licensing. + + + +AVAILABILITY: +------------ +The latest version of this code can be obtained at: +http://kstenerud.cjb.net + + + +CONTACTING THE AUTHOR: +--------------------- +I can be reached at kstenerud@mame.net + + + +BASIC CONFIGURATION: +------------------- +The basic configuration will give you a standard 68000 that has sufficient +functionality to work in a primitive environment. + +This setup assumes that you only have 1 device interrupting it, that the +device will always request an autovectored interrupt, and it will always clear +the interrupt before the interrupt service routine finishes (but could +possibly re-assert the interrupt). +You will have only one address space, no tracing, and no instruction prefetch. + +To implement the basic configuration: + +- Open m68kconf.h and verify that the settings for INLINE and DECL_SPEC will + work with your compiler. (They are set for gcc) + +- In your host program, implement the following functions: + unsigned int m68k_read_memory_8(unsigned int address); + unsigned int m68k_read_memory_16(unsigned int address); + unsigned int m68k_read_memory_32(unsigned int address); + void m68k_write_memory_8(unsigned int address, unsigned int value); + void m68k_write_memory_16(unsigned int address, unsigned int value); + void m68k_write_memory_32(unsigned int address, unsigned int value); + +- In your host program, be sure to call m68k_pulse_reset() once before calling + any of the other functions as this initializes the core. + +- Use m68k_execute() to execute instructions and m68k_set_irq() to cause an + interrupt. + + + +ADDING PROPER INTERRUPT HANDLING: +-------------------------------- +The interrupt handling in the basic configuration doesn't emulate the +interrupt acknowledge phase of the CPU and automatically clears an interrupt +request during interrupt processing. +While this works for most systems, you may need more accurate interrupt +handling. + +To add proper interrupt handling: + +- In m68kconf.h, set M68K_EMULATE_INT_ACK to OPT_SPECIFY_HANDLER + +- In m68kconf.h, set M68K_INT_ACK_CALLBACK(A) to your interrupt acknowledge + routine + +- Your interrupt acknowledge routine must return an interrupt vector, + M68K_INT_ACK_AUTOVECTOR, or M68K_INT_ACK_SPURIOUS. most m68k + implementations just use autovectored interrupts. + +- When the interrupting device is satisfied, you must call m68k_set_irq(0) to + remove the interrupt request. + + + +MULTIPLE INTERRUPTS: +------------------- +The above system will work if you have only one device interrupting the CPU, +but if you have more than one device, you must do a bit more. + +To add multiple interrupts: + +- You must make an interrupt arbitration device that will take the highest + priority interrupt and encode it onto the IRQ pins on the CPU. + +- The interrupt arbitration device should use m68k_set_irq() to set the + highest pending interrupt, or 0 for no interrupts pending. + + + +SEPARATE IMMEDIATE AND PC-RELATIVE READS: +---------------------------------------- +You can write faster memory access functions if you know whether you are +fetching from ROM or RAM. Immediate reads are always from the program space +(Always in ROM unless it is running self-modifying code). +This will also separate the pc-relative reads, since some systems treat +PROGRAM mode reads and DATA mode reads differently (for program encryption, +for instance). See the section below (ADDRESS SPACE) for an explanation of +PROGRAM and DATA mode. + +To enable separate reads: + +- In m68kconf.h, turn on M68K_SEPARATE_READS. + +- In your host program, implement the following functions: + unsigned int m68k_read_immediate_16(unsigned int address); + unsigned int m68k_read_immediate_32(unsigned int address); + + unsigned int m68k_read_pcrelative_8(unsigned int address); + unsigned int m68k_read_pcrelative_16(unsigned int address); + unsigned int m68k_read_pcrelative_32(unsigned int address); + +- If you need to know the current PC (for banking and such), set + M68K_MONITOR_PC to OPT_SPECIFY_HANDLER, and set M68K_SET_PC_CALLBACK(A) to + your routine. + + + +ADDRESS SPACES: +-------------- +Most systems will only implement one address space, placing ROM at the lower +addresses and RAM at the higher. However, there is the possibility that a +system will implement ROM and RAM in the same address range, but in different +address spaces, or will have different mamory types that require different +handling for the program and the data. + +The 68k accomodates this by allowing different program spaces, the most +important to us being PROGRAM and DATA space. Here is a breakdown of +how information is fetched: + +- All immediate reads are fetched from PROGRAM space. + +- All PC-relative reads are fetched from PROGRAM space. + +- The initial stack pointer and program counter are fetched from PROGRAM space. + +- All other reads (except for those from the moves instruction for 68020) + are fetched from DATA space. + +The m68k deals with this by encoding the requested address space on the +function code pins: + + FC + Address Space 210 + ------------------ --- + USER DATA 001 + USER PROGRAM 010 + SUPERVISOR DATA 101 + SUPERVISOR PROGRAM 110 + CPU SPACE 111 <-- not emulated in this core since we emulate + interrupt acknowledge in another way. + +Problems arise here if you need to emulate this distinction (if, for example, +your ROM and RAM are at the same address range, with RAM and ROM enable +wired to the function code pins). + +There are 2 ways to deal with this situation using Musashi: + +1. If you only need the distinction between PROGRAM and DATA (the most common), + you can just separate the reads (see the preceeding section). This is the + faster solution. + +2. You can emulate the function code pins entirely. + +To emulate the function code pins: + +- In m68kconf.h, set M68K_EMULATE_FC to OPT_SPECIFY_HANDLER and set + M68K_SET_FC_CALLBACK(A) to your function code handler function. + +- Your function code handler should select the proper address space for + subsequent calls to m68k_read_xx (and m68k_write_xx for 68010+). + +Note: immediate reads are always done from program space, so technically you + don't need to implement the separate immediate reads, although you could + gain more speed improvements leaving them in and doing some clever + programming. + + + +USING DIFFERENT CPU TYPES: +------------------------- +The default is to enable only the 68000 cpu type. To change this, change the +settings for M68K_EMULATE_010 etc in m68kconf.h. + +To set the CPU type you want to use: + +- Make sure it is enabled in m68kconf.h. Current switches are: + M68K_EMULATE_010 + M68K_EMULATE_EC020 + M68K_EMULATE_020 + +- In your host program, call m68k_set_cpu_type() and then call + m68k_pulse_reset(). Valid CPU types are: + M68K_CPU_TYPE_68000, + M68K_CPU_TYPE_68010, + M68K_CPU_TYPE_68EC020, + M68K_CPU_TYPE_68020 + + + +CLOCK FREQUENCY: +--------------- +In order to emulate the correct clock frequency, you will have to calculate +how long it takes the emulation to execute a certain number of "cycles" and +vary your calls to m68k_execute() accordingly. +As well, it is a good idea to take away the CPU's timeslice when it writes to +a memory-mapped port in order to give the device it wrote to a chance to +react. + +You can use the functions m68k_cycles_run(), m68k_cycles_remaining(), +m68k_modify_timeslice(), and m68k_end_timeslice() to do this. +Try to use large cycle values in your calls to m68k_execute() since it will +increase throughput. You can always take away the timeslice later. + + + +MORE CORRECT EMULATION: +---------------------- +You may need to enable these in order to properly emulate some of the more +obscure functions of the m68k: + +- M68K_EMULATE_BKPT_ACK causes the CPU to call a breakpoint handler on a BKPT + instruction + +- M68K_EMULATE_TRACE causes the CPU to generate trace exceptions when the + trace bits are set + +- M68K_EMULATE_RESET causes the CPU to call a reset handler on a RESET + instruction. + +- M68K_EMULATE_PREFETCH emulates the 4-word instruction prefetch that is part + of the 68000/68010 (needed for Amiga emulation). + +- call m68k_pulse_halt() to emulate the HALT pin. + + + +CONVENIENCE FUNCTIONS: +--------------------- +These are in here for programmer convenience: + +- M68K_INSTRUCTION_HOOK lets you call a handler before each instruction. + +- M68K_LOG_ENABLE and M68K_LOG_1010_1111 lets you log illegal and A/F-line + instructions. + + + +MULTIPLE CPU EMULATION: +---------------------- +The default is to use only one CPU. To use more than one CPU in this core, +there are some things to keep in mind: + +- To have different cpus call different functions, use OPT_ON instead of + OPT_SPECIFY_HANDLER, and use the m68k_set_xxx_callback() functions to set + your callback handlers on a per-cpu basis. + +- Be sure to call set_cpu_type() for each CPU you use. + +- Use m68k_set_context() and m68k_get_context() to switch to another CPU. + + + +LOAD AND SAVE CPU CONTEXTS FROM DISK: +------------------------------------ +You can use them68k_load_context() and m68k_save_context() functions to load +and save the CPU state to disk. + + + +GET/SET INFORMATION FROM THE CPU: +-------------------------------- +You can use m68k_get_reg() and m68k_set_reg() to gain access to the internals +of the CPU. + + + +EXAMPLE: +------- + +I have included a file example.zip that contains a full example. diff --git a/cpu/mz80/Makefile b/cpu/mz80/Makefile new file mode 100644 index 00000000..2080dda3 --- /dev/null +++ b/cpu/mz80/Makefile @@ -0,0 +1,13 @@ +CFLAGS = -Wno-conversion -Wno-sign-compare # -Wno-pointer-sign + +all : mz80.asm + +mz80.asm : makez80 + ./makez80 -s -l -x86 $@ + +makez80 : makez80.o + + +clean : + $(RM) makez80 makez80.o mz80.asm + diff --git a/cpu/mz80/Makefile.win b/cpu/mz80/Makefile.win new file mode 100644 index 00000000..0fe2ddad --- /dev/null +++ b/cpu/mz80/Makefile.win @@ -0,0 +1,18 @@ +all : mz80.obj + +mz80.obj : mz80.asm + nasm -f win32 mz80.asm -o $@ + +mz80.asm : makez80.exe + makez80.exe -s -x86 $@ + +makez80.exe : makez80.c + cl /DWIN32 /W3 makez80.c + + +clean : tidy + del mz80.obj + +tidy : + del mz80.asm makez80.exe makez80.obj + diff --git a/cpu/mz80/makez80.c b/cpu/mz80/makez80.c new file mode 100644 index 00000000..653d82e8 --- /dev/null +++ b/cpu/mz80/makez80.c @@ -0,0 +1,9512 @@ +/* Multi-Z80 32 Bit emulator */ + +/* Copyright 1996, 1997, 1998, 1999, 2000 Neil Bradley, All rights reserved + * + * License agreement: + * + * (MZ80 Refers to both the assembly and C code emitted by makeZ80.c and + * makeZ80.c itself) + * + * MZ80 May be distributed in unmodified form to any medium. + * + * MZ80 May not be sold, or sold as a part of a commercial package without + * the express written permission of Neil Bradley (neil@synthcom.com). This + * includes shareware. + * + * Modified versions of MZ80 may not be publicly redistributed without author + * approval (neil@synthcom.com). This includes distributing via a publicly + * accessible LAN. You may make your own source modifications and distribute + * MZ80 in source or object form, but if you make modifications to MZ80 + * then it should be noted in the top as a comment in makeZ80.c. + * + * MZ80 Licensing for commercial applications is available. Please email + * neil@synthcom.com for details. + * + * Synthcom Systems, Inc, and Neil Bradley will not be held responsible for + * any damage done by the use of MZ80. It is purely "as-is". + * + * If you use MZ80 in a freeware application, credit in the following text: + * + * "Multi-Z80 CPU emulator by Neil Bradley (neil@synthcom.com)" + * + * must accompany the freeware application within the application itself or + * in the documentation. + * + * Legal stuff aside: + * + * If you find problems with MZ80, please email the author so they can get + * resolved. If you find a bug and fix it, please also email the author so + * that those bug fixes can be propogated to the installed base of MZ80 + * users. If you find performance improvements or problems with MZ80, please + * email the author with your changes/suggestions and they will be rolled in + * with subsequent releases of MZ80. + * + * The whole idea of this emulator is to have the fastest available 32 bit + * Multi-Z80 emulator for the PC, giving maximum performance. + * + */ + +#include +#include +#include +#include + +#define VERSION "3.4" + +#define TRUE 0xff +#define FALSE 0x0 +#define INVALID 0xff + +#define UINT32 unsigned long int +#define UINT8 unsigned char + +#define TIMING_REGULAR 0x00 +#define TIMING_XXCB 0x01 +#define TIMING_CB 0xcb +#define TIMING_DDFD 0xdd +#define TIMING_ED 0xed +#define TIMING_EXCEPT 0x02 + +FILE *fp = NULL; +char string[150]; +char cpubasename[150]; +static char mz80Index[50]; +static char mz80IndexHalfHigh[50]; +static char mz80IndexHalfLow[50]; +char majorOp[50]; +char procname[150]; +UINT32 dwGlobalLabel = 0; + +enum +{ + MZ80_ASSEMBLY_X86, + MZ80_C, + MZ80_UNKNOWN +}; + +UINT8 bPlain = FALSE; +UINT8 bNoTiming = FALSE; +UINT8 bUseStack = 0; +UINT8 bCurrentMode = TIMING_REGULAR; // Current timing mode +UINT8 b16BitIo = FALSE; +UINT8 bThroughCallHandler = FALSE; +UINT8 bOS2 = FALSE; +UINT8 bWhat = MZ80_UNKNOWN; + +void ProcBegin(UINT32 dwOpcode); + +UINT8 *pbLocalReg[8] = +{ + "ch", + "cl", + "dh", + "dl", + "bh", + "bl", + "dl", + "al" +}; + +UINT8 *pbLocalRegC[8] = +{ + "cpu.z80B", + "cpu.z80C", + "cpu.z80D", + "cpu.z80E", + "cpu.z80H", + "cpu.z80L", + "barf", + "cpu.z80A" +}; + +UINT8 *pbPushReg[8] = +{ + "cl", + "ch", + "byte [_z80de]", + "byte [_z80de + 1]", + "bl", + "bh", + "ah", + "al" +}; + +UINT8 *pbFlags[8] = +{ + "nz", + "z", + "nc", + "c", + "po", + "pe", + "ns", + "s" +}; + +UINT8 *pbRegPairC[] = +{ + "cpu.z80BC", + "cpu.z80DE", + "cpu.z80HL", + "cpu.z80sp" +}; + +UINT8 *pbFlagsC[8] = +{ + "(!(cpu.z80F & Z80_FLAG_ZERO))", + "(cpu.z80F & Z80_FLAG_ZERO)", + "(!(cpu.z80F & Z80_FLAG_CARRY))", + "(cpu.z80F & Z80_FLAG_CARRY)", + "(!(cpu.z80F & Z80_FLAG_OVERFLOW_PARITY))", + "(cpu.z80F & Z80_FLAG_OVERFLOW_PARITY)", + "(!(cpu.z80F & Z80_FLAG_SIGN))", + "(cpu.z80F & Z80_FLAG_SIGN)" +}; + +UINT8 *pbMathReg[8] = +{ + "ch", + "cl", + "byte [_z80de + 1]", + "byte [_z80de]", + "bh", + "bl", + "INVALID", + "al" +}; + +UINT8 *pbMathRegC[8] = +{ + "cpu.z80B", + "cpu.z80C", + "cpu.z80D", + "cpu.z80E", + "cpu.z80H", + "cpu.z80L", + "bTemp", + "cpu.z80A" +}; + +UINT8 *pbRegPairs[4] = +{ + "cx", // BC + "word [_z80de]", // DE + "bx", // HL + "word [_z80sp]" // SP +}; + +UINT8 *pbRegPairsC[4] = +{ + "cpu.z80BC", // BC + "cpu.z80DE", // DE + "cpu.z80HL", // HL + "cpu.z80sp" // SP +}; + +UINT8 *pbPopRegPairs[4] = +{ + "cx", // BC + "word [_z80de]", // DE + "bx", // HL + "ax" // SP +}; + +UINT8 *pbPopRegPairC[4] = +{ + "cpu.z80BC", + "cpu.z80DE", + "cpu.z80HL", + "cpu.z80AF" +}; + +UINT8 *pbIndexedRegPairs[4] = +{ + "cx", // BC + "word [_z80de]", // DE + "di", // IX/IY + "word [_z80sp]" // SP +}; + +// Timing tables + +UINT8 bTimingRegular[0x100] = +{ + 0x04, 0x0a, 0x07, 0x06, 0x04, 0x04, 0x07, 0x04, 0x04, 0x0b, 0x07, 0x06, 0x04, 0x04, 0x07, 0x04, + 0x08, 0x0a, 0x07, 0x06, 0x04, 0x04, 0x07, 0x04, 0x0c, 0x0b, 0x07, 0x06, 0x04, 0x04, 0x07, 0x04, + 0x07, 0x0a, 0x10, 0x06, 0x04, 0x04, 0x07, 0x04, 0x07, 0x0b, 0x10, 0x06, 0x04, 0x04, 0x07, 0x04, + 0x07, 0x0a, 0x0d, 0x06, 0x0b, 0x0b, 0x0a, 0x04, 0x07, 0x0b, 0x0d, 0x06, 0x04, 0x04, 0x07, 0x04, + + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07, 0x04, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x04, 0x07, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07, 0x04, + + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07, 0x04, + + 0x05, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x07, 0x0b, 0x05, 0x0a, 0x0a, 0x00, 0x0a, 0x11, 0x07, 0x0b, + 0x05, 0x0a, 0x0a, 0x0b, 0x0a, 0x0b, 0x07, 0x0b, 0x05, 0x04, 0x0a, 0x0b, 0x0a, 0x00, 0x07, 0x0b, + 0x05, 0x0a, 0x0a, 0x13, 0x0a, 0x0b, 0x07, 0x0b, 0x05, 0x04, 0x0a, 0x04, 0x0a, 0x00, 0x07, 0x0b, + 0x05, 0x0a, 0x0a, 0x04, 0x0a, 0x0b, 0x07, 0x0b, 0x05, 0x06, 0x0a, 0x04, 0x0a, 0x00, 0x07, 0x0b +}; + +UINT8 bTimingCB[0x100] = +{ + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, + + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0c, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0c, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0c, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0c, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08 +}; + +UINT8 bTimingXXCB[0x100] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00 +}; + +UINT8 bTimingDDFD[0x100] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x14, 0x0a, 0x09, 0x09, 0x09, 0x00, 0x00, 0x0f, 0x14, 0x0a, 0x09, 0x09, 0x09, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x13, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x13, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x13, 0x00, + + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x13, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x13, 0x09, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x13, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x13, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x13, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x13, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x13, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x17, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +UINT8 bTimingED[0x100] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x0c, 0x0c, 0x0f, 0x14, 0x08, 0x0e, 0x08, 0x09, 0x0c, 0x0c, 0x0f, 0x14, 0x08, 0x0e, 0x08, 0x09, + 0x0c, 0x0c, 0x0f, 0x14, 0x08, 0x08, 0x08, 0x09, 0x0c, 0x0c, 0x0f, 0x14, 0x08, 0x08, 0x08, 0x09, + 0x0c, 0x0c, 0x0f, 0x14, 0x08, 0x08, 0x08, 0x12, 0x0c, 0x0c, 0x0f, 0x14, 0x08, 0x08, 0x08, 0x12, + 0x0c, 0x0c, 0x0f, 0x14, 0x08, 0x08, 0x08, 0x00, 0x0c, 0x0c, 0x0f, 0x14, 0x08, 0x08, 0x08, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void EDHandler(UINT32 dwOpcode); +void DDHandler(UINT32 dwOpcode); +void FDHandler(UINT32 dwOpcode); +void CBHandler(UINT32 dwOpcode); + +void PushPopOperations(UINT32 dwOpcode); +void AddRegpairOperations(UINT32 dwOpcode); +void CallHandler(UINT32 dwOpcode); +void MiscHandler(UINT32 dwOpcode); +void IMHandler(UINT32 dwOpcode); +void IRHandler(UINT32 dwOpcode); +void LdRegPairImmediate(UINT32 dwOpcode); +void LoadImmediate(UINT32 dwOpcode); +void LdRegpairPtrByte(UINT32 dwOpcode); +void MathOperation(UINT32 dwOpcode); +void RegIntoMemory(UINT32 dwOpcode); +void JpHandler(UINT32 dwOpcode); +void LdRegImmediate(UINT32 dwOpcode); +void IncRegister(UINT32 dwOpcode); +void DecRegister(UINT32 dwOpcode); +void IncDecRegpair(UINT32 dwOpcode); +void LdRegReg(UINT32 dwOpcode); +void MathOperationDirect(UINT32 dwOpcode); +void JrHandler(UINT32 dwOpcode); +void RetHandler(UINT32 dwOpcode); +void RestartHandler(UINT32 dwOpcode); +void ToRegFromHl(UINT32); +void RraRlaHandler(UINT32); +void LdByteRegpair(UINT32); +void IncDecHLPtr(UINT32 dwOpcode); +void InOutHandler(UINT32 dwOpcode); +void RLCRRCRLRRSLASRASRLHandler(UINT32 dwOpcode); +void BITHandler(UINT32 dwOpcode); +void RESSETHandler(UINT32 dwOpcode); +void PushPopOperationsIndexed(UINT32 dwOpcode); +void LDILDRLDIRLDDRHandler(UINT32); +void LdRegpair(UINT32 dwOpcode); +void ExtendedRegIntoMemory(UINT32 dwOpcode); +void NegHandler(UINT32 dwOpcode); +void ExtendedInHandler(UINT32 dwOpcode); +void ExtendedOutHandler(UINT32 dwOpcode); +void RetIRetNHandler(UINT32 dwOcode); +void AdcSbcRegpair(UINT32 dwOpcode); +void CPICPDCPIRCPDRHandler(UINT32 dwOpcode); +void RRDRLDHandler(UINT32 dwOpcode); +void UndocRegToIndex(UINT32 dwOpcode); +void UndocIndexToReg(UINT32 dwOpcode); +void MathOperationIndexed(UINT32 dwOpcode); +void IncDecIndexed(UINT32 dwOpcode); +void DDFDCBHandler(UINT32 dwOpcode); +void JPIXIYHandler(UINT32 dwOpcode); +void AddIndexHandler(UINT32 dwOpcode); +void SPToIndex(UINT32 dwOpcode); +void LdByteToIndex(UINT32 dwOpcode); +void LdRegIndexOffset(UINT32 dwOpcode); +void IncDecIndexReg(UINT32 dwOpcode); +void ExIndexed(UINT32 dwOpcode); +void UndocIncDecIndexReg(UINT32 dwOpcode); +void UndocLoadHalfIndexReg(UINT32 dwOpcode); +void UndocMathIndex(UINT32 dwOpcode); +void ddcbBitWise(UINT32 dwOpcode); +void LdIndexPtrReg(UINT32 dwOpcode); +void StoreIndexReg(UINT32 dwOpcode); +void LoadIndexReg(UINT32 dwOpcode); +void OTIROTDROUTIOUTDHandler(UINT32 dwOpcode); +void INIRINDRINIINDHandler(UINT32 dwOpcode); + +struct sOp +{ + UINT32 bOpCode; + void (*Emitter)(UINT32); +}; + +struct sOp StandardOps[] = +{ + {0xd3, InOutHandler}, // V + {0xdb, InOutHandler}, // V + + {0x0a, LdByteRegpair}, // V + {0x1a, LdByteRegpair}, // V + + {0x17, RraRlaHandler}, // V + {0x1f, RraRlaHandler}, // V + + {0x05, DecRegister}, // V + {0x0d, DecRegister}, // V + {0x15, DecRegister}, // V + {0x1d, DecRegister}, // V + {0x25, DecRegister}, // V + {0x2d, DecRegister}, // V + {0x3d, DecRegister}, // V + + {0x04, IncRegister}, // V + {0x0c, IncRegister}, // V + {0x14, IncRegister}, // V + {0x1c, IncRegister}, // V + {0x24, IncRegister}, // V + {0x2c, IncRegister}, // V + {0x3c, IncRegister}, // V + + {0x32, RegIntoMemory}, // V + {0x22, RegIntoMemory}, // V + + {0xc3, JpHandler}, // V + {0xc2, JpHandler}, // V + {0xca, JpHandler}, // V + {0xd2, JpHandler}, // V + {0xda, JpHandler}, // V + {0xe2, JpHandler}, // V + {0xea, JpHandler}, // V + {0xf2, JpHandler}, // V + {0xfa, JpHandler}, // V + + + {0x06, LdRegImmediate}, // V + {0x0e, LdRegImmediate}, // V + {0x16, LdRegImmediate}, // V + {0x1e, LdRegImmediate}, // V + {0x26, LdRegImmediate}, // V + {0x2e, LdRegImmediate}, // V + {0x3e, LdRegImmediate}, // V + + {0x0b, IncDecRegpair}, // V + {0x1b, IncDecRegpair}, // V + {0x2b, IncDecRegpair}, // V + {0x3b, IncDecRegpair}, // V + + {0x03, IncDecRegpair}, // V + {0x13, IncDecRegpair}, // V + {0x23, IncDecRegpair}, // V + {0x33, IncDecRegpair}, // V + + {0x34, IncDecHLPtr}, // V + {0x35, IncDecHLPtr}, // V + + {0xcb, CBHandler}, + {0xdd, DDHandler}, + {0xed, EDHandler}, + {0xfd, FDHandler}, + + {0x01, LdRegPairImmediate}, // V + {0x11, LdRegPairImmediate}, // V + {0x21, LdRegPairImmediate}, // V + {0x31, LdRegPairImmediate}, // V + + {0xe3, MiscHandler}, // V + {0x2a, MiscHandler}, // V + {0xfb, MiscHandler}, // V + {0xf9, MiscHandler}, // V + {0xd9, MiscHandler}, // V + {0x76, MiscHandler}, // V + {0x3f, MiscHandler}, // V + {0x37, MiscHandler}, // V + {0x27, MiscHandler}, // V + {0x07, MiscHandler}, // V + {0x08, MiscHandler}, // V + {0x00, MiscHandler}, // V + {0xe9, MiscHandler}, // V + {0xeb, MiscHandler}, // V + {0xf3, MiscHandler}, // V + {0x3a, MiscHandler}, // V + {0x10, MiscHandler}, // V + {0x2f, MiscHandler}, // V + {0x0f, MiscHandler}, // V + + {0x02, LdRegpairPtrByte}, // V + {0x12, LdRegpairPtrByte}, // V + + {0x70, LdRegpairPtrByte}, // V + {0x71, LdRegpairPtrByte}, // V + {0x72, LdRegpairPtrByte}, // V + {0x73, LdRegpairPtrByte}, // V + {0x74, LdRegpairPtrByte}, // V + {0x75, LdRegpairPtrByte}, // V + {0x77, LdRegpairPtrByte}, // V + + {0x36, LdRegpairPtrByte}, // V + + {0x80, MathOperation}, // V + {0x81, MathOperation}, // V + {0x82, MathOperation}, // V + {0x83, MathOperation}, // V + {0x84, MathOperation}, // V + {0x85, MathOperation}, // V + {0x86, MathOperation}, // V + {0x87, MathOperation}, // V + {0x88, MathOperation}, // V + {0x89, MathOperation}, // V + {0x8a, MathOperation}, // V + {0x8b, MathOperation}, // V + {0x8c, MathOperation}, // V + {0x8d, MathOperation}, // V + {0x8e, MathOperation}, // V + {0x8f, MathOperation}, // V + {0x90, MathOperation}, // V + {0x91, MathOperation}, // V + {0x92, MathOperation}, // V + {0x93, MathOperation}, // V + {0x94, MathOperation}, // V + {0x95, MathOperation}, // V + {0x96, MathOperation}, // V + {0x97, MathOperation}, // V + {0x98, MathOperation}, // V + {0x99, MathOperation}, // V + {0x9a, MathOperation}, // V + {0x9b, MathOperation}, // V + {0x9c, MathOperation}, // V + {0x9d, MathOperation}, // V + {0x9e, MathOperation}, // V + {0x9f, MathOperation}, // V + {0xa0, MathOperation}, // V + {0xa1, MathOperation}, // V + {0xa2, MathOperation}, // V + {0xa3, MathOperation}, // V + {0xa4, MathOperation}, // V + {0xa5, MathOperation}, // V + {0xa6, MathOperation}, // V + {0xa7, MathOperation}, // V + {0xa8, MathOperation}, // V + {0xa9, MathOperation}, // V + {0xaa, MathOperation}, // V + {0xab, MathOperation}, // V + {0xac, MathOperation}, // V + {0xad, MathOperation}, // V + {0xae, MathOperation}, // V + {0xaf, MathOperation}, // V + {0xb0, MathOperation}, // V + {0xb1, MathOperation}, // V + {0xb2, MathOperation}, // V + {0xb3, MathOperation}, // V + {0xb4, MathOperation}, // V + {0xb5, MathOperation}, // V + {0xb6, MathOperation}, // V + {0xb7, MathOperation}, // V + {0xb8, MathOperation}, // V + {0xb9, MathOperation}, // V + {0xba, MathOperation}, // V + {0xbb, MathOperation}, // V + {0xbc, MathOperation}, // V + {0xbd, MathOperation}, // V + {0xbe, MathOperation}, // V + {0xbf, MathOperation}, // V + + {0x40, LdRegReg}, // V + {0x41, LdRegReg}, // V + {0x42, LdRegReg}, // V + {0x43, LdRegReg}, // V + {0x44, LdRegReg}, // V + {0x45, LdRegReg}, // V + {0x47, LdRegReg}, // V + {0x48, LdRegReg}, // V + {0x49, LdRegReg}, // V + {0x4a, LdRegReg}, // V + {0x4b, LdRegReg}, // V + {0x4c, LdRegReg}, // V + {0x4d, LdRegReg}, // V + {0x4f, LdRegReg}, // V + {0x50, LdRegReg}, // V + {0x51, LdRegReg}, // V + {0x52, LdRegReg}, // V + {0x53, LdRegReg}, // V + {0x54, LdRegReg}, // V + {0x55, LdRegReg}, // V + {0x57, LdRegReg}, // V + {0x58, LdRegReg}, // V + {0x59, LdRegReg}, // V + {0x5a, LdRegReg}, // V + {0x5b, LdRegReg}, // V + {0x5c, LdRegReg}, // V + {0x5d, LdRegReg}, // V + {0x5f, LdRegReg}, // V + {0x60, LdRegReg}, // V + {0x61, LdRegReg}, // V + {0x62, LdRegReg}, // V + {0x63, LdRegReg}, // V + {0x64, LdRegReg}, // V + {0x65, LdRegReg}, // V + {0x67, LdRegReg}, // V + {0x68, LdRegReg}, // V + {0x69, LdRegReg}, // V + {0x6a, LdRegReg}, // V + {0x6b, LdRegReg}, // V + {0x6c, LdRegReg}, // V + {0x6d, LdRegReg}, // V + {0x6f, LdRegReg}, // V + {0x78, LdRegReg}, // V + {0x79, LdRegReg}, // V + {0x7a, LdRegReg}, // V + {0x7b, LdRegReg}, // V + {0x7c, LdRegReg}, // V + {0x7d, LdRegReg}, // V + {0x7f, LdRegReg}, // V + + {0xc6, MathOperationDirect}, // V + {0xce, MathOperationDirect}, // V + {0xd6, MathOperationDirect}, // V + {0xde, MathOperationDirect}, // V + {0xe6, MathOperationDirect}, // V + {0xee, MathOperationDirect}, // V + {0xf6, MathOperationDirect}, // V + {0xfe, MathOperationDirect}, // V + + {0x18, JrHandler}, // V + {0x20, JrHandler}, // V + {0x28, JrHandler}, // V + {0x30, JrHandler}, // V + {0x38, JrHandler}, + + {0xc4, CallHandler}, // V + {0xcc, CallHandler}, // V + {0xcd, CallHandler}, // V + {0xd4, CallHandler}, // V + {0xdc, CallHandler}, // V + {0xe4, CallHandler}, // V + {0xec, CallHandler}, // V + {0xf4, CallHandler}, // V + {0xfc, CallHandler}, // V + + {0xc9, RetHandler}, // V + {0xc0, RetHandler}, // V + {0xc8, RetHandler}, // V + {0xd0, RetHandler}, // V + {0xd8, RetHandler}, // V + {0xe0, RetHandler}, // V + {0xe8, RetHandler}, // V + {0xf0, RetHandler}, // V + {0xf8, RetHandler}, // V + + {0xc7, RestartHandler}, // V + {0xcf, RestartHandler}, // V + {0xd7, RestartHandler}, // V + {0xdf, RestartHandler}, // V + {0xe7, RestartHandler}, // V + {0xef, RestartHandler}, // V + {0xf7, RestartHandler}, // V + {0xff, RestartHandler}, // V + + {0x46, ToRegFromHl}, // V + {0x4e, ToRegFromHl}, // V + {0x56, ToRegFromHl}, // V + {0x5e, ToRegFromHl}, // V + {0x66, ToRegFromHl}, // V + {0x6e, ToRegFromHl}, // V + {0x7e, ToRegFromHl}, + + {0x09, AddRegpairOperations}, // V + {0x19, AddRegpairOperations}, // V + {0x29, AddRegpairOperations}, // V + {0x39, AddRegpairOperations}, // V + + {0xc5, PushPopOperations}, // V + {0xd5, PushPopOperations}, // V + {0xe5, PushPopOperations}, // V + {0xf5, PushPopOperations}, // V + {0xc1, PushPopOperations}, // V + {0xd1, PushPopOperations}, // V + {0xe1, PushPopOperations}, // V + {0xf1, PushPopOperations}, // V + + // Terminator + + {0xffffffff, NULL} +}; + +struct sOp CBOps[] = +{ + {0x00, RLCRRCRLRRSLASRASRLHandler}, + {0x01, RLCRRCRLRRSLASRASRLHandler}, + {0x02, RLCRRCRLRRSLASRASRLHandler}, + {0x03, RLCRRCRLRRSLASRASRLHandler}, + {0x04, RLCRRCRLRRSLASRASRLHandler}, + {0x05, RLCRRCRLRRSLASRASRLHandler}, + {0x06, RLCRRCRLRRSLASRASRLHandler}, + {0x07, RLCRRCRLRRSLASRASRLHandler}, + {0x08, RLCRRCRLRRSLASRASRLHandler}, + {0x09, RLCRRCRLRRSLASRASRLHandler}, + {0x0a, RLCRRCRLRRSLASRASRLHandler}, + {0x0b, RLCRRCRLRRSLASRASRLHandler}, + {0x0c, RLCRRCRLRRSLASRASRLHandler}, + {0x0d, RLCRRCRLRRSLASRASRLHandler}, + {0x0e, RLCRRCRLRRSLASRASRLHandler}, + {0x0f, RLCRRCRLRRSLASRASRLHandler}, + + {0x10, RLCRRCRLRRSLASRASRLHandler}, + {0x11, RLCRRCRLRRSLASRASRLHandler}, + {0x12, RLCRRCRLRRSLASRASRLHandler}, + {0x13, RLCRRCRLRRSLASRASRLHandler}, + {0x14, RLCRRCRLRRSLASRASRLHandler}, + {0x15, RLCRRCRLRRSLASRASRLHandler}, + {0x16, RLCRRCRLRRSLASRASRLHandler}, + {0x17, RLCRRCRLRRSLASRASRLHandler}, + {0x18, RLCRRCRLRRSLASRASRLHandler}, + {0x19, RLCRRCRLRRSLASRASRLHandler}, + {0x1a, RLCRRCRLRRSLASRASRLHandler}, + {0x1b, RLCRRCRLRRSLASRASRLHandler}, + {0x1c, RLCRRCRLRRSLASRASRLHandler}, + {0x1d, RLCRRCRLRRSLASRASRLHandler}, + {0x1e, RLCRRCRLRRSLASRASRLHandler}, + {0x1f, RLCRRCRLRRSLASRASRLHandler}, + + {0x20, RLCRRCRLRRSLASRASRLHandler}, + {0x21, RLCRRCRLRRSLASRASRLHandler}, + {0x22, RLCRRCRLRRSLASRASRLHandler}, + {0x23, RLCRRCRLRRSLASRASRLHandler}, + {0x24, RLCRRCRLRRSLASRASRLHandler}, + {0x25, RLCRRCRLRRSLASRASRLHandler}, + {0x26, RLCRRCRLRRSLASRASRLHandler}, + {0x27, RLCRRCRLRRSLASRASRLHandler}, + {0x28, RLCRRCRLRRSLASRASRLHandler}, + {0x29, RLCRRCRLRRSLASRASRLHandler}, + {0x2a, RLCRRCRLRRSLASRASRLHandler}, + {0x2b, RLCRRCRLRRSLASRASRLHandler}, + {0x2c, RLCRRCRLRRSLASRASRLHandler}, + {0x2d, RLCRRCRLRRSLASRASRLHandler}, + {0x2e, RLCRRCRLRRSLASRASRLHandler}, + {0x2f, RLCRRCRLRRSLASRASRLHandler}, + + {0x30, RLCRRCRLRRSLASRASRLHandler}, + {0x31, RLCRRCRLRRSLASRASRLHandler}, + {0x32, RLCRRCRLRRSLASRASRLHandler}, + {0x33, RLCRRCRLRRSLASRASRLHandler}, + {0x34, RLCRRCRLRRSLASRASRLHandler}, + {0x35, RLCRRCRLRRSLASRASRLHandler}, + {0x36, RLCRRCRLRRSLASRASRLHandler}, + {0x37, RLCRRCRLRRSLASRASRLHandler}, + + {0x38, RLCRRCRLRRSLASRASRLHandler}, + {0x39, RLCRRCRLRRSLASRASRLHandler}, + {0x3a, RLCRRCRLRRSLASRASRLHandler}, + {0x3b, RLCRRCRLRRSLASRASRLHandler}, + {0x3c, RLCRRCRLRRSLASRASRLHandler}, + {0x3d, RLCRRCRLRRSLASRASRLHandler}, + {0x3e, RLCRRCRLRRSLASRASRLHandler}, + {0x3f, RLCRRCRLRRSLASRASRLHandler}, + + {0x40, BITHandler}, + {0x41, BITHandler}, + {0x42, BITHandler}, + {0x43, BITHandler}, + {0x44, BITHandler}, + {0x45, BITHandler}, + {0x46, BITHandler}, + {0x47, BITHandler}, + {0x48, BITHandler}, + {0x49, BITHandler}, + {0x4a, BITHandler}, + {0x4b, BITHandler}, + {0x4c, BITHandler}, + {0x4d, BITHandler}, + {0x4e, BITHandler}, + {0x4f, BITHandler}, + + {0x50, BITHandler}, + {0x51, BITHandler}, + {0x52, BITHandler}, + {0x53, BITHandler}, + {0x54, BITHandler}, + {0x55, BITHandler}, + {0x56, BITHandler}, + {0x57, BITHandler}, + {0x58, BITHandler}, + {0x59, BITHandler}, + {0x5a, BITHandler}, + {0x5b, BITHandler}, + {0x5c, BITHandler}, + {0x5d, BITHandler}, + {0x5e, BITHandler}, + {0x5f, BITHandler}, + + {0x60, BITHandler}, + {0x61, BITHandler}, + {0x62, BITHandler}, + {0x63, BITHandler}, + {0x64, BITHandler}, + {0x65, BITHandler}, + {0x66, BITHandler}, + {0x67, BITHandler}, + {0x68, BITHandler}, + {0x69, BITHandler}, + {0x6a, BITHandler}, + {0x6b, BITHandler}, + {0x6c, BITHandler}, + {0x6d, BITHandler}, + {0x6e, BITHandler}, + {0x6f, BITHandler}, + + {0x70, BITHandler}, + {0x71, BITHandler}, + {0x72, BITHandler}, + {0x73, BITHandler}, + {0x74, BITHandler}, + {0x75, BITHandler}, + {0x76, BITHandler}, + {0x77, BITHandler}, + {0x78, BITHandler}, + {0x79, BITHandler}, + {0x7a, BITHandler}, + {0x7b, BITHandler}, + {0x7c, BITHandler}, + {0x7d, BITHandler}, + {0x7e, BITHandler}, + {0x7f, BITHandler}, + + // RES + + {0x80, RESSETHandler}, + {0x81, RESSETHandler}, + {0x82, RESSETHandler}, + {0x83, RESSETHandler}, + {0x84, RESSETHandler}, + {0x85, RESSETHandler}, + {0x86, RESSETHandler}, + {0x87, RESSETHandler}, + {0x88, RESSETHandler}, + {0x89, RESSETHandler}, + {0x8a, RESSETHandler}, + {0x8b, RESSETHandler}, + {0x8c, RESSETHandler}, + {0x8d, RESSETHandler}, + {0x8e, RESSETHandler}, + {0x8f, RESSETHandler}, + + {0x90, RESSETHandler}, + {0x91, RESSETHandler}, + {0x92, RESSETHandler}, + {0x93, RESSETHandler}, + {0x94, RESSETHandler}, + {0x95, RESSETHandler}, + {0x96, RESSETHandler}, + {0x97, RESSETHandler}, + {0x98, RESSETHandler}, + {0x99, RESSETHandler}, + {0x9a, RESSETHandler}, + {0x9b, RESSETHandler}, + {0x9c, RESSETHandler}, + {0x9d, RESSETHandler}, + {0x9e, RESSETHandler}, + {0x9f, RESSETHandler}, + + {0xa0, RESSETHandler}, + {0xa1, RESSETHandler}, + {0xa2, RESSETHandler}, + {0xa3, RESSETHandler}, + {0xa4, RESSETHandler}, + {0xa5, RESSETHandler}, + {0xa6, RESSETHandler}, + {0xa7, RESSETHandler}, + {0xa8, RESSETHandler}, + {0xa9, RESSETHandler}, + {0xaa, RESSETHandler}, + {0xab, RESSETHandler}, + {0xac, RESSETHandler}, + {0xad, RESSETHandler}, + {0xae, RESSETHandler}, + {0xaf, RESSETHandler}, + + {0xb0, RESSETHandler}, + {0xb1, RESSETHandler}, + {0xb2, RESSETHandler}, + {0xb3, RESSETHandler}, + {0xb4, RESSETHandler}, + {0xb5, RESSETHandler}, + {0xb6, RESSETHandler}, + {0xb7, RESSETHandler}, + {0xb8, RESSETHandler}, + {0xb9, RESSETHandler}, + {0xba, RESSETHandler}, + {0xbb, RESSETHandler}, + {0xbc, RESSETHandler}, + {0xbd, RESSETHandler}, + {0xbe, RESSETHandler}, + {0xbf, RESSETHandler}, + + // SET + + {0xc0, RESSETHandler}, + {0xc1, RESSETHandler}, + {0xc2, RESSETHandler}, + {0xc3, RESSETHandler}, + {0xc4, RESSETHandler}, + {0xc5, RESSETHandler}, + {0xc6, RESSETHandler}, + {0xc7, RESSETHandler}, + {0xc8, RESSETHandler}, + {0xc9, RESSETHandler}, + {0xca, RESSETHandler}, + {0xcb, RESSETHandler}, + {0xcc, RESSETHandler}, + {0xcd, RESSETHandler}, + {0xce, RESSETHandler}, + {0xcf, RESSETHandler}, + + {0xd0, RESSETHandler}, + {0xd1, RESSETHandler}, + {0xd2, RESSETHandler}, + {0xd3, RESSETHandler}, + {0xd4, RESSETHandler}, + {0xd5, RESSETHandler}, + {0xd6, RESSETHandler}, + {0xd7, RESSETHandler}, + {0xd8, RESSETHandler}, + {0xd9, RESSETHandler}, + {0xda, RESSETHandler}, + {0xdb, RESSETHandler}, + {0xdc, RESSETHandler}, + {0xdd, RESSETHandler}, + {0xde, RESSETHandler}, + {0xdf, RESSETHandler}, + + {0xe0, RESSETHandler}, + {0xe1, RESSETHandler}, + {0xe2, RESSETHandler}, + {0xe3, RESSETHandler}, + {0xe4, RESSETHandler}, + {0xe5, RESSETHandler}, + {0xe6, RESSETHandler}, + {0xe7, RESSETHandler}, + {0xe8, RESSETHandler}, + {0xe9, RESSETHandler}, + {0xea, RESSETHandler}, + {0xeb, RESSETHandler}, + {0xec, RESSETHandler}, + {0xed, RESSETHandler}, + {0xee, RESSETHandler}, + {0xef, RESSETHandler}, + + {0xf0, RESSETHandler}, + {0xf1, RESSETHandler}, + {0xf2, RESSETHandler}, + {0xf3, RESSETHandler}, + {0xf4, RESSETHandler}, + {0xf5, RESSETHandler}, + {0xf6, RESSETHandler}, + {0xf7, RESSETHandler}, + {0xf8, RESSETHandler}, + {0xf9, RESSETHandler}, + {0xfa, RESSETHandler}, + {0xfb, RESSETHandler}, + {0xfc, RESSETHandler}, + {0xfd, RESSETHandler}, + {0xfe, RESSETHandler}, + {0xff, RESSETHandler}, + + // Terminator + + {0xffffffff, NULL} +}; + +struct sOp EDOps[] = +{ + {0x67, RRDRLDHandler}, + {0x6f, RRDRLDHandler}, + {0x42, AdcSbcRegpair}, + {0x4a, AdcSbcRegpair}, + {0x52, AdcSbcRegpair}, + {0x5a, AdcSbcRegpair}, + {0x62, AdcSbcRegpair}, + {0x6a, AdcSbcRegpair}, + {0x72, AdcSbcRegpair}, + {0x7a, AdcSbcRegpair}, + {0x45, RetIRetNHandler}, + {0x4d, RetIRetNHandler}, + {0x44, NegHandler}, + {0xa0, LDILDRLDIRLDDRHandler}, + {0xa8, LDILDRLDIRLDDRHandler}, + {0xb0, LDILDRLDIRLDDRHandler}, + {0xb8, LDILDRLDIRLDDRHandler}, + {0x57, IRHandler}, + {0x5F, IRHandler}, + {0x47, IRHandler}, + {0x4F, IRHandler}, + {0x46, IMHandler}, + {0x56, IMHandler}, + {0x5e, IMHandler}, + {0x4b, LdRegpair}, + {0x5b, LdRegpair}, + {0x7b, LdRegpair}, + {0x43, ExtendedRegIntoMemory}, + {0x53, ExtendedRegIntoMemory}, + {0x63, ExtendedRegIntoMemory}, + {0x73, ExtendedRegIntoMemory}, + {0x40, ExtendedInHandler}, + {0x48, ExtendedInHandler}, + {0x50, ExtendedInHandler}, + {0x58, ExtendedInHandler}, + {0x60, ExtendedInHandler}, + {0x68, ExtendedInHandler}, + {0x78, ExtendedInHandler}, + {0x41, ExtendedOutHandler}, + {0x49, ExtendedOutHandler}, + {0x51, ExtendedOutHandler}, + {0x59, ExtendedOutHandler}, + {0x61, ExtendedOutHandler}, + {0x69, ExtendedOutHandler}, + {0x79, ExtendedOutHandler}, + {0xa1, CPICPDCPIRCPDRHandler}, + {0xa9, CPICPDCPIRCPDRHandler}, + {0xb1, CPICPDCPIRCPDRHandler}, + {0xb9, CPICPDCPIRCPDRHandler}, + + {0xbb, OTIROTDROUTIOUTDHandler}, // OTDR + {0xb3, OTIROTDROUTIOUTDHandler}, // OTIR + {0xab, OTIROTDROUTIOUTDHandler}, // OUTD + {0xa3, OTIROTDROUTIOUTDHandler}, // OUTI + + {0xb2, INIRINDRINIINDHandler}, // INIR + {0xba, INIRINDRINIINDHandler}, // INDR + {0xa2, INIRINDRINIINDHandler}, // INI + {0xaa, INIRINDRINIINDHandler}, // IND + + // Terminator + + {0xffffffff, NULL} +}; + +struct sOp DDFDOps[] = +{ + {0x35, IncDecIndexed}, + {0x34, IncDecIndexed}, + {0xcb, DDFDCBHandler}, + {0x86, MathOperationIndexed}, + {0x8e, MathOperationIndexed}, + {0x96, MathOperationIndexed}, + {0x9e, MathOperationIndexed}, + {0xa6, MathOperationIndexed}, + {0xae, MathOperationIndexed}, + {0xb6, MathOperationIndexed}, + {0xbe, MathOperationIndexed}, + + {0xe1, PushPopOperationsIndexed}, + {0xe5, PushPopOperationsIndexed}, + {0x21, LoadImmediate}, + {0xe9, JPIXIYHandler}, + {0x09, AddIndexHandler}, + {0x19, AddIndexHandler}, + {0x29, AddIndexHandler}, + {0x39, AddIndexHandler}, + {0xf9, SPToIndex}, + {0x36, LdByteToIndex}, + {0x46, LdRegIndexOffset}, + {0x4e, LdRegIndexOffset}, + {0x56, LdRegIndexOffset}, + {0x5e, LdRegIndexOffset}, + {0x66, LdRegIndexOffset}, + {0x6e, LdRegIndexOffset}, + {0x7e, LdRegIndexOffset}, + + {0x70, LdIndexPtrReg}, + {0x71, LdIndexPtrReg}, + {0x72, LdIndexPtrReg}, + {0x73, LdIndexPtrReg}, + {0x74, LdIndexPtrReg}, + {0x75, LdIndexPtrReg}, + {0x77, LdIndexPtrReg}, + + {0x23, IncDecIndexReg}, + {0x2b, IncDecIndexReg}, + + {0x22, StoreIndexReg}, + {0x2a, LoadIndexReg}, + {0xe3, ExIndexed}, + + {0x44, UndocRegToIndex}, + {0x45, UndocRegToIndex}, + {0x4c, UndocRegToIndex}, + {0x4d, UndocRegToIndex}, + {0x54, UndocRegToIndex}, + {0x55, UndocRegToIndex}, + {0x5c, UndocRegToIndex}, + {0x5d, UndocRegToIndex}, + {0x7c, UndocRegToIndex}, + {0x7d, UndocRegToIndex}, + + {0x60, UndocIndexToReg}, + {0x61, UndocIndexToReg}, + {0x62, UndocIndexToReg}, + {0x63, UndocIndexToReg}, + {0x64, UndocIndexToReg}, + {0x65, UndocIndexToReg}, + {0x67, UndocIndexToReg}, + {0x68, UndocIndexToReg}, + {0x69, UndocIndexToReg}, + {0x6a, UndocIndexToReg}, + {0x6b, UndocIndexToReg}, + {0x6c, UndocIndexToReg}, + {0x6d, UndocIndexToReg}, + {0x6f, UndocIndexToReg}, + + {0x24, UndocIncDecIndexReg}, + {0x25, UndocIncDecIndexReg}, + {0x2c, UndocIncDecIndexReg}, + {0x2d, UndocIncDecIndexReg}, + + {0x26, UndocLoadHalfIndexReg}, + {0x2e, UndocLoadHalfIndexReg}, + + {0x84, UndocMathIndex}, + {0x85, UndocMathIndex}, + {0x8c, UndocMathIndex}, + {0x8d, UndocMathIndex}, + + {0x94, UndocMathIndex}, + {0x95, UndocMathIndex}, + {0x9c, UndocMathIndex}, + {0x9d, UndocMathIndex}, + + {0xa4, UndocMathIndex}, + {0xa5, UndocMathIndex}, + {0xac, UndocMathIndex}, + {0xad, UndocMathIndex}, + + {0xb4, UndocMathIndex}, + {0xb5, UndocMathIndex}, + {0xbc, UndocMathIndex}, + {0xbd, UndocMathIndex}, + + // Terminator + + {0xffffffff, NULL} +}; + +struct sOp DDFDCBOps[] = +{ + {0x06, ddcbBitWise}, + {0x0e, ddcbBitWise}, + {0x16, ddcbBitWise}, + {0x1e, ddcbBitWise}, + {0x26, ddcbBitWise}, + {0x2e, ddcbBitWise}, + {0x3e, ddcbBitWise}, + {0x46, ddcbBitWise}, + {0x4e, ddcbBitWise}, + {0x56, ddcbBitWise}, + {0x5e, ddcbBitWise}, + {0x66, ddcbBitWise}, + {0x6e, ddcbBitWise}, + {0x76, ddcbBitWise}, + {0x7e, ddcbBitWise}, + {0x86, ddcbBitWise}, + {0x8e, ddcbBitWise}, + {0x96, ddcbBitWise}, + {0x9e, ddcbBitWise}, + {0xa6, ddcbBitWise}, + {0xae, ddcbBitWise}, + {0xb6, ddcbBitWise}, + {0xbe, ddcbBitWise}, + {0xc6, ddcbBitWise}, + {0xce, ddcbBitWise}, + {0xd6, ddcbBitWise}, + {0xde, ddcbBitWise}, + {0xe6, ddcbBitWise}, + {0xee, ddcbBitWise}, + {0xf6, ddcbBitWise}, + {0xfe, ddcbBitWise}, + + // Terminator + + {0xffffffff, NULL} +}; + +void InvalidInstructionC(UINT32 dwCount) +{ + fprintf(fp, " InvalidInstruction(%ld);\n", dwCount); +} + +UINT32 Timing(UINT8 bWho, UINT32 dwOpcode) +{ + UINT32 dwTiming = 0; + + assert(dwOpcode < 0x100); + + if (TIMING_REGULAR == bWho) // Regular? + dwTiming = bTimingRegular[dwOpcode]; + else + if (TIMING_CB == bWho) + dwTiming = bTimingCB[dwOpcode]; + else + if (TIMING_DDFD == bWho) + dwTiming = bTimingDDFD[dwOpcode]; + else + if (TIMING_ED == bWho) + dwTiming = bTimingED[dwOpcode]; + else + if (TIMING_XXCB == bWho) + dwTiming = bTimingXXCB[dwOpcode]; + else + if (TIMING_EXCEPT == bWho) + dwTiming = dwOpcode; + else + assert(0); + + if (0 == dwTiming) + { + fprintf(stderr, "Opcode: %.2x:%.2x - Not zero!\n", bWho, dwOpcode); + fclose(fp); + exit(1); + } + + return(dwTiming); +} + +void IndexedOffset(UINT8 *Localmz80Index) +{ + fprintf(fp, " mov dl, [esi] ; Fetch our offset\n"); + fprintf(fp, " inc esi ; Move past the offset\n"); + fprintf(fp, " or dl, dl ; Is this bad boy signed?\n"); + fprintf(fp, " jns notSigned%ld ; Nope!\n", dwGlobalLabel); + fprintf(fp, " dec dh ; Make it FFable\n"); + fprintf(fp, "notSigned%ld:\n", dwGlobalLabel); + fprintf(fp, " add dx, [_z80%s] ; Our offset!\n", Localmz80Index); + ++dwGlobalLabel; +} + +void CBHandler(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp, ";\n"); + fprintf(fp, "; Handler for all CBxx instructions\n"); + fprintf(fp, ";\n"); + sprintf(string, "RegInst%.2x", dwOpcode); + ProcBegin(0xffffffff); + fprintf(fp, " mov dl, [esi]\n"); + fprintf(fp, " inc esi\n"); + fprintf(fp, " jmp dword [z80PrefixCB+edx*4]\n\n"); + fprintf(fp, "\n\n"); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " CBHandler();\n"); + } + else + { + assert(0); + } +} + +void EDHandler(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp, ";\n"); + fprintf(fp, "; Handler for all EDxx instructions\n"); + fprintf(fp, ";\n"); + sprintf(string, "RegInst%.2x", dwOpcode); + ProcBegin(0xffffffff); + fprintf(fp, " mov dl, [esi]\n"); + fprintf(fp, " inc esi\n"); + fprintf(fp, " jmp dword [z80PrefixED+edx*4]\n\n"); + fprintf(fp, "\n\n"); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " EDHandler();\n"); + } + else + { + assert(0); + } +} + +void DDHandler(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp, ";\n"); + fprintf(fp, "; Handler for all DDxx instructions\n"); + fprintf(fp, ";\n"); + sprintf(string, "RegInst%.2x", dwOpcode); + ProcBegin(0xffffffff); + fprintf(fp, " mov dl, [esi]\n"); + fprintf(fp, " inc esi\n"); + fprintf(fp, " jmp dword [z80PrefixDD+edx*4]\n\n"); + fprintf(fp, "\n\n"); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " DDHandler();\n"); + } + else + { + assert(0); + } +} + +void FDHandler(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp, ";\n"); + fprintf(fp, "; Handler for all FDxx instructions\n"); + fprintf(fp, ";\n"); + sprintf(string, "RegInst%.2x", dwOpcode); + ProcBegin(0xffffffff); + fprintf(fp, " mov dl, [esi]\n"); + fprintf(fp, " inc esi\n"); + fprintf(fp, " jmp dword [z80PrefixFD+edx*4]\n\n"); + fprintf(fp, "\n\n"); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " FDHandler();\n"); + } + else + { + assert(0); + } +} + +StandardHeader() +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp,"; For assembly by NASM only\n"); + fprintf(fp,"bits 32\n\n"); + + fprintf(fp,"; Theory of operation\n\n"); + fprintf(fp,"; EDI=General purpose\n"); + fprintf(fp,"; ESI=Program counter + base address\n"); + fprintf(fp,"; EBP=z80Base\n"); + fprintf(fp,"; AX=AF\n"); + fprintf(fp,"; BX=HL\n"); + fprintf(fp,"; CX=BC\n"); + fprintf(fp,"; DX=General purpose\n\n"); + + if (bUseStack) + fprintf(fp, "; Using stack calling conventions\n"); + else + fprintf(fp, "; Using register calling conventions\n"); + + if (b16BitIo) + fprintf(fp, "; Extended input/output instructions treat (BC) as I/O address\n"); + else + fprintf(fp, "; Extended input/output instructions treat (C) as I/O address\n\n"); + + fprintf(fp, "IFF1 equ 01h\n"); + fprintf(fp, "IFF2 equ 02h\n"); + + fprintf(fp, "CPUREG_PC equ 00h\n"); + fprintf(fp, "CPUREG_SP equ 01h\n"); + fprintf(fp, "CPUREG_AF equ 02h\n"); + fprintf(fp, "CPUREG_BC equ 03h\n"); + fprintf(fp, "CPUREG_DE equ 04h\n"); + fprintf(fp, "CPUREG_HL equ 05h\n"); + fprintf(fp, "CPUREG_AFPRIME equ 06h\n"); + fprintf(fp, "CPUREG_BCPRIME equ 07h\n"); + fprintf(fp, "CPUREG_DEPRIME equ 08h\n"); + fprintf(fp, "CPUREG_HLPRIME equ 09h\n"); + fprintf(fp, "CPUREG_IX equ 0ah\n"); + fprintf(fp, "CPUREG_IY equ 0bh\n"); + fprintf(fp, "CPUREG_I equ 0ch\n"); + fprintf(fp, "CPUREG_A equ 0dh\n"); + fprintf(fp, "CPUREG_F equ 0eh\n"); + fprintf(fp, "CPUREG_B equ 0fh\n"); + fprintf(fp, "CPUREG_C equ 10h\n"); + fprintf(fp, "CPUREG_D equ 11h\n"); + fprintf(fp, "CPUREG_E equ 12h\n"); + fprintf(fp, "CPUREG_H equ 13h\n"); + fprintf(fp, "CPUREG_L equ 14h\n"); + fprintf(fp, "CPUREG_IFF1 equ 15h\n"); + fprintf(fp, "CPUREG_IFF2 equ 16h\n"); + fprintf(fp, "CPUREG_CARRY equ 17h\n"); + fprintf(fp, "CPUREG_NEGATIVE equ 18h\n"); + fprintf(fp, "CPUREG_PARITY equ 19h\n"); + fprintf(fp, "CPUREG_OVERFLOW equ 1ah\n"); + fprintf(fp, "CPUREG_HALFCARRY equ 1bh\n"); + fprintf(fp, "CPUREG_ZERO equ 1ch\n"); + fprintf(fp, "CPUREG_SIGN equ 1dh\n"); + fprintf(fp, "CPUREG_MAXINDEX equ 1eh\n\n"); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, "/* Multi-Z80 32 Bit emulator */\n"); + fprintf(fp, "\n"); + fprintf(fp, "/* Copyright 1996-2000 Neil Bradley, All rights reserved\n"); + fprintf(fp, " *\n"); + fprintf(fp, " * License agreement:\n"); + fprintf(fp, " *\n"); + fprintf(fp, " * (MZ80 Refers to both the assembly code emitted by makeZ80.c and makeZ80.c\n"); + fprintf(fp, " * itself)\n"); + fprintf(fp, " *\n"); + fprintf(fp, " * MZ80 May be distributed in unmodified form to any medium.\n"); + fprintf(fp, " *\n"); + fprintf(fp, " * MZ80 May not be sold, or sold as a part of a commercial package without\n"); + fprintf(fp, " * the express written permission of Neil Bradley (neil@synthcom.com). This\n"); + fprintf(fp, " * includes shareware.\n"); + fprintf(fp, " *\n"); + fprintf(fp, " * Modified versions of MZ80 may not be publicly redistributed without author\n"); + fprintf(fp, " * approval (neil@synthcom.com). This includes distributing via a publicly\n"); + fprintf(fp, " * accessible LAN. You may make your own source modifications and distribute\n"); + fprintf(fp, " * MZ80 in source or object form, but if you make modifications to MZ80\n"); + fprintf(fp, " * then it should be noted in the top as a comment in makeZ80.c.\n"); + fprintf(fp, " *\n"); + fprintf(fp, " * MZ80 Licensing for commercial applications is available. Please email\n"); + fprintf(fp, " * neil@synthcom.com for details.\n"); + fprintf(fp, " *\n"); + fprintf(fp, " * Synthcom Systems, Inc, and Neil Bradley will not be held responsible for\n"); + fprintf(fp, " * any damage done by the use of MZ80. It is purely \"as-is\".\n"); + fprintf(fp, " *\n"); + fprintf(fp, " * If you use MZ80 in a freeware application, credit in the following text:\n"); + fprintf(fp, " *\n"); + fprintf(fp, " * \"Multi-Z80 CPU emulator by Neil Bradley (neil@synthcom.com)\"\n"); + fprintf(fp, " *\n"); + fprintf(fp, " * must accompany the freeware application within the application itself or\n"); + fprintf(fp, " * in the documentation.\n"); + fprintf(fp, " *\n"); + fprintf(fp, " * Legal stuff aside:\n"); + fprintf(fp, " *\n"); + fprintf(fp, " * If you find problems with MZ80, please email the author so they can get\n"); + fprintf(fp, " * resolved. If you find a bug and fix it, please also email the author so\n"); + fprintf(fp, " * that those bug fixes can be propogated to the installed base of MZ80\n"); + fprintf(fp, " * users. If you find performance improvements or problems with MZ80, please\n"); + fprintf(fp, " * email the author with your changes/suggestions and they will be rolled in\n"); + fprintf(fp, " * with subsequent releases of MZ80.\n"); + fprintf(fp, " *\n"); + fprintf(fp, " * The whole idea of this emulator is to have the fastest available 32 bit\n"); + fprintf(fp, " * Multi-Z80 emulator for the PC, giving maximum performance. \n"); + fprintf(fp, " */\n\n"); + fprintf(fp, "#include \n"); + fprintf(fp, "#include \n"); + fprintf(fp, "#include \n"); + fprintf(fp, "#include \"mz80.h\"\n"); + + // HACK HACK + + fprintf(fp, "UINT32 z80intAddr;\n"); + fprintf(fp, "UINT32 z80pc;\n"); + } + else + { + // Whoops. Unknown emission type. + + assert(0); + } + + fprintf(fp, "\n\n"); +} + +Alignment() +{ + fprintf(fp, "\ntimes ($$-$) & 3 nop ; pad with NOPs to 4-byte boundary\n\n"); +} + +void ProcBegin(UINT32 dwOpcode) +{ + Alignment(); + fprintf(fp, "%s:\n", procname); +} + +void SetSubFlagsSZHVC(UINT8 *pszLeft, UINT8 *pszRight) +{ + fprintf(fp, " cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | \n"); + fprintf(fp, " Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) |\n"); + fprintf(fp, " pbSubSbcTable[((UINT32) %s << 8) | %s];\n", pszLeft, pszRight); +} + +void SetSbcFlagsSZHVC(UINT8 *pszLeft, UINT8 *pszRight) +{ + fprintf(fp, " cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | \n"); + fprintf(fp, " Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) |\n"); + fprintf(fp, " pbSubSbcTable[((UINT32) %s << 8) | %s | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)];\n", pszLeft, pszRight); +} + +void SetAddFlagsSZHVC(UINT8 *pszLeft, UINT8 *pszRight) +{ + fprintf(fp, " cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | \n"); + fprintf(fp, " Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) |\n"); + fprintf(fp, " pbAddAdcTable[((UINT32) %s << 8) | %s];\n", pszLeft, pszRight); +} + +void SetAdcFlagsSZHVC(UINT8 *pszLeft, UINT8 *pszRight) +{ + fprintf(fp, " cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | \n"); + fprintf(fp, " Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) |\n"); + fprintf(fp, " pbAddAdcTable[((UINT32) %s << 8) | %s | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)];\n", pszLeft, pszRight); +} + +UINT32 dwOverflowCount = 0; + +SetOverflow() +{ + fprintf(fp, " seto dl\n"); + fprintf(fp, " and ah, 0fbh ; Knock out parity/overflow\n"); + fprintf(fp, " shl dl, 2\n"); + fprintf(fp, " or ah, dl\n"); +} + +void FetchNextInstruction(UINT32 dwOpcode) +{ + if (0xffffffff != dwOpcode) + { + fprintf(fp, " sub edi, byte %ld\n", Timing(bCurrentMode, dwOpcode)); + + if (bCurrentMode == TIMING_REGULAR) + fprintf(fp, " js near noMoreExec\n"); + else + fprintf(fp, " js near noMoreExec\n"); + } + + fprintf(fp, " mov dl, byte [esi] ; Get our next instruction\n"); + fprintf(fp, " inc esi ; Increment PC\n"); + fprintf(fp, " jmp dword [z80regular+edx*4]\n\n"); +} + +void WriteValueToMemory(UINT8 *pszAddress, UINT8 *pszValue) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp, " mov [cyclesRemaining], edi\n"); + fprintf(fp, " mov [_z80af], ax ; Store AF\n"); + + // First off, load our byte to write into al after we've saved AF + + if (strcmp(pszValue, "al") != 0) + fprintf(fp, " mov al, %s ; And our data to write\n", pszValue); + if (strcmp(pszValue, "[esi]") == 0) // Immediate value? + fprintf(fp, " inc esi ; Increment our program counter\n"); + + // Now get the address in DX - regardless of what it is + + if (strcmp(pszAddress, "[_z80de]") == 0 || + strcmp(pszAddress, "[_orgval]") == 0 || + strcmp(pszAddress, "[_z80ix]") == 0 || + strcmp(pszAddress, "[_z80iy]") == 0) + fprintf(fp, " mov dx, %s\n", pszAddress); + + fprintf(fp, " mov edi, [_z80MemWrite] ; Point to the write array\n\n", cpubasename); + fprintf(fp, "checkLoop%ld:\n", dwGlobalLabel); + fprintf(fp, " cmp [edi], word 0ffffh ; End of our list?\n"); + fprintf(fp, " je memoryWrite%ld ; Yes - go write it!\n", dwGlobalLabel); + + if (strcmp(pszAddress, "[_z80de]") == 0 || + strcmp(pszAddress, "[_orgval]") == 0 || + strcmp(pszAddress, "[_z80ix]") == 0 || + strcmp(pszAddress, "[_z80iy]") == 0) + fprintf(fp, " cmp dx, [edi] ; Are we smaller?\n", pszAddress); + else + fprintf(fp, " cmp %s, [edi] ; Are we smaller?\n", pszAddress); + + fprintf(fp, " jb nextAddr%ld ; Yes... go to the next addr\n", dwGlobalLabel); + + if (strcmp(pszAddress, "[_z80de]") == 0 || + strcmp(pszAddress, "[_orgval]") == 0 || + strcmp(pszAddress, "[_z80ix]") == 0 || + strcmp(pszAddress, "[_z80iy]") == 0) + fprintf(fp, " cmp dx, [edi+4] ; Are we smaller?\n", pszAddress); + else + fprintf(fp, " cmp %s, [edi+4] ; Are we smaller?\n", pszAddress); + + fprintf(fp, " jbe callRoutine%ld ; If not, go call it!\n\n", dwGlobalLabel); + fprintf(fp, "nextAddr%ld:\n", dwGlobalLabel); + fprintf(fp, " add edi, 10h ; Next structure, please\n"); + fprintf(fp, " jmp short checkLoop%ld\n\n", dwGlobalLabel); + fprintf(fp, "callRoutine%ld:\n", dwGlobalLabel); + + // Save off our registers! + + if ((strcmp(pszAddress, "dx") != 0) && (strcmp(pszAddress, "[_z80de]") != 0) && + (strcmp(pszAddress, "[_z80ix]") != 0) && + (strcmp(pszAddress, "[_orgval]") != 0) && + (strcmp(pszAddress, "[_z80iy]") != 0)) + fprintf(fp, " mov dx, %s ; Get our address to target\n", pszAddress); + + fprintf(fp, " call WriteMemoryByte ; Go write the data!\n"); + fprintf(fp, " jmp short WriteMacroExit%ld\n", dwGlobalLabel); + + fprintf(fp, "memoryWrite%ld:\n", dwGlobalLabel); + + if (strcmp(pszValue, "[esi]") == 0) + fprintf(fp, " mov [ebp + e%s], al ; Store our direct value\n", pszAddress); + else + { + if (pszValue[0] == 'b' && pszValue[1] == 'y' && pszValue[2] == 't') + { + fprintf(fp, " mov edi, edx\n"); + assert(strcmp(pszValue, "dl") != 0); + + fprintf(fp, " mov dl, %s\n", pszValue); + + if (strcmp(pszAddress, "dx") == 0) + fprintf(fp, " mov [ebp + edi], dl\n"); + else + fprintf(fp, " mov [ebp + e%s], dl\n", pszAddress); + + fprintf(fp, " mov edx, edi\n"); + } + else + { + if (strcmp(pszAddress, "[_z80de]") != 0 && + strcmp(pszAddress, "[_orgval]") != 0 && + strcmp(pszAddress, "[_z80ix]") != 0 && + strcmp(pszAddress, "[_z80iy]") != 0) + fprintf(fp, " mov [ebp + e%s], %s\n", pszAddress, pszValue); + else + fprintf(fp, " mov [ebp + edx], al\n"); + } + } + + fprintf(fp, " mov ax, [_z80af] ; Get our accumulator and flags\n"); + + fprintf(fp, "WriteMacroExit%ld:\n", dwGlobalLabel); + fprintf(fp, " mov edi, [cyclesRemaining]\n"); + + ++dwGlobalLabel; + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */\n"); + fprintf(fp, " while (psMemWrite->lowAddr != 0xffffffff)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " if ((%s >= psMemWrite->lowAddr) && (%s <= psMemWrite->highAddr))\n", pszAddress, pszAddress); + fprintf(fp, " {\n"); + fprintf(fp, " cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base;\n"); + fprintf(fp, " if (psMemWrite->memoryCall)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " psMemWrite->memoryCall(%s, %s, psMemWrite);\n", pszAddress, pszValue); + fprintf(fp, " }\n"); + fprintf(fp, " else\n"); + fprintf(fp, " {\n"); + fprintf(fp, " *((UINT8 *) psMemWrite->pUserArea + (%s - psMemWrite->lowAddr)) = %s;\n", pszAddress, pszValue); + fprintf(fp, " }\n"); + fprintf(fp, " psMemWrite = NULL;\n"); + fprintf(fp, " break;\n"); + fprintf(fp, " }\n"); + fprintf(fp, " ++psMemWrite;\n"); + fprintf(fp, " }\n\n"); + fprintf(fp, " if (psMemWrite)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " cpu.z80Base[%s] = (UINT8) %s;\n", pszAddress, pszValue); + fprintf(fp, " }\n\n"); + } +} + +void WriteWordToMemory(UINT8 *pszAddress, UINT8 *pszTarget) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp, " mov [cyclesRemaining], edi\n"); + fprintf(fp, " mov edi, [_z80MemWrite] ; Point to the write array\n\n", cpubasename); + fprintf(fp, "checkLoop%ld:\n", dwGlobalLabel); + fprintf(fp, " cmp [edi], word 0ffffh ; End of the list?\n"); + fprintf(fp, " je memoryWrite%ld\n", dwGlobalLabel); + fprintf(fp, " cmp %s, [edi] ; Are we smaller?\n", pszAddress); + fprintf(fp, " jb nextAddr%ld ; Yes, go to the next address\n", dwGlobalLabel); + fprintf(fp, " cmp %s, [edi+4] ; Are we bigger?\n", pszAddress); + fprintf(fp, " jbe callRoutine%ld\n\n", dwGlobalLabel); + fprintf(fp, "nextAddr%ld:\n", dwGlobalLabel); + fprintf(fp, " add edi, 10h ; Next structure!\n"); + fprintf(fp, " jmp short checkLoop%ld\n\n", dwGlobalLabel); + fprintf(fp, "callRoutine%ld:\n", dwGlobalLabel); + + fprintf(fp, " push ax ; Save this for later\n"); + + // Write the LSB + + fprintf(fp, " push dx\n"); + + if (strcmp(pszTarget, "ax") != 0) + { + fprintf(fp, " mov ax, %s\n", pszTarget); + } + else + { + fprintf(fp, " xchg ah, al\n"); + } + + fprintf(fp, " call WriteMemoryByte\n"); + fprintf(fp, " pop dx\n"); + fprintf(fp, " pop ax\n"); + fprintf(fp, " inc dx\n\n"); + + fprintf(fp, " push ax\n"); + fprintf(fp, " push dx\n"); + + if (strcmp(pszTarget, "ax") != 0) + { + fprintf(fp, " mov ax, %s\n", pszTarget); + fprintf(fp, " xchg ah, al\n"); + } + + fprintf(fp, " call WriteMemoryByte\n"); + fprintf(fp, " pop dx\n"); + fprintf(fp, " pop ax ; Restore us!\n"); + + fprintf(fp, " jmp writeExit%ld\n\n", dwGlobalLabel); + + fprintf(fp, "memoryWrite%ld:\n", dwGlobalLabel); + + if (strlen(pszTarget) != 2) + { + fprintf(fp, " mov di, %s\n", pszTarget); + fprintf(fp, " mov [ebp + e%s], di ; Store our word\n", pszAddress); + } + else + { + if (strcmp(pszTarget, "ax") != 0) + { + fprintf(fp, " mov [ebp + e%s], %s ; Store our word\n", pszAddress, pszTarget); + } + else + { + fprintf(fp, " xchg ah, al ; Swap for later\n"); + fprintf(fp, " mov [ebp + e%s], %s ; Store our word\n", pszAddress, pszTarget); + fprintf(fp, " xchg ah, al ; Restore\n"); + } + } + + fprintf(fp, "writeExit%ld:\n", dwGlobalLabel); + fprintf(fp, " mov edi, [cyclesRemaining]\n"); + + dwGlobalLabel++; + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */\n"); + fprintf(fp, " while (psMemWrite->lowAddr != 0xffffffff)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " if ((%s >= psMemWrite->lowAddr) && (%s <= psMemWrite->highAddr))\n", pszAddress, pszAddress); + fprintf(fp, " {\n"); + fprintf(fp, " cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base;\n"); + + fprintf(fp, " if (psMemWrite->memoryCall)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " psMemWrite->memoryCall(%s, (%s & 0xff), psMemWrite);\n", pszAddress, pszTarget); + fprintf(fp, " psMemWrite->memoryCall(%s + 1, (%s >> 8), psMemWrite);\n", pszAddress, pszTarget); + fprintf(fp, " }\n"); + fprintf(fp, " else\n"); + fprintf(fp, " {\n"); + fprintf(fp, " *((UINT8 *) psMemWrite->pUserArea + (%s - psMemWrite->lowAddr)) = %s;\n", pszAddress, pszTarget); + fprintf(fp, " *((UINT8 *) psMemWrite->pUserArea + (%s - psMemWrite->lowAddr) + 1) = %s >> 8;\n", pszAddress, pszTarget); + fprintf(fp, " }\n"); + + fprintf(fp, " psMemWrite = NULL;\n"); + fprintf(fp, " break;\n"); + fprintf(fp, " }\n"); + fprintf(fp, " ++psMemWrite;\n"); + fprintf(fp, " }\n\n"); + fprintf(fp, " if (psMemWrite)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " cpu.z80Base[%s] = (UINT8) %s;\n", pszAddress, pszTarget); + fprintf(fp, " cpu.z80Base[%s + 1] = (UINT8) ((UINT32) %s >> 8);\n", pszAddress, pszTarget); + fprintf(fp, " }\n\n"); + } + else + { + assert(0); + } +} + +void WriteValueToIo(UINT8 *pszIoAddress, UINT8 *pszValue) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp, " mov [cyclesRemaining], edi\n"); + fprintf(fp, " mov [_z80af], ax ; Store AF\n"); + + if (strcmp(pszValue, "al") != 0) + fprintf(fp, " mov al, %s ; And our data to write\n", pszValue); + if (strcmp(pszValue, "[esi]") == 0) // Immediate value? + fprintf(fp, " inc esi ; Increment our program counter\n"); + + fprintf(fp, " mov edi, [_z80IoWrite] ; Point to the I/O write array\n\n", cpubasename); + fprintf(fp, "checkLoop%ld:\n", dwGlobalLabel); + fprintf(fp, " cmp [edi], word 0ffffh ; End of our list?\n"); + fprintf(fp, " je WriteMacroExit%ld ; Yes - ignore it!\n", dwGlobalLabel); + fprintf(fp, " cmp %s, [edi] ; Are we smaller?\n", pszIoAddress); + fprintf(fp, " jb nextAddr%ld ; Yes... go to the next addr\n", dwGlobalLabel); + fprintf(fp, " cmp %s, [edi+2] ; Are we bigger?\n", pszIoAddress); + fprintf(fp, " jbe callRoutine%ld ; If not, go call it!\n\n", dwGlobalLabel); + fprintf(fp, "nextAddr%ld:\n", dwGlobalLabel); + fprintf(fp, " add edi, 0ch ; Next structure, please\n"); + fprintf(fp, " jmp short checkLoop%ld\n\n", dwGlobalLabel); + fprintf(fp, "callRoutine%ld:\n", dwGlobalLabel); + + // Save off our registers! + + if (strcmp(pszIoAddress, "dx") != 0) + fprintf(fp, " mov dx, %s ; Get our address to target\n", pszIoAddress); + + fprintf(fp, " call WriteIOByte ; Go write the data!\n"); + + fprintf(fp, "WriteMacroExit%ld:\n", dwGlobalLabel); + fprintf(fp, " mov edi, [cyclesRemaining]\n"); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " psIoWrite = cpu.z80IoWrite; /* Beginning of our handler */\n"); + fprintf(fp, " while (psIoWrite->lowIoAddr != 0xffff)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " if ((%s >= psIoWrite->lowIoAddr) && (%s <= psIoWrite->highIoAddr))\n", pszIoAddress, pszIoAddress); + fprintf(fp, " {\n"); + fprintf(fp, " cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base;\n"); + fprintf(fp, " psIoWrite->IOCall(%s, %s, psIoWrite);\n", pszIoAddress, pszValue); + fprintf(fp, " psIoWrite = NULL;\n"); + fprintf(fp, " break;\n"); + fprintf(fp, " }\n"); + fprintf(fp, " ++psIoWrite;\n"); + fprintf(fp, " }\n\n"); + } + else + { + assert(0); + } + + ++dwGlobalLabel; +} + +void ReadValueFromMemory(UINT8 *pszAddress, UINT8 *pszTarget) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp, " mov [cyclesRemaining], edi\n"); + fprintf(fp, " mov edi, [_z80MemRead] ; Point to the read array\n\n", cpubasename); + fprintf(fp, "checkLoop%ld:\n", dwGlobalLabel); + fprintf(fp, " cmp [edi], word 0ffffh ; End of the list?\n"); + fprintf(fp, " je memoryRead%ld\n", dwGlobalLabel); + fprintf(fp, " cmp e%s, [edi] ; Are we smaller?\n", pszAddress); + fprintf(fp, " jb nextAddr%ld ; Yes, go to the next address\n", dwGlobalLabel); + fprintf(fp, " cmp e%s, [edi+4] ; Are we bigger?\n", pszAddress); + fprintf(fp, " jbe callRoutine%ld\n\n", dwGlobalLabel); + fprintf(fp, "nextAddr%ld:\n", dwGlobalLabel); + fprintf(fp, " add edi, 10h ; Next structure!\n"); + fprintf(fp, " jmp short checkLoop%ld\n\n", dwGlobalLabel); + fprintf(fp, "callRoutine%ld:\n", dwGlobalLabel); + + if (strcmp(pszAddress, "dx") != 0) + fprintf(fp, " mov dx, %s ; Get our address\n", pszAddress); + + fprintf(fp, " call ReadMemoryByte ; Standard read routine\n"); + + // Yes, these are intentionally reversed! + + if (strcmp(pszTarget, "al") == 0) + fprintf(fp, " mov [_z80af], al ; Save our new accumulator\n"); + else + if (strcmp(pszTarget, "ah") == 0) + fprintf(fp, " mov [_z80af + 1], al ; Save our new flags\n"); + else + fprintf(fp, " mov %s, al ; Put our returned value here\n", pszTarget); + + // And are properly restored HERE: + + fprintf(fp, " mov ax, [_z80af] ; Get our AF back\n"); + + // Restore registers here... + + fprintf(fp, " jmp short readExit%ld\n\n", dwGlobalLabel); + fprintf(fp, "memoryRead%ld:\n", dwGlobalLabel); + + if (pszTarget[0] == 'b' && pszTarget[1] == 'y' && pszTarget[2] == 't') + { + fprintf(fp, " mov di, dx\n"); + fprintf(fp, " mov dl, [ebp + e%s]\n", pszAddress); + fprintf(fp, " mov %s, dl\n", pszTarget); + fprintf(fp, " mov dx, di\n"); + } + else + fprintf(fp, " mov %s, [ebp + e%s] ; Get our data\n\n", pszTarget, pszAddress); + + fprintf(fp, "readExit%ld:\n", dwGlobalLabel); + fprintf(fp, " mov edi, [cyclesRemaining]\n"); + + dwGlobalLabel++; + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " psMemRead = cpu.z80MemRead; /* Beginning of our handler */\n"); + fprintf(fp, " while (psMemRead->lowAddr != 0xffffffff)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " if ((%s >= psMemRead->lowAddr) && (%s <= psMemRead->highAddr))\n", pszAddress, pszAddress); + fprintf(fp, " {\n"); + fprintf(fp, " cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base;\n"); + fprintf(fp, " if (psMemRead->memoryCall)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " %s = psMemRead->memoryCall(%s, psMemRead);\n", pszTarget, pszAddress); + fprintf(fp, " }\n"); + fprintf(fp, " else\n"); + fprintf(fp, " {\n"); + fprintf(fp, " %s = *((UINT8 *) psMemRead->pUserArea + (%s - psMemRead->lowAddr));\n", pszTarget, pszAddress); + fprintf(fp, " }\n"); + fprintf(fp, " psMemRead = NULL;\n"); + fprintf(fp, " break;\n"); + fprintf(fp, " }\n"); + fprintf(fp, " ++psMemRead;\n"); + fprintf(fp, " }\n\n"); + fprintf(fp, " if (psMemRead)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " %s = cpu.z80Base[%s];\n", pszTarget, pszAddress); + fprintf(fp, " }\n\n"); + } + else + { + assert(0); + } +} + + +void ReadWordFromMemory(UINT8 *pszAddress, UINT8 *pszTarget) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp, " mov [cyclesRemaining], edi\n"); + fprintf(fp, " mov edi, [_z80MemRead] ; Point to the read array\n\n", cpubasename); + fprintf(fp, "checkLoop%ld:\n", dwGlobalLabel); + fprintf(fp, " cmp [edi], word 0ffffh ; End of the list?\n"); + fprintf(fp, " je memoryRead%ld\n", dwGlobalLabel); + fprintf(fp, " cmp %s, [edi] ; Are we smaller?\n", pszAddress); + fprintf(fp, " jb nextAddr%ld ; Yes, go to the next address\n", dwGlobalLabel); + fprintf(fp, " cmp %s, [edi+4] ; Are we bigger?\n", pszAddress); + fprintf(fp, " jbe callRoutine%ld\n\n", dwGlobalLabel); + fprintf(fp, "nextAddr%ld:\n", dwGlobalLabel); + fprintf(fp, " add edi, 10h ; Next structure!\n"); + fprintf(fp, " jmp short checkLoop%ld\n\n", dwGlobalLabel); + fprintf(fp, "callRoutine%ld:\n", dwGlobalLabel); + + if (strcmp(pszAddress, "dx") != 0) + fprintf(fp, " mov dx, %s ; Get our address\n", pszAddress); + + if (strcmp(pszTarget, "ax") != 0) + fprintf(fp, " push ax ; Save this for later\n"); + + fprintf(fp, " push dx ; Save address\n"); + fprintf(fp, " call ReadMemoryByte ; Standard read routine\n"); + fprintf(fp, " pop dx ; Restore our address\n"); + + fprintf(fp, " inc dx ; Next byte, please\n"); + + fprintf(fp, " push ax ; Save returned byte\n"); + fprintf(fp, " call ReadMemoryByte ; Standard read routine\n"); + fprintf(fp, " xchg ah, al ; Swap for endian's sake\n"); + fprintf(fp, " pop dx ; Restore LSB\n"); + + fprintf(fp, " mov dh, ah ; Our word is now in DX\n"); + + // DX Now has our data and our address is toast + + if (strcmp(pszTarget, "ax") != 0) + { + fprintf(fp, " pop ax ; Restore this\n"); + + if (strcmp(pszTarget, "dx") != 0) + { + fprintf(fp, " mov %s, dx ; Store our word\n", pszTarget); + } + } + else + fprintf(fp, " mov ax, dx\n"); + + if (strcmp(pszTarget, "ax") == 0) + { + fprintf(fp, " xchg ah, al\n"); + } + + fprintf(fp, " jmp readExit%ld\n\n", dwGlobalLabel); + + fprintf(fp, "memoryRead%ld:\n", dwGlobalLabel); + + if (strlen(pszTarget) == 2) + { + fprintf(fp, " mov %s, [ebp + e%s]\n", pszTarget, pszAddress); + if (strcmp(pszTarget, "ax") == 0) + { + fprintf(fp, " xchg ah, al\n"); + } + } + else + { + fprintf(fp, " mov dx, [ebp + e%s]\n", pszAddress); + fprintf(fp, " mov %s, dx\n", pszTarget); + } + + fprintf(fp, "readExit%ld:\n", dwGlobalLabel); + fprintf(fp, " mov edi, [cyclesRemaining]\n"); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " psMemRead = cpu.z80MemRead; /* Beginning of our handler */\n"); + fprintf(fp, " while (psMemRead->lowAddr != 0xffffffff)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " if ((%s >= psMemRead->lowAddr) && (%s <= psMemRead->highAddr))\n", pszAddress, pszAddress); + fprintf(fp, " {\n"); + fprintf(fp, " cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base;\n"); + fprintf(fp, " if (psMemRead->memoryCall)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " %s = psMemRead->memoryCall(%s, psMemRead);\n", pszTarget, pszAddress); + fprintf(fp, " %s |= (UINT32) ((UINT32) psMemRead->memoryCall(%s + 1, psMemRead) << 8);\n", pszTarget, pszAddress); + fprintf(fp, " }\n"); + fprintf(fp, " else\n"); + fprintf(fp, " {\n"); + fprintf(fp, " %s = *((UINT8 *) psMemRead->pUserArea + (%s - psMemRead->lowAddr));\n", pszTarget, pszAddress); + fprintf(fp, " %s |= (UINT32) ((UINT32) *((UINT8 *) psMemRead->pUserArea + (%s - psMemRead->lowAddr + 1)) << 8);\n", pszTarget, pszAddress); + fprintf(fp, " }\n"); + fprintf(fp, " psMemRead = NULL;\n"); + fprintf(fp, " break;\n"); + fprintf(fp, " }\n"); + fprintf(fp, " ++psMemRead;\n"); + fprintf(fp, " }\n\n"); + fprintf(fp, " if (psMemRead)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " %s = cpu.z80Base[%s];\n", pszTarget, pszAddress); + fprintf(fp, " %s |= (UINT32) ((UINT32) cpu.z80Base[%s + 1] << 8);\n", pszTarget, pszAddress); + fprintf(fp, " }\n\n"); + } + else + { + assert(0); + } + + dwGlobalLabel++; +} + + +void ReadValueFromIo(UINT8 *pszIoAddress, UINT8 *pszTarget) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp, " mov [cyclesRemaining], edi\n"); + fprintf(fp, " mov edi, [_z80IoRead] ; Point to the read array\n\n", cpubasename); + fprintf(fp, "checkLoop%ld:\n", dwGlobalLabel); + fprintf(fp, " cmp [edi], word 0ffffh ; End of the list?\n"); + fprintf(fp, " je ioRead%ld\n", dwGlobalLabel); + fprintf(fp, " cmp %s, [edi] ; Are we smaller?\n", pszIoAddress); + fprintf(fp, " jb nextAddr%ld ; Yes, go to the next address\n", dwGlobalLabel); + fprintf(fp, " cmp %s, [edi+2] ; Are we bigger?\n", pszIoAddress); + fprintf(fp, " jbe callRoutine%ld\n\n", dwGlobalLabel); + fprintf(fp, "nextAddr%ld:\n", dwGlobalLabel); + fprintf(fp, " add edi, 0ch ; Next structure!\n"); + fprintf(fp, " jmp short checkLoop%ld\n\n", dwGlobalLabel); + fprintf(fp, "callRoutine%ld:\n", dwGlobalLabel); + + if (strcmp(pszIoAddress, "dx") != 0) + fprintf(fp, " mov dx, %s ; Get our address\n", pszIoAddress); + + fprintf(fp, " call ReadIOByte ; Standard read routine\n"); + + // Yes, these are intentionally reversed! + + if (strcmp(pszTarget, "al") == 0) + fprintf(fp, " mov [_z80af], al ; Save our new accumulator\n"); + else + if (strcmp(pszTarget, "ah") == 0) + fprintf(fp, " mov [_z80af + 1], ah ; Save our new flags\n"); + else + if (strcmp(pszTarget, "dl") == 0) + fprintf(fp, " mov [_z80de], al ; Put it in E\n"); + else + if (strcmp(pszTarget, "dh") == 0) + fprintf(fp, " mov [_z80de + 1], al ; Put it in D\n"); + else + if (strcmp(pszTarget, "*dl") == 0) + fprintf(fp, " mov dl, al ; Put it in DL for later consumption\n"); + else + fprintf(fp, " mov %s, al ; Put our returned value here\n", pszTarget); + + // And are properly restored HERE: + + fprintf(fp, " mov ax, [_z80af] ; Get our AF back\n"); + + // Restore registers here... + + fprintf(fp, " jmp short readExit%ld\n\n", dwGlobalLabel); + fprintf(fp, "ioRead%ld:\n", dwGlobalLabel); + + if (strcmp(pszTarget, "*dl") == 0) + fprintf(fp, " mov dl, 0ffh ; An unreferenced read\n"); + else + fprintf(fp, " mov %s, 0ffh ; An unreferenced read\n", pszTarget); + fprintf(fp, "readExit%ld:\n", dwGlobalLabel); + fprintf(fp, " mov edi, [cyclesRemaining]\n"); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " psIoRead = cpu.z80IoRead; /* Beginning of our handler */\n"); + fprintf(fp, " while (psIoRead->lowIoAddr != 0xffff)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " if ((%s >= psIoRead->lowIoAddr) && (%s <= psIoRead->highIoAddr))\n", pszIoAddress, pszIoAddress); + fprintf(fp, " {\n"); + fprintf(fp, " cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base;\n"); + fprintf(fp, " %s = psIoRead->IOCall(%s, psIoRead);\n", pszTarget, pszIoAddress); + fprintf(fp, " psIoRead = NULL;\n"); + fprintf(fp, " break;\n"); + fprintf(fp, " }\n"); + fprintf(fp, " ++psIoRead;\n"); + fprintf(fp, " }\n\n"); + fprintf(fp, " if (psIoRead)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " %s = 0xff; /* Unclaimed I/O read */\n", pszTarget); + fprintf(fp, " }\n\n"); + } + else + { + assert(0); + } + + dwGlobalLabel++; +} + +// Basic instruction set area + +void MiscHandler(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if (dwOpcode == 0xe3) + { + if (bThroughCallHandler) + { + fprintf(fp, " call PopWord\n"); + fprintf(fp, " xchg bx, [_wordval]\n"); + fprintf(fp, " call PushWord\n"); + } + else + { + fprintf(fp, " mov dx, word [_z80sp]\n"); + fprintf(fp, " xchg bx, [ebp+edx]\n"); + fprintf(fp, " xor edx, edx\n"); + } + } + + if (dwOpcode == 0x2a) + { + fprintf(fp, " mov dx, [esi] ; Get address to load\n"); + fprintf(fp, " add esi, 2 ; Skip over it so we don't execute it\n"); + + ReadWordFromMemory("dx", "bx"); + fprintf(fp, " xor edx, edx\n"); + } + + if (dwOpcode == 0xfb) + { + fprintf(fp, " or dword [_z80iff], IFF1 ; Indicate interrupts are enabled now\n"); + fprintf(fp, " sub edi, 4 ; Takes 4 cycles!\n"); + fprintf(fp, " mov [dwEITiming], edi ; Snapshot our current timing\n"); + fprintf(fp, " mov [bEIExit], byte 1 ; Indicate we're exiting because of an EI\n"); + fprintf(fp, " xor edi, edi ; Force next instruction to exit\n"); + fprintf(fp, " mov dl, byte [esi] ; Get our next instruction\n"); + fprintf(fp, " inc esi ; Next PC\n"); + fprintf(fp, " jmp dword [z80regular+edx*4]\n\n"); + } + + if (dwOpcode == 0xf9) + fprintf(fp, " mov word [_z80sp], bx\n"); + + if (dwOpcode == 0xd9) + { + fprintf(fp, " mov [cyclesRemaining], edi\n"); + fprintf(fp, " mov di, [_z80de]\n"); + fprintf(fp, " xchg cx, [_z80bcprime]\n"); + fprintf(fp, " xchg di, [_z80deprime]\n"); + fprintf(fp, " xchg bx, [_z80hlprime]\n"); + fprintf(fp, " mov [_z80de], di\n"); + fprintf(fp, " mov edi, [cyclesRemaining]\n"); + } + + if (dwOpcode == 0x76) + { + fprintf(fp, " mov dword [_z80halted], 1 ; We've halted the chip!\n"); + + if (FALSE == bNoTiming) + { + fprintf(fp, " xor edi, edi\n"); + fprintf(fp, " mov [cyclesRemaining], edi\n"); + } + + fprintf(fp, " jmp noMoreExec\n"); + return; + } + + if (dwOpcode == 0x3f) + { + fprintf(fp, " mov dl, ah\n"); + fprintf(fp, " and dl, 01h\n"); + fprintf(fp, " shl dl, 4\n"); + fprintf(fp, " xor ah, 01h\n"); + fprintf(fp, " and ah, 0edh\n"); + fprintf(fp, " or ah, dl\n"); + } + + if (dwOpcode == 0x37) + { + fprintf(fp, " or ah, 1\n"); + fprintf(fp, " and ah,0edh\n"); + } + + if (dwOpcode == 0x27) + { + fprintf(fp, " mov dh, ah\n"); + fprintf(fp, " and dh, 02ah\n"); + fprintf(fp, " test ah, 02h ; Were we doing a subtraction?\n"); + fprintf(fp, " jnz handleNeg ; Nope!\n"); + fprintf(fp, " sahf\n"); + fprintf(fp, " daa\n"); + fprintf(fp, " lahf\n"); + fprintf(fp, " jmp short endDaa\n"); + fprintf(fp, "handleNeg:\n"); + fprintf(fp, " sahf\n"); + fprintf(fp, " das\n"); + fprintf(fp, " lahf\n"); + fprintf(fp, "endDaa:\n"); + fprintf(fp, " and ah, 0d5h\n"); + fprintf(fp, " or ah, dh\n"); + fprintf(fp, " xor edx, edx\n"); + } + + if (dwOpcode == 0x08) + { + fprintf(fp, " xchg ah, al\n"); + fprintf(fp, " xchg ax, [_z80afprime]\n"); + fprintf(fp, " xchg ah, al\n"); + } + + if (dwOpcode == 0x07) + { + fprintf(fp, " sahf\n"); + fprintf(fp, " rol al, 1\n"); + fprintf(fp, " lahf\n"); + fprintf(fp, " and ah, 0edh\n"); + } + + if (dwOpcode == 0x0f) + { + fprintf(fp, " sahf\n"); + fprintf(fp, " ror al, 1\n"); + fprintf(fp, " lahf\n"); + fprintf(fp, " and ah, 0edh\n"); + } + + if (dwOpcode == 0xe9) + { + fprintf(fp, " mov si, bx\n"); + fprintf(fp, " and esi, 0ffffh\n"); + fprintf(fp, " add esi, ebp\n"); + } + + if (dwOpcode == 0xeb) + fprintf(fp, " xchg [_z80de], bx ; Exchange DE & HL\n"); + + if (dwOpcode == 0x2f) + { + fprintf(fp, " not al\n"); + fprintf(fp, " or ah, 012h ; N And H are now on!\n"); + } + + if (dwOpcode == 0x10) // DJNZ + { + fprintf(fp, " mov dl, [esi] ; Get our relative offset\n"); + fprintf(fp, " inc esi ; Next instruction, please!\n"); + fprintf(fp, " dec ch ; Decrement B\n"); + fprintf(fp, " jz noJump ; Don't take the jump if it's done!\n"); + fprintf(fp, "; Otherwise, take the jump\n"); + + fprintf(fp, " sub edi, 5\n"); + + fprintf(fp, " xchg eax, edx\n"); + fprintf(fp, " cbw\n"); + fprintf(fp, " xchg eax, edx\n"); + fprintf(fp, " sub esi, ebp\n"); + fprintf(fp, " add si, dx\n"); + fprintf(fp, " add esi, ebp\n"); + fprintf(fp, "noJump:\n"); + fprintf(fp, " xor edx, edx\n"); + } + + if (dwOpcode == 0x3a) // LD A,(xxxx) + { + fprintf(fp, " mov dx, [esi] ; Get our address\n"); + fprintf(fp, " add esi, 2 ; Skip past the address\n"); + ReadValueFromMemory("dx", "al"); + fprintf(fp, " xor edx, edx ; Make sure we don't hose things\n"); + } + + if (dwOpcode == 0xf3) // DI + { + fprintf(fp, " and dword [_z80iff], (~IFF1) ; Not in an interrupt\n"); + } + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (dwOpcode == 0x76) // HALT! + { + fprintf(fp, " cpu.z80halted = 1;\n"); + fprintf(fp, " dwElapsedTicks += sdwCyclesRemaining;\n"); + + fprintf(fp, " sdwCyclesRemaining = 0;\n"); + } + else + if (dwOpcode == 0x2f) // CPL + { + fprintf(fp, " cpu.z80A ^= 0xff;\n"); + fprintf(fp, " cpu.z80F |= (Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY);\n"); + } + else + if (dwOpcode == 0xd9) // EXX + { + fprintf(fp, " dwTemp = cpu.z80DE;\n"); + fprintf(fp, " cpu.z80DE = cpu.z80deprime;\n"); + fprintf(fp, " cpu.z80deprime = dwTemp;\n"); + + fprintf(fp, " dwTemp = cpu.z80BC;\n"); + fprintf(fp, " cpu.z80BC = cpu.z80bcprime;\n"); + fprintf(fp, " cpu.z80bcprime = dwTemp;\n"); + + fprintf(fp, " dwTemp = cpu.z80HL;\n"); + fprintf(fp, " cpu.z80HL = cpu.z80hlprime;\n"); + fprintf(fp, " cpu.z80hlprime = dwTemp;\n"); + } + else + if (dwOpcode == 0xf9) // LD SP, HL + { + fprintf(fp, " cpu.z80sp = cpu.z80HL;\n"); + } + else + if (dwOpcode == 0x27) // DAA + { + fprintf(fp, " dwAddr = (((cpu.z80F & Z80_FLAG_CARRY) | \n"); + fprintf(fp, " ((cpu.z80F & Z80_FLAG_HALF_CARRY) >> 3) | \n"); + fprintf(fp, " ((cpu.z80F & Z80_FLAG_NEGATIVE) << 1)) << 8) | cpu.z80A;\n"); + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN);\n"); + fprintf(fp, " cpu.z80F |= (wDAATable[dwAddr] >> 8);\n"); + fprintf(fp, " cpu.z80A = wDAATable[dwAddr] & 0xff;\n"); + } + else + if (dwOpcode == 0x2a) + { + fprintf(fp, " dwAddr = *pbPC++;\n"); + fprintf(fp, " dwAddr |= ((UINT32) *pbPC++ << 8);\n"); + ReadWordFromMemory("dwAddr", "cpu.z80HL"); + } + else + if (dwOpcode == 0xe3) // EX (SP), HL + { + ReadWordFromMemory("cpu.z80sp", "dwAddr"); + WriteWordToMemory("cpu.z80sp", "cpu.z80HL"); + fprintf(fp, " cpu.z80HL = dwAddr;\n"); + } + else + if (dwOpcode == 0xe9) // JP (HL) + { + fprintf(fp, " pbPC = cpu.z80Base + cpu.z80HL;\n"); + } + else + if (0x08 == dwOpcode) // EX AF, AF' + { + fprintf(fp, " dwAddr = (UINT32) cpu.z80AF;\n"); + fprintf(fp, " cpu.z80AF = cpu.z80afprime;\n"); + fprintf(fp, " cpu.z80afprime = dwAddr;\n"); + } + else + if (0xeb == dwOpcode) // EX DE, HL + { + fprintf(fp, " dwAddr = cpu.z80DE;\n"); + fprintf(fp, " cpu.z80DE = cpu.z80HL;\n"); + fprintf(fp, " cpu.z80HL = dwAddr;\n"); + } + else + if (0x10 == dwOpcode) // DJNZ + { + fprintf(fp, " sdwAddr = (INT8) *pbPC++; /* Get LSB first */\n"); + fprintf(fp, " if (--cpu.z80B)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " dwElapsedTicks += 5; /* 5 More for jump taken */\n"); + fprintf(fp, " cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base;\n"); + fprintf(fp, " sdwAddr = (sdwAddr + (INT32) cpu.z80pc) & 0xffff;\n"); + fprintf(fp, " pbPC = cpu.z80Base + sdwAddr; /* Normalize the address */\n"); + fprintf(fp, " }\n"); + } + else + if (0x37 == dwOpcode) // SCF + { + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE);\n"); + fprintf(fp, " cpu.z80F |= Z80_FLAG_CARRY;\n"); + } + else + if (0x3f == dwOpcode) // CCF + { + fprintf(fp, " bTemp = (cpu.z80F & Z80_FLAG_CARRY) << 4;\n"); + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE);\n"); + fprintf(fp, " cpu.z80F ^= Z80_FLAG_CARRY;\n"); + } + else + if (0x07 == dwOpcode) // RLCA + { + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY);\n"); + fprintf(fp, " cpu.z80F |= (cpu.z80A >> 7);\n"); + fprintf(fp, " cpu.z80A = (cpu.z80A << 1) | (cpu.z80A >> 7);\n"); + } + else + if (0x0f == dwOpcode) // RRCA + { + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY);\n"); + fprintf(fp, " cpu.z80F |= (cpu.z80A & Z80_FLAG_CARRY);\n"); + fprintf(fp, " cpu.z80A = (cpu.z80A >> 1) | (cpu.z80A << 7);\n"); + } + else + if (0x3a == dwOpcode) // LD A, (xxxxh) + { + fprintf(fp, " dwTemp = *pbPC++;\n"); + fprintf(fp, " dwTemp |= (((UINT32) *pbPC++) << 8);\n"); + ReadValueFromMemory("dwTemp", "cpu.z80A"); + } + else + if (0xf3 == dwOpcode) // DI + { + fprintf(fp, " cpu.z80iff &= (~IFF1);\n"); + } + else + if (0xfb == dwOpcode) // EI + { + fprintf(fp, " cpu.z80iff |= IFF1;\n"); + } + else + if (0x00 == dwOpcode) // NOP + { + fprintf(fp, " /* Intentionally not doing anything - NOP! */\n"); + } + else + { + InvalidInstructionC(1); + } + } + else + { + assert(0); + } + +} + +void LdRegPairImmediate(UINT32 dwOpcode) +{ + UINT8 bOp = 0; + + bOp = (dwOpcode >> 4) & 0x3; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if (bOp == 0) + fprintf(fp, " mov cx, [esi] ; Get our immediate value of BC\n"); + else + if (bOp == 2) + fprintf(fp, " mov bx, [esi] ; Get our immediate value of HL\n"); + else + if (bOp == 1) + { + fprintf(fp, " mov dx, [esi] ; Get our immediate value of DE\n"); + fprintf(fp, " mov word [_z80de], dx ; Store DE\n"); + fprintf(fp, " xor edx, edx\n"); + } + else + if (bOp == 3) + { + fprintf(fp, " mov dx, [esi] ; Get our immediate value of SP\n"); + fprintf(fp, " mov word [_z80sp], dx ; Store it!\n"); + fprintf(fp, " xor edx, edx\n"); + } + + fprintf(fp, " add esi, 2\n"); + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " %s = *pbPC++; /* LSB First */\n", pbRegPairC[bOp]); + fprintf(fp, " %s |= (((UINT32) *pbPC++ << 8)); /* Now the MSB */\n", pbRegPairC[bOp]); + } + else + { + assert(0); + } +} + +void LdRegpairPtrByte(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if (dwOpcode == 0x36) // Immediate into (HL) + WriteValueToMemory("bx", "[esi]"); + + if (dwOpcode == 0x12) + WriteValueToMemory("[_z80de]", "al"); // (DE), A + + if (dwOpcode == 0x2) // (BC), A + WriteValueToMemory("cx", "al"); + + if (dwOpcode >= 0x70 && dwOpcode < 0x78) + WriteValueToMemory("bx", pbMathReg[dwOpcode & 0x07]); + + fprintf(fp, " xor edx, edx\n"); + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (dwOpcode == 0x36) + WriteValueToMemory("cpu.z80HL", "*pbPC++"); + + if (dwOpcode == 0x12) + WriteValueToMemory("cpu.z80DE", "cpu.z80A"); + + if (dwOpcode == 0x02) + WriteValueToMemory("cpu.z80BC", "cpu.z80A"); + + if (dwOpcode >= 0x70 && dwOpcode < 0x78) + WriteValueToMemory("cpu.z80HL", pbMathRegC[dwOpcode & 0x07]); + } + else + { + assert(0); + } +} + +void MathOperation(UINT32 dwOrgOpcode) +{ + UINT8 bRegister; + UINT32 dwOpcode; + UINT8 tempstr[150]; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOrgOpcode); + + dwOpcode = dwOrgOpcode; + bRegister = dwOpcode & 0x07; + dwOpcode &= 0xf8; + + if (dwOpcode == 0x80) + strcpy(tempstr, "add"); + if (dwOpcode == 0x88) + strcpy(tempstr, "adc"); + if (dwOpcode == 0x90) + strcpy(tempstr, "sub"); + if (dwOpcode == 0x98) + strcpy(tempstr, "sbb"); + if (dwOpcode == 0xa0) + strcpy(tempstr, "and"); + if (dwOpcode == 0xa8) + strcpy(tempstr, "xor"); + if (dwOpcode == 0xb0) + strcpy(tempstr, "or"); + if (dwOpcode == 0xb8) + strcpy(tempstr, "cmp"); + + // Let's see if we have to deal with (HL) or #xxh + + if (bRegister == 0x6) + { + // We have to deal with (HL) + + ReadValueFromMemory("bx", "dl"); + } + + if (bRegister != 0x06 && bRegister < 0xff) + { + fprintf(fp, " sahf\n"); + fprintf(fp, " %s al, %s\n", tempstr, pbMathReg[bRegister]); + fprintf(fp, " lahf\n"); + } + else // If it's (HL).... + { + fprintf(fp, " sahf\n"); + fprintf(fp, " %s al, dl\n", tempstr); + fprintf(fp, " lahf\n"); + } + + if (dwOpcode != 0xa8 && dwOpcode != 0xa0 && dwOpcode != 0xb0) + SetOverflow(); + + if (dwOpcode == 0xa8) + fprintf(fp, " and ah, 0ech ; Only these flags matter!\n"); + + if (dwOpcode == 0xa0) + { + fprintf(fp, " and ah, 0ech ; Only these flags matter!\n"); + fprintf(fp, " or ah, 010h ; Half carry gets set\n"); + } + + if (dwOpcode == 0xb0) + fprintf(fp, " and ah, 0ech ; No H, N, or C\n"); + + if (dwOpcode == 0xb8) + fprintf(fp, " or ah, 02h ; Set N for compare!\n"); + + if (dwOpcode == 0x80 || dwOpcode == 0x88) + fprintf(fp, " and ah, 0fdh ; No N!\n"); + + if (dwOpcode == 0x90 || dwOpcode == 0x98) + fprintf(fp, " or ah, 02h ; N Gets set!\n"); + + if (bRegister == 0x6) + fprintf(fp, " xor edx, edx ; Zero this...\n"); + + FetchNextInstruction(dwOrgOpcode); + } + else + if (MZ80_C == bWhat) + { + dwOpcode = dwOrgOpcode; + bRegister = dwOpcode & 0x07; + dwOpcode &= 0xf8; + + if (6 == bRegister) // Deal with (HL) + { + ReadValueFromMemory("cpu.z80HL", "bTemp"); + } + + if (dwOpcode == 0xa0) + { + fprintf(fp, " cpu.z80A &= %s;\n", pbMathRegC[bRegister]); + } + else + if (dwOpcode == 0xa8) + { + fprintf(fp, " cpu.z80A ^= %s;\n", pbMathRegC[bRegister]); + } + else + if (dwOpcode == 0xb0) + { + fprintf(fp, " cpu.z80A |= %s;\n", pbMathRegC[bRegister]); + } + else + if (dwOpcode == 0xb8) + { + // Don't do anything. We just do flags! + } + else + if (dwOpcode == 0x88) // ADC + { + fprintf(fp, " bTemp2 = cpu.z80A + %s + (cpu.z80F & Z80_FLAG_CARRY);\n", pbMathRegC[bRegister]); + } + else + if (dwOpcode == 0x90) // SUB + { + fprintf(fp, " bTemp2 = cpu.z80A - %s;\n", pbMathRegC[bRegister]); + } + else + if (dwOpcode == 0x80) // ADD + { + fprintf(fp, " bTemp2 = cpu.z80A + %s;\n", pbMathRegC[bRegister]); + } + else + if (dwOpcode == 0x98) // SBC + { + fprintf(fp, " bTemp2 = cpu.z80A - %s - (cpu.z80F & Z80_FLAG_CARRY);\n", pbMathRegC[bRegister]); + } + else + { + InvalidInstructionC(1); + } + + // Now do flag fixup + + if (0xb0 == dwOpcode || 0xa8 == dwOpcode) + { + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN);\n"); + fprintf(fp, " cpu.z80F |= bPostORFlags[cpu.z80A];\n\n"); + } + + if (0xa0 == dwOpcode) + { + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN);\n"); + fprintf(fp, " cpu.z80F |= bPostANDFlags[cpu.z80A];\n\n"); + } + + if (0xb8 == dwOpcode || 0x90 == dwOpcode) + { + SetSubFlagsSZHVC("cpu.z80A", pbMathRegC[bRegister]); + + if (0x90 == dwOpcode) + { + fprintf(fp, " cpu.z80A = bTemp2;\n"); + } + } + + if (0x80 == dwOpcode) // Add fixup + { + SetAddFlagsSZHVC("cpu.z80A", pbMathRegC[bRegister]); + fprintf(fp, " cpu.z80A = bTemp2;\n"); + } + + if (0x88 == dwOpcode) // Adc fixup + { + SetAdcFlagsSZHVC("cpu.z80A", pbMathRegC[bRegister]); + fprintf(fp, " cpu.z80A = bTemp2;\n"); + } + + if (0x98 == dwOpcode) // Sbc fixup + { + SetSbcFlagsSZHVC("cpu.z80A", pbMathRegC[bRegister]); + fprintf(fp, " cpu.z80A = bTemp2;\n"); + } + } + else + { + assert(0); + } +} + +void RegIntoMemory(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + fprintf(fp, " mov dx, [esi] ; Get our address to write to\n"); + fprintf(fp, " add esi, 2 ; Next address, please...\n"); + + if (0x32 == dwOpcode) // LD (xxxx), A + WriteValueToMemory("dx", "al"); + if (0x22 == dwOpcode) // LD (xxxx), HL + { + WriteWordToMemory("dx", "bx"); + } + + fprintf(fp, " xor edx, edx ; Zero our upper byte\n"); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " dwTemp = *pbPC++;\n"); + fprintf(fp, " dwTemp |= ((UINT32) *pbPC++ << 8);\n"); + + if (0x32 == dwOpcode) + WriteValueToMemory("dwTemp", "cpu.z80A"); + if (0x22 == dwOpcode) + WriteWordToMemory("dwTemp", "cpu.z80HL"); + + return; + } + else + { + assert(0); + } +} + +void JpHandler(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if (0xc3 == dwOpcode) // If it's a straight jump... + { + fprintf(fp, " mov si, [esi] ; Get our new address\n"); + fprintf(fp, " and esi, 0ffffh ; Only the lower 16 bits\n"); + fprintf(fp, " add esi, ebp ; Our new address!\n"); + } + else // It's a conditional handler... + { + fprintf(fp, " sahf ; Restore our flags\n"); + fprintf(fp, " j%s takeJump%ld ; We're going to take a jump\n", pbFlags[(dwOpcode >> 3) & 0x07], dwGlobalLabel); + fprintf(fp, " add esi, 2 ; Skip past the address\n"); + fprintf(fp, " jmp short nextInst%ld ; Go execute the next instruction\n", dwGlobalLabel); + fprintf(fp, "takeJump%ld:\n", dwGlobalLabel); + + fprintf(fp, " mov si, [esi] ; Get our new offset\n"); + fprintf(fp, " and esi, 0ffffh ; Only the lower WORD is valid\n"); + fprintf(fp, " add esi, ebp ; Our new address!\n"); + fprintf(fp, "nextInst%ld:\n", dwGlobalLabel); + ++dwGlobalLabel; + } + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " dwAddr = *pbPC++; /* Get LSB first */\n"); + fprintf(fp, " dwAddr |= ((UINT32) *pbPC++ << 8); /* Get MSB last */\n"); + + if (0xc3 != dwOpcode) + { + fprintf(fp, " if %s\n", pbFlagsC[(dwOpcode >> 3) & 0x07]); + fprintf(fp, " {\n"); + fprintf(fp, " pbPC = cpu.z80Base + dwAddr; /* Normalize the address */\n"); + fprintf(fp, " }\n"); + } + else // Regular jump here + { + fprintf(fp, " pbPC = cpu.z80Base + dwAddr; /* Normalize the address */\n"); + } + } + else + { + assert(0); + } +} + +void LdRegImmediate(UINT32 dwOpcode) +{ + UINT8 bOp; + + bOp = (dwOpcode >> 3) & 0x7; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + + if (bOp != 2 && bOp != 3) + fprintf(fp, " mov %s, [esi] ; Get our immediate value\n", pbMathReg[bOp]); + else + { + fprintf(fp, " mov dl, [esi] ; Get our immediate value\n"); + fprintf(fp, " mov %s, dl ; Store our new value\n", pbMathReg[bOp]); + } + + fprintf(fp, " inc esi\n"); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " %s = *pbPC++; /* Get immediate byte into register */\n", pbMathRegC[bOp]); + } + else + { + assert(0); + } +} + +void IncRegister(UINT32 dwOpcode) +{ + UINT32 dwOpcode1 = 0; + + dwOpcode1 = (dwOpcode >> 3) & 0x07; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + fprintf(fp, " sahf\n"); + fprintf(fp, " inc %s\n", pbMathReg[dwOpcode1]); + fprintf(fp, " lahf\n"); + SetOverflow(); + fprintf(fp, " and ah, 0fdh ; Knock out N!\n"); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE);\n"); + fprintf(fp ," cpu.z80F |= bPostIncFlags[%s++];\n", pbMathRegC[dwOpcode1]); + } + else + { + assert(0); + } +} + +void DecRegister(UINT32 dwOpcode) +{ + UINT32 dwOpcode1 = 0; + + dwOpcode1 = (dwOpcode >> 3) & 0x07; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + fprintf(fp, " sahf\n"); + fprintf(fp, " dec %s\n", pbMathReg[dwOpcode1]); + fprintf(fp, " lahf\n"); + SetOverflow(); + fprintf(fp, " or ah, 02h ; Set negative!\n"); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY);\n"); + fprintf(fp ," cpu.z80F |= bPostDecFlags[%s--];\n", pbMathRegC[dwOpcode1]); + } + else + { + assert(0); + } +} + +void IncDecRegpair(UINT32 dwOpcode) +{ + UINT32 dwOpcode1 = 0; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if ((dwOpcode & 0x0f) == 3) // Increment? + fprintf(fp, " inc %s\n", pbRegPairs[(dwOpcode >> 4) & 0x03]); + else + fprintf(fp, " dec %s\n", pbRegPairs[(dwOpcode >> 4) & 0x03]); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if ((dwOpcode & 0x0f) == 3) // Increment + fprintf(fp, " %s++;\n", pbRegPairC[(dwOpcode >> 4) & 0x03]); + else + fprintf(fp, " %s--;\n", pbRegPairC[(dwOpcode >> 4) & 0x03]); + fprintf(fp, " %s &= 0xffff;\n", pbRegPairC[(dwOpcode >> 4) & 0x03]); + } + else + { + assert(0); + } +} + +void LdRegReg(UINT32 dwOpcode) +{ + UINT8 bDestination; + UINT8 bSource; + + bDestination = (dwOpcode >> 3) & 0x07; + bSource = (dwOpcode) & 0x07; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + + ProcBegin(dwOpcode); + + if (bSource != bDestination) + { + if (bSource == 2 && bDestination == 3) + { + fprintf(fp, " mov dl, byte [_z80de + 1]\n"); + fprintf(fp, " mov [_z80de], dl\n"); + } + else + if (bSource == 3 && bDestination == 2) + { + fprintf(fp, " mov dl, byte [_z80de]\n"); + fprintf(fp, " mov [_z80de + 1], dl\n"); + } + else + fprintf(fp, " mov %s, %s\n", pbMathReg[bDestination], pbMathReg[bSource]); + } + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (bDestination != bSource) + { + fprintf(fp, " %s = %s;\n", + pbMathRegC[bDestination], + pbMathRegC[bSource]); + } + } + else + { + assert(0); + } +} + +void MathOperationDirect(UINT32 dwOpcode) +{ + UINT8 tempstr[4]; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + if (dwOpcode == 0xc6) + strcpy(tempstr, "add"); + if (dwOpcode == 0xce) + strcpy(tempstr, "adc"); + if (dwOpcode == 0xd6) + strcpy(tempstr, "sub"); + if (dwOpcode == 0xde) + strcpy(tempstr, "sbb"); + if (dwOpcode == 0xe6) + strcpy(tempstr, "and"); + if (dwOpcode == 0xee) + strcpy(tempstr, "xor"); + if (dwOpcode == 0xf6) + strcpy(tempstr, "or"); + if (dwOpcode == 0xfe) + strcpy(tempstr, "cmp"); + + ProcBegin(dwOpcode); + + // Let's see if we have to deal with (HL) or #xxh + + fprintf(fp, " sahf\n"); + fprintf(fp, " %s al, [esi]\n", tempstr); + fprintf(fp, " lahf\n"); + + if (dwOpcode != 0xee && dwOpcode != 0xe6 && dwOpcode != 0xf6) + { + SetOverflow(); + } + + if (dwOpcode == 0xe6) + { + fprintf(fp, " and ah, 0ech ; Only parity, half carry, sign, zero\n"); + fprintf(fp, " or ah, 10h ; Half carry\n"); + } + + if (dwOpcode == 0xc6 || dwOpcode == 0xce) + fprintf(fp, " and ah, 0fdh ; Knock out N!\n"); + + if (dwOpcode == 0xd6 || dwOpcode == 0xde || dwOpcode == 0xfe) + fprintf(fp, " or ah, 02h ; Set negative!\n"); + + if (dwOpcode == 0xf6 || dwOpcode == 0xee) + fprintf(fp, " and ah, 0ech ; No H, N, or C\n"); + + fprintf(fp, " inc esi\n"); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (0xfe == dwOpcode) // Cp + { + SetSubFlagsSZHVC("cpu.z80A", "*pbPC++"); + } + else + if (0xe6 == dwOpcode) // And + { + fprintf(fp, " cpu.z80A &= *pbPC++;\n"); + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN);\n"); + fprintf(fp, " cpu.z80F |= bPostANDFlags[cpu.z80A];\n\n"); + } + else + if (0xf6 == dwOpcode) // Or + { + fprintf(fp, " cpu.z80A |= *pbPC++;\n"); + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN);\n"); + fprintf(fp, " cpu.z80F |= bPostORFlags[cpu.z80A];\n\n"); + } + else + if (0xc6 == dwOpcode) // Add + { + fprintf(fp, " bTemp = *pbPC++;\n"); + SetAddFlagsSZHVC("cpu.z80A", "bTemp"); + fprintf(fp, " cpu.z80A += bTemp;\n"); + } + else + if (0xce == dwOpcode) // Adc + { + fprintf(fp, " bTemp = *pbPC++ + (cpu.z80F & Z80_FLAG_CARRY);\n"); + SetAdcFlagsSZHVC("cpu.z80A", "bTemp"); + fprintf(fp, " cpu.z80A += bTemp;\n"); + } + else + if (0xd6 == dwOpcode) // Sub + { + fprintf(fp, " bTemp = *pbPC++;\n"); + SetSubFlagsSZHVC("cpu.z80A", "bTemp"); + fprintf(fp, " cpu.z80A -= bTemp;\n"); + } + else + if (0xde == dwOpcode) // Sbc + { + fprintf(fp, " bTemp = *pbPC++ + (cpu.z80F & Z80_FLAG_CARRY);\n"); + SetSbcFlagsSZHVC("cpu.z80A", "bTemp"); + fprintf(fp, " cpu.z80A = cpu.z80A - bTemp;\n"); + } + else + if (0xee == dwOpcode) // Xor + { + fprintf(fp, " cpu.z80A ^= *pbPC++;\n"); + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN);\n"); + fprintf(fp, " cpu.z80F |= bPostORFlags[cpu.z80A];\n\n"); + } + else + InvalidInstructionC(1); + } + else + { + assert(0); + } +} + +// JR cc, addr + +void JrHandler(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + fprintf(fp, " sub esi, ebp\n"); + fprintf(fp, " and esi, 0ffffh\n"); + fprintf(fp, " add esi, ebp\n"); + + fprintf(fp, " mov dl, [esi] ; Get our relative offset\n"); + fprintf(fp, " inc esi ; Next instruction, please!\n"); + + if (dwOpcode != 0x18) + { + fprintf(fp, " sahf\n"); + fprintf(fp, " j%s takeJump%ld\n", pbFlags[(dwOpcode >> 3) & 0x3], dwGlobalLabel); + fprintf(fp, " jmp short noJumpMan%ld\n", dwGlobalLabel); + fprintf(fp, "takeJump%ld:\n", dwGlobalLabel); + + if (FALSE == bNoTiming) + { + fprintf(fp, " sub edi, 5\n"); + } + } + else // It's a JR + { + fprintf(fp, " cmp dl, 0feh ; Jump to self?\n"); + fprintf(fp, " je yesJrMan ; Yup! Bail out!\n"); + } + + fprintf(fp, " xchg eax, edx\n"); + fprintf(fp, " cbw\n"); + fprintf(fp, " xchg eax, edx\n"); + fprintf(fp, " sub esi, ebp\n"); + fprintf(fp, " add si, dx\n"); + fprintf(fp, " and esi, 0ffffh ; Only the lower 16 bits\n"); + fprintf(fp, " add esi, ebp\n"); + fprintf(fp, " xor dh, dh\n"); + fprintf(fp, "noJumpMan%ld:\n", dwGlobalLabel++); + + FetchNextInstruction(dwOpcode); + + if (0x18 == dwOpcode) + { + fprintf(fp,"yesJrMan:\n"); + + fprintf(fp, " xor edx, edx ; Zero me for later\n"); + fprintf(fp, " mov edi, edx\n"); + fprintf(fp, " mov [cyclesRemaining], edx\n"); + fprintf(fp, " sub esi, 2 ; Back to the instruction again\n"); + fprintf(fp, " jmp noMoreExec\n\n"); + } + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " sdwAddr = (INT8) *pbPC++; /* Get LSB first */\n"); + fprintf(fp, " cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base;\n"); + fprintf(fp, " sdwAddr = (sdwAddr + (INT32) cpu.z80pc) & 0xffff;\n"); + + if (0x18 != dwOpcode) + { + fprintf(fp, " if %s\n", pbFlagsC[(dwOpcode >> 3) & 0x03]); + } + + fprintf(fp, " {\n"); + + fprintf(fp, " sdwCyclesRemaining -= 5;\n"); + + fprintf(fp, " pbPC = cpu.z80Base + sdwAddr; /* Normalize the address */\n"); + fprintf(fp, " }\n"); + + } + else + { + assert(0); + } +} + +void CallHandler(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if (dwOpcode != 0xcd) + { + fprintf(fp, " sahf ; Restore our flags\n"); + fprintf(fp, " j%s takeJump%ld ; We're going call in this case\n", pbFlags[(dwOpcode >> 3) & 0x07], dwGlobalLabel); + fprintf(fp, " add esi, 2 ; Skip past the address\n"); + fprintf(fp, " jmp short noCallTaken%ld ; Go execute the next instruction\n", dwGlobalLabel); + fprintf(fp, "takeJump%ld:\n", dwGlobalLabel); + + fprintf(fp, " sub edi, 7\n"); + } + + + if (bThroughCallHandler) + { + fprintf(fp, " mov dx, [esi] ; Get our call to address\n"); + fprintf(fp, " mov [_z80pc], dx ; Store our new program counter\n"); + fprintf(fp, " add esi, 2 ; Skip to our new address to be pushed\n"); + fprintf(fp, " sub esi, ebp ; Value to push onto the \"stack\"\n"); + fprintf(fp, " mov [_wordval], si ; Store our return address on the stack\n"); + fprintf(fp, " mov si, dx ; Our new address\n"); + fprintf(fp, " add esi, ebp ; And our base address\n"); + fprintf(fp, " call PushWord ; Go push our orgval to the stack\n"); + } + else + { + fprintf(fp, " mov dx, [esi] ; Get our call to address\n"); + fprintf(fp, " mov [_z80pc], dx ; Store our new program counter\n"); + fprintf(fp, " add esi, 2 ; Skip to our new address to be pushed\n"); + fprintf(fp, " sub esi, ebp ; Value to push onto the \"stack\"\n"); + fprintf(fp, " mov dx, word [_z80sp] ; Get the current stack pointer\n"); + fprintf(fp, " sub dx, 2 ; Back up two bytes\n"); + fprintf(fp, " mov [ebp+edx], si ; PUSH It!\n"); + fprintf(fp, " mov word [_z80sp], dx ; Store our new stack pointer\n"); + fprintf(fp, " mov si, [_z80pc] ; Get our new program counter\n"); + fprintf(fp, " add esi, ebp ; Naturalize it!\n"); + } + + if (dwOpcode != 0xcd) + fprintf(fp, "noCallTaken%ld:\n", dwGlobalLabel++); + + fprintf(fp, " xor edx, edx\n"); + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " dwAddr = *pbPC++; /* Get LSB first */\n"); + fprintf(fp, " dwAddr |= ((UINT32) *pbPC++ << 8); /* Get MSB last */\n"); + + if (0xcd != dwOpcode) + { + fprintf(fp, " if %s\n", pbFlagsC[(dwOpcode >> 3) & 0x07]); + fprintf(fp, " {\n"); + fprintf(fp, " cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base;\n"); + fprintf(fp, " pbSP = (cpu.z80Base + cpu.z80sp - 1); /* Normalize the stack pointer */\n"); + fprintf(fp, " *pbSP-- = cpu.z80pc >> 8; /* MSB */\n"); + fprintf(fp, " *pbSP = (UINT8) cpu.z80pc; /* LSB */\n"); + fprintf(fp, " cpu.z80sp -= 2; /* Back our stack up */\n"); + fprintf(fp, " pbPC = cpu.z80Base + dwAddr; /* Normalize the address */\n"); + fprintf(fp, " }\n"); + } + else // Just a regular call + { + fprintf(fp, " cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base;\n"); + fprintf(fp, " pbSP = (cpu.z80Base + cpu.z80sp - 1); /* Normalize the stack pointer */\n"); + fprintf(fp, " *pbSP-- = cpu.z80pc >> 8; /* LSB */\n"); + fprintf(fp, " *pbSP = (UINT8) cpu.z80pc; /* MSB */\n"); + fprintf(fp, " cpu.z80sp -= 2; /* Back our stack up */\n"); + fprintf(fp, " pbPC = cpu.z80Base + dwAddr; /* Normalize the address */\n"); + } + } + else + { + assert(0); + } +} + +void RetHandler(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if (dwOpcode != 0xc9) + { + fprintf(fp, " sahf\n"); + fprintf(fp, " j%s takeReturn%ld\n", pbFlags[(dwOpcode >> 3) & 0x07], dwGlobalLabel); + fprintf(fp, " jmp short retNotTaken%ld\n", dwGlobalLabel); + fprintf(fp, "takeReturn%ld:\n", dwGlobalLabel); + + if (FALSE == bNoTiming) + { + fprintf(fp, " sub edi, byte 6\n"); + } + } + + + if (bThroughCallHandler) + { + fprintf(fp, " call PopWord\n"); + fprintf(fp, " xor esi, esi\n"); + fprintf(fp, " mov si, dx\n"); + fprintf(fp, " add esi, ebp\n"); + fprintf(fp, " xor edx, edx\n"); + } + else + { + fprintf(fp, " mov dx, word [_z80sp] ; Get our current stack pointer\n"); + fprintf(fp, " mov si, [edx+ebp] ; Get our return address\n"); + fprintf(fp, " and esi, 0ffffh ; Only within 64K!\n"); + fprintf(fp, " add esi, ebp ; Add in our base address\n"); + fprintf(fp, " add word [_z80sp], 02h ; Remove our two bytes from the stack\n"); + fprintf(fp, " xor edx, edx\n"); + } + + if (dwOpcode != 0xc9) + fprintf(fp, "retNotTaken%ld:\n", dwGlobalLabel++); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (dwOpcode != 0xc9) + { + fprintf(fp, " if %s\n", pbFlagsC[(dwOpcode >> 3) & 0x07]); + fprintf(fp, " {\n"); + fprintf(fp, " dwElapsedTicks += 6;\n"); + } + + fprintf(fp, " pbSP = cpu.z80Base + cpu.z80sp; /* Normalize our stack PTR */\n"); + fprintf(fp, " dwAddr = *pbSP++; /* Pop LSB */\n"); + fprintf(fp, " dwAddr |= ((UINT32) *pbSP << 8); /* Pop MSB */\n"); + fprintf(fp, " cpu.z80sp += 2; /* Pop the word off */\n"); + fprintf(fp, " pbPC = (cpu.z80Base + dwAddr); /* Point PC to our return address */\n"); + + if (dwOpcode != 0xc9) + { + fprintf(fp, " }\n"); + } + } + else + { + assert(0); + } +} + +void RestartHandler(UINT32 dwOpcode) +{ + UINT32 dwOpcode1 = 0; + + dwOpcode1 = dwOpcode & 0x38; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if (bThroughCallHandler) + { + fprintf(fp, " sub esi, ebp\n"); + fprintf(fp, " mov [_wordval], si ; Store our return address\n"); + fprintf(fp, " call PushWord\n"); + fprintf(fp, " xor esi, esi\n"); + fprintf(fp, " mov si, %.4lxh\n", dwOpcode1); + fprintf(fp, " add esi, ebp\n"); + } + else + { + fprintf(fp, " mov dx, word [_z80sp] ; Get our stack pointer\n"); + fprintf(fp, " sub dx, 2 ; Make room for the new value!\n"); + fprintf(fp, " mov word [_z80sp], dx ; Store our new stack pointer\n"); + fprintf(fp, " sub esi, ebp ; Get our real PC\n"); + fprintf(fp, " mov [ebp+edx], si ; Our return address\n"); + fprintf(fp, " mov si, 0%.2xh ; Our new call address\n", dwOpcode1); + fprintf(fp, " add esi, ebp ; Back to the base!\n"); + } + + fprintf(fp, " xor edx, edx\n"); + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base;\n"); + fprintf(fp, " pbSP = (cpu.z80Base + cpu.z80sp - 1); /* Normalize the stack pointer */\n"); + fprintf(fp, " *pbSP-- = cpu.z80pc >> 8; /* LSB */\n"); + fprintf(fp, " *pbSP = (UINT8) cpu.z80pc; /* MSB */\n"); + fprintf(fp, " cpu.z80sp -= 2; /* Back our stack up */\n"); + fprintf(fp, " pbPC = cpu.z80Base + 0x%.2x; /* Normalize the address */\n", dwOpcode1); + } + else + { + assert(0); + } +} + +void ToRegFromHl(UINT32 dwOpcode) +{ + UINT8 bReg; + + bReg = (dwOpcode >> 3) & 0x07; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if (bReg != 2 && bReg != 3) + ReadValueFromMemory("bx", pbMathReg[bReg]); + else + { + ReadValueFromMemory("bx", pbLocalReg[bReg]); + fprintf(fp, " mov %s, %s\n", pbMathReg[bReg], pbLocalReg[bReg]); + } + + fprintf(fp, " xor edx, edx\n"); + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + ReadValueFromMemory("cpu.z80HL", pbLocalRegC[bReg]); + } + else + { + assert(0); + } +} + +void AddRegpairOperations(UINT32 dwOpcode) +{ + UINT8 bRegpair; + + bRegpair = (dwOpcode >> 4) & 0x3; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + fprintf(fp, " mov dh, ah ; Get our flags\n"); + fprintf(fp, " and dh, 0ech ; Preserve the top three and bits 2 & 3\n"); + + fprintf(fp, " mov [_orgval], bx ; Store our original value\n"); + fprintf(fp, " add bx, %s\n", pbRegPairs[bRegpair]); + fprintf(fp, " lahf\n"); + + fprintf(fp, " mov [cyclesRemaining], edi\n"); + fprintf(fp, " mov di, [_orgval] ; Get original\n"); + fprintf(fp, " xor di, bx ; XOR It with our computed value\n"); + fprintf(fp, " xor di, %s\n", pbRegPairs[bRegpair]); + fprintf(fp, " and di, 1000h ; Just our half carry\n"); + fprintf(fp, " or dx, di ; Or in our flags\n"); + fprintf(fp, " and ah, 01h ; Just carry\n"); + fprintf(fp, " or ah, dh\n"); + fprintf(fp, " mov edi, [cyclesRemaining]\n"); + fprintf(fp, " xor edx, edx\n"); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY);\n"); + fprintf(fp, " dwTemp = cpu.z80HL + %s;\n", pbRegPairsC[bRegpair]); + fprintf(fp, " cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY) | (((cpu.z80HL ^ dwTemp ^ %s) >> 8) & Z80_FLAG_HALF_CARRY);\n", pbRegPairsC[bRegpair]); + fprintf(fp, " cpu.z80HL = dwTemp & 0xffff;\n"); + + return; + } + else + { + assert(0); + } +} + +void PushPopOperations(UINT32 dwOpcode) +{ + UINT8 bRegPair; + + bRegPair = ((dwOpcode >> 4) & 0x3) << 1; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if ((dwOpcode & 0xcf) == 0xc5) // Push + { + fprintf(fp, " sub word [_z80sp], 2\n"); + fprintf(fp, " mov dx, [_z80sp]\n"); + WriteWordToMemory("dx", pbPopRegPairs[bRegPair >> 1]); + } + else // Pop + { + fprintf(fp, " mov dx, [_z80sp]\n"); + ReadWordFromMemory("dx", pbPopRegPairs[bRegPair >> 1]); + fprintf(fp, " add word [_z80sp], 2\n"); + } + + fprintf(fp, " xor edx, edx\n"); + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if ((dwOpcode & 0xcf) == 0xc5) // Push? + { + fprintf(fp, " cpu.z80sp -= 2;\n"); + fprintf(fp, " pbSP = (cpu.z80Base + cpu.z80sp); /* Normalize the stack pointer */\n"); + + WriteWordToMemory("cpu.z80sp", pbPopRegPairC[bRegPair >> 1]); + return; + } + else + { + ReadWordFromMemory("cpu.z80sp", pbPopRegPairC[bRegPair >> 1]); + + fprintf(fp, " cpu.z80sp += 2;\n"); + fprintf(fp, " pbSP = (cpu.z80Base + cpu.z80sp); /* Normalize the stack pointer */\n"); + return; + } + + InvalidInstructionC(1); + } + else + { + assert(0); + } +} + +void RraRlaHandler(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + fprintf(fp, " sahf\n"); + if (dwOpcode == 0x1f) + fprintf(fp, " rcr al, 1\n"); + else + fprintf(fp, " rcl al, 1\n"); + + fprintf(fp, " lahf\n"); + fprintf(fp, " and ah, 0edh\n"); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (0x1f == dwOpcode) // RRA + { + fprintf(fp, " bTemp = (cpu.z80F & Z80_FLAG_CARRY) << 7;\n"); + fprintf(fp, " cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY)) | (cpu.z80A & Z80_FLAG_CARRY);\n"); + fprintf(fp, " cpu.z80A = ((cpu.z80A >> 1) | bTemp);\n"); + } + else // RLA + { + fprintf(fp, " bTemp = cpu.z80A >> 7;\n"); + fprintf(fp, " cpu.z80A = (cpu.z80A << 1) | (cpu.z80F & Z80_FLAG_CARRY);\n"); + fprintf(fp, " cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY)) | bTemp;\n"); + } + } + else + { + assert(0); + } +} + +void LdByteRegpair(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if (dwOpcode == 0x0a) + ReadValueFromMemory("cx", "al"); + if (dwOpcode == 0x1a) + { + fprintf(fp, " mov dx, [_z80de]\n"); + ReadValueFromMemory("dx", "al"); + } + + fprintf(fp, " xor edx, edx\n"); + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (dwOpcode == 0x0a) + ReadValueFromMemory("cpu.z80BC", "cpu.z80A"); + if (dwOpcode == 0x1a) + ReadValueFromMemory("cpu.z80DE", "cpu.z80A"); + } + else + { + assert(0); + } +} + +void IncDecHLPtr(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + ReadValueFromMemory("bx", "dl"); + + fprintf(fp, " sahf\n"); + + if (dwOpcode == 0x34) + fprintf(fp, " inc dl\n"); + else + fprintf(fp, " dec dl\n"); + fprintf(fp, " lahf\n"); + + fprintf(fp, " o16 pushf\n"); + fprintf(fp, " shl edx, 16\n"); + fprintf(fp, " and ah, 0fbh ; Knock out parity/overflow\n"); + fprintf(fp, " pop dx\n"); + fprintf(fp, " and dh, 08h ; Just the overflow\n"); + fprintf(fp, " shr dh, 1 ; Shift it into position\n"); + fprintf(fp, " or ah, dh ; OR It in with the real flags\n"); + + fprintf(fp, " shr edx, 16\n"); + + if (dwOpcode == 0x34) + fprintf(fp, " and ah, 0fdh ; Knock out N!\n"); + else + fprintf(fp, " or ah, 02h ; Make it N!\n"); + + WriteValueToMemory("bx", "dl"); + fprintf(fp, " xor edx, edx\n"); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + ReadValueFromMemory("cpu.z80HL", "bTemp"); + + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE);\n"); + + if (0x34 == dwOpcode) + fprintf(fp ," cpu.z80F |= bPostIncFlags[bTemp];\n"); + else + fprintf(fp ," cpu.z80F |= bPostDecFlags[bTemp];\n"); + + if (0x34 == dwOpcode) + fprintf(fp, " bTemp++;\n"); + else + fprintf(fp, " bTemp--;\n"); + + WriteValueToMemory("cpu.z80HL", "bTemp"); + return; + } + else + { + assert(0); + } +} + +void InOutHandler(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + fprintf(fp, " mov dl, [esi] ; Get our address to 'out' to\n"); + fprintf(fp, " inc esi ; Next address\n"); + + if (b16BitIo) + { + fprintf(fp, " mov dh, al ; Upper 8 bits are the A register for 16 bit addressing\n"); + } + + if (0xd3 == dwOpcode) + WriteValueToIo("dx", "al"); + else + ReadValueFromIo("dx", "al"); + + fprintf(fp, " xor edx, edx\n"); + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp ," dwTemp = *pbPC++;\n"); + + if (0xd3 == dwOpcode) + WriteValueToIo("dwTemp", "cpu.z80A"); + else + ReadValueFromIo("dwTemp", "cpu.z80A"); + + // Not supposed to set flags for immediate instruction! + + return; + } + else + { + assert(0); + } +} + +// CB Area + +void RESSETHandler(UINT32 dwOpcode) +{ + UINT8 op = 0; + + op = dwOpcode & 0x07; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if ((2 == op) || (3 == op)) + fprintf(fp, " mov dx, [_z80de] ; Move DE into something half usable\n"); + + if ((dwOpcode & 0x07) == 6) // (HL)? + ReadValueFromMemory("bx", "dl"); + + if ((dwOpcode & 0xc0) == 0x80) + fprintf(fp, " and %s, 0%.2xh ; Reset a bit\n", + pbLocalReg[op], + 0xff - (1 << ((dwOpcode >> 3) & 0x7))); + + if ((dwOpcode & 0xc0) == 0xc0) + fprintf(fp, " or %s, 0%.2xh ; Set a bit\n", + pbLocalReg[op], + (1 << ((dwOpcode >> 3) & 0x7))); + + if ((2 == op) || (3 == op)) + { + fprintf(fp, " mov [_z80de], dx ; Once modified, put it back\n"); + fprintf(fp, " xor edx, edx\n"); + } + + if ((dwOpcode & 0x07) == 6) // (HL)? + { + WriteValueToMemory("bx", "dl"); + fprintf(fp, " xor edx, edx\n"); + } + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (6 == op) // (HL)? + ReadValueFromMemory("cpu.z80HL", "bTemp"); + + if ((dwOpcode & 0xc0) == 0x80) // RES + fprintf(fp, " %s &= 0x%.2x;\n", pbMathRegC[op], (UINT8) ~((UINT8) 1 << ((dwOpcode >> 3) & 0x07))); + else // SET + fprintf(fp, " %s |= 0x%.2x;\n", pbMathRegC[op], 1 << ((dwOpcode >> 3) & 0x07)); + + if (6 == op) // (HL)? + WriteValueToMemory("cpu.z80HL", "bTemp"); + } + else + assert(0); +} + +void BITHandler(UINT32 dwOpcode) +{ + UINT8 op = 0; + UINT8 bBitVal = 0; + + op = dwOpcode & 0x07; + bBitVal = 1 << ((dwOpcode >> 3) & 0x07); + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if ((dwOpcode & 0x07) == 6) // (HL)? + ReadValueFromMemory("bx", "dl"); + + fprintf(fp, " mov byte [_z80af], ah ; Store F\n"); + fprintf(fp, " sahf\n"); + + if ((dwOpcode & 0x07) == 6) + fprintf(fp, " test dl, 0%.2xh ; Do a bitwise check\n", 1 << ((dwOpcode >> 3) & 0x7)); + else + fprintf(fp, " test %s, 0%.2xh ; Do a bitwise check\n", pbMathReg[op], 1 << ((dwOpcode >> 3) & 0x7)); + + fprintf(fp, " lahf\n"); + fprintf(fp, " and ah, 0c0h ; Only care about Z and S\n"); + fprintf(fp, " or ah, 10h ; Set half carry to 1\n"); + + fprintf(fp, " and byte [_z80af], 029h ; Only zero/non-zero!\n"); + fprintf(fp, " or ah, byte [_z80af] ; Put it in with the real flags\n"); + + if (6 == (dwOpcode & 0x07)) // (HL)? + fprintf(fp, " xor edx, edx\n"); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (6 == op) // (HL)? + ReadValueFromMemory("cpu.z80HL", "bTemp"); + + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO);\n"); + fprintf(fp, " cpu.z80F |= (Z80_FLAG_HALF_CARRY);\n"); + fprintf(fp, " if (!(%s & 0x%.2lx))\n", pbMathRegC[op], bBitVal); + fprintf(fp, " {\n"); + fprintf(fp, " cpu.z80F |= Z80_FLAG_ZERO;\n"); + fprintf(fp, " }\n"); + } + else + assert(0); +} + +void RLCRRCRLRRSLASRASRLHandler(UINT32 dwOpcode) +{ + UINT8 op = 0; + + op = dwOpcode & 0x07; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if ((2 == op) || (3 == op)) + fprintf(fp, " mov dx, [_z80de] ; Move DE into something half usable\n"); + + if ((dwOpcode & 0x07) == 6) // (HL)? + ReadValueFromMemory("bx", "dl"); + + fprintf(fp, " sahf\n"); + + if ((dwOpcode & 0xf8) == 0) + fprintf(fp, " rol %s, 1\n", pbLocalReg[op]); + else + if ((dwOpcode & 0xf8) == 0x08) + fprintf(fp, " ror %s, 1\n", pbLocalReg[op]); + else + if ((dwOpcode & 0xf8) == 0x10) + fprintf(fp, " rcl %s, 1\n", pbLocalReg[op]); + else + if ((dwOpcode & 0xf8) == 0x18) + fprintf(fp, " rcr %s, 1\n", pbLocalReg[op]); + else + if ((dwOpcode & 0xf8) == 0x20 || (dwOpcode & 0xf8) == 0x30) + fprintf(fp, " shl %s, 1\n", pbLocalReg[op]); + else + if ((dwOpcode & 0xf8) == 0x28) + fprintf(fp, " sar %s, 1\n", pbLocalReg[op]); + else + if ((dwOpcode & 0xf8) == 0x38) + fprintf(fp, " shr %s, 1\n", pbLocalReg[op]); + else + assert(0); + + fprintf(fp, " lahf\n"); + + if ((dwOpcode & 0xf8) >= 0x20) + { + if ((dwOpcode & 0xf8) == 0x30) + fprintf(fp, " or %s, 1 ; Slide in a 1 bit (SLIA)\n", pbLocalReg[op]); + fprintf(fp, " and ah, 0edh ; Clear H and N\n"); + } + else + { + fprintf(fp, " and ah, 029h ; Clear H and N\n"); + fprintf(fp, " mov byte [_z80af], ah\n"); + + fprintf(fp, " or %s, %s\n", pbLocalReg[op], pbLocalReg[op]); + + fprintf(fp, " lahf\n"); + fprintf(fp, " and ah, 0c4h ; Sign, zero, and parity\n"); + fprintf(fp, " or ah, byte [_z80af]\n"); + } + + if ((2 == op) || (3 == op)) + { + fprintf(fp, " mov [_z80de], dx ; Once modified, put it back\n"); + fprintf(fp, " xor edx, edx\n"); + } + + if ((dwOpcode & 0x07) == 6) // (HL)? + { + WriteValueToMemory("bx", "dl"); + fprintf(fp, " xor edx, edx\n"); + } + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (6 == op) // (HL)? + ReadValueFromMemory("cpu.z80HL", "bTemp"); + + dwOpcode &= 0xf8; // Just the instruction + + if (0 == dwOpcode) // RLC + { + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY);\n"); + fprintf(fp, " bTemp2 = (%s >> 7);\n", pbMathRegC[op]); + fprintf(fp, " %s = (%s << 1) | bTemp2;\n", pbMathRegC[op], pbMathRegC[op]); + fprintf(fp, " cpu.z80F |= bTemp2 | bPostORFlags[%s];\n", pbMathRegC[op]); + } + else + if (0x08 == dwOpcode) // RRC + { + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY);\n"); + fprintf(fp, " cpu.z80F |= (%s & Z80_FLAG_CARRY);\n", pbMathRegC[op]); + fprintf(fp, " %s = (%s >> 1) | (%s << 7);\n", pbMathRegC[op], pbMathRegC[op], pbMathRegC[op]); + fprintf(fp, " cpu.z80F |= bPostORFlags[%s];\n", pbMathRegC[op]); + } + else + if (0x10 == dwOpcode) // RL + { + fprintf(fp, " bTemp2 = cpu.z80F & Z80_FLAG_CARRY;\n"); + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY);\n"); + fprintf(fp, " cpu.z80F |= (%s >> 7);\n", pbMathRegC[op]); + fprintf(fp, " %s = (%s << 1) | bTemp2;\n", pbMathRegC[op], pbMathRegC[op]); + fprintf(fp, " cpu.z80F |= bPostORFlags[%s];\n", pbMathRegC[op]); + } + else + if (0x18 == dwOpcode) // RR + { + fprintf(fp, " bTemp2 = (cpu.z80F & Z80_FLAG_CARRY) << 7;\n"); + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY);\n"); + fprintf(fp, " cpu.z80F |= (%s & Z80_FLAG_CARRY);\n", pbMathRegC[op]); + fprintf(fp, " %s = (%s >> 1) | bTemp2;\n", pbMathRegC[op], pbMathRegC[op]); + fprintf(fp, " cpu.z80F |= bPostORFlags[%s];\n", pbMathRegC[op]); + } + else + if ((0x20 == dwOpcode) || (0x30 == dwOpcode)) // SLA/SRL + { + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY);\n"); + fprintf(fp, " cpu.z80F |= (%s >> 7);\n", pbMathRegC[op]); + fprintf(fp, " %s = (%s << 1);\n", pbMathRegC[op], pbMathRegC[op]); + fprintf(fp, " cpu.z80F |= bPostORFlags[%s];\n", pbMathRegC[op]); + } + else + if (0x28 == dwOpcode) // SRA + { + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY);\n"); + fprintf(fp, " cpu.z80F |= (%s & Z80_FLAG_CARRY);\n", pbMathRegC[op]); + fprintf(fp, " %s = (%s >> 1) | (%s & 0x80);\n", pbMathRegC[op], pbMathRegC[op], pbMathRegC[op]); + fprintf(fp, " cpu.z80F |= bPostORFlags[%s];\n", pbMathRegC[op]); + } + else + if (0x38 == dwOpcode) // SRL + { + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY);\n"); + fprintf(fp, " cpu.z80F |= (%s & Z80_FLAG_CARRY);\n", pbMathRegC[op]); + fprintf(fp, " %s = (%s >> 1);\n", pbMathRegC[op], pbMathRegC[op], pbMathRegC[op]); + fprintf(fp, " cpu.z80F |= bPostORFlags[%s];\n", pbMathRegC[op]); + } + else + { + InvalidInstructionC(2); + } + + if (6 == op) // (HL)? + WriteValueToMemory("cpu.z80HL", "bTemp"); + } + else + assert(0); +} + +// ED Area + +void RRDRLDHandler(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + ReadValueFromMemory("bx", "dl"); // Get (HL) + fprintf(fp, " mov dh, dl ; Put a copy in DH\n"); + + if (0x6f == dwOpcode) // RLD + { + fprintf(fp, " shr dh, 4 ; Get our upper nibble in position\n"); + fprintf(fp, " shl dl, 4 ; Get our lower nibble into the higher position\n"); + fprintf(fp, " shl ecx, 16 ; Save this for later\n"); + fprintf(fp, " mov cl, al\n"); + fprintf(fp, " and cl, 0fh\n ; Only the lower nibble\n"); + fprintf(fp, " or dl, cl ; OR In A->(HL) transfer\n"); + fprintf(fp, " and al, 0f0h ; Only the upper 4 bits remain\n"); + fprintf(fp, " or al, dh ; OR It in to our accumulator\n"); + fprintf(fp, " shr ecx, 16 ; Restore this\n"); + } + else // RRD + if (0x67 == dwOpcode) + { + fprintf(fp, " shr dl, 4 ; Upper nibble to lower nibble\n"); + fprintf(fp, " shl ecx, 16 ; Save this\n"); + fprintf(fp, " mov cl, al\n"); + fprintf(fp, " shl cl, 4\n"); + fprintf(fp, " or dl, cl ; OR In what was in A\n"); + fprintf(fp, " and al, 0f0h ; Knock out lower part\n"); + fprintf(fp, " and dh, 0fh ; Only the lower nibble\n"); + fprintf(fp, " or al, dh ; OR In our nibble\n"); + fprintf(fp, " shr ecx, 16 ; Restore this\n"); + } + else // Whoops! + assert(0); + + // This routine assumes that the new value to be placed at (HL) is in DL + + fprintf(fp, " and ah, 29h ; Retain carry & two undefined bits\n"); + fprintf(fp, " mov dh, ah ; Store our flags away for later\n"); + + fprintf(fp, " or al, al ; Get our flags\n"); + fprintf(fp, " lahf\n"); + fprintf(fp, " and ah,0c4h ; Only partiy, zero, and sign\n"); + fprintf(fp, " or ah, dh ; OR In our old flags\n"); + + // Now go write the value back + + WriteValueToMemory("bx", "dl"); + fprintf(fp, " xor edx, edx ; Zero out this for later\n"); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (0x67 == dwOpcode) // RRD + { + ReadValueFromMemory("cpu.z80HL", "bTemp"); + fprintf(fp, " bTemp2 = (cpu.z80A & 0x0f) << 4;\n"); + fprintf(fp, " cpu.z80A = (cpu.z80A & 0xf0) | (bTemp & 0x0f);\n"); + fprintf(fp, " bTemp = (bTemp >> 4) | bTemp2;\n"); + + WriteValueToMemory("cpu.z80HL", "bTemp"); + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE);\n"); + fprintf(fp, " cpu.z80F |= bPostORFlags[cpu.z80A];\n"); + } + else + if (0x6f == dwOpcode) // RLD + { + ReadValueFromMemory("cpu.z80HL", "bTemp"); + + fprintf(fp, " bTemp2 = (cpu.z80A & 0x0f);\n"); + fprintf(fp, " cpu.z80A = (cpu.z80A & 0xf0) | (bTemp >> 4);\n"); + fprintf(fp, " bTemp = (bTemp << 4) | bTemp2;\n"); + + WriteValueToMemory("cpu.z80HL", "bTemp"); + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE);\n"); + fprintf(fp, " cpu.z80F |= bPostORFlags[cpu.z80A];\n"); + } + else + InvalidInstructionC(2); + } + else + assert(0); +} + +void CPICPDCPIRCPDRHandler(UINT32 dwOpcode) +{ + UINT32 dwRepeatOb = 0; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if (dwOpcode == 0xb1 || dwOpcode == 0xb9) + { + fprintf(fp, "cpRepeat%ld:\n", dwGlobalLabel); + dwRepeatOb = dwGlobalLabel; + ++dwGlobalLabel; + } + + // Now go get the data from the source + + ReadValueFromMemory("bx", "dl"); + + // Target data is in DL + + fprintf(fp, " mov byte [_z80af], ah\n"); + fprintf(fp, " sahf\n"); + fprintf(fp, " cmp al, dl ; Do our comparison\n"); + fprintf(fp, " lahf\n"); + fprintf(fp, " and ah, 0fah ; No P/V or carry!\n"); + fprintf(fp, " dec cx ; Dec BC\n"); + fprintf(fp, " jz notBcZero%ld\n", dwGlobalLabel); + fprintf(fp, " or ah, 04h ; P/V set when BC not zero\n"); + fprintf(fp, "notBcZero%ld:\n", dwGlobalLabel); + fprintf(fp, " or ah, 02h ; N Gets set when we do compares\n"); + fprintf(fp, " mov dl, byte [_z80af]\n"); + fprintf(fp, " and dl, 01h\n"); + fprintf(fp, " or ah, dl ; Preserve carry!\n"); + + if (dwOpcode == 0xa1 || dwOpcode == 0xb1) + fprintf(fp, " inc bx ; Increment!\n"); + if (dwOpcode == 0xa9 || dwOpcode == 0xb9) + fprintf(fp, " dec bx ; Decrement!\n"); + + // Let's see if we repeat... + + if (dwOpcode == 0xb1 || dwOpcode == 0xb9) + { + fprintf(fp, " sahf\n"); + fprintf(fp, " jz BCDone%ld\n", dwRepeatOb); + fprintf(fp, " jnp BCDone%ld\n", dwRepeatOb); + + if (FALSE == bNoTiming) + { + fprintf(fp, " sub edi, dword 21\n"); + fprintf(fp, " js BCDoneExit%ld\n", dwRepeatOb); + } + + fprintf(fp, " jmp cpRepeat%ld\n", dwRepeatOb); + + fprintf(fp, "BCDoneExit%ld:\n", dwRepeatOb); + fprintf(fp, " sub esi, 2 ; Back up to the instruction again\n"); + fprintf(fp, " jmp noMoreExec\n\n"); + fprintf(fp, "BCDone%ld:\n", dwRepeatOb); + } + + fprintf(fp, " xor edx, edx\n"); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (0xb1 == dwOpcode || 0xb9 == dwOpcode) // Repeat instruction? + { + fprintf(fp, " while ((sdwCyclesRemaining >= 0) && (cpu.z80BC))\n"); + } + + fprintf(fp, " {\n"); + + ReadValueFromMemory("cpu.z80HL", "bTemp"); + + if (0xb1 == dwOpcode || 0xa1 == dwOpcode) + { + fprintf(fp, " cpu.z80HL++;\n"); + fprintf(fp, " cpu.z80HL &= 0xffff;\n"); + } + else + { + fprintf(fp, " cpu.z80HL--;\n"); + fprintf(fp, " cpu.z80HL &= 0xffff;\n"); + } + + fprintf(fp, " cpu.z80BC--;\n"); + fprintf(fp, " cpu.z80BC &= 0xffff;\n"); + + if (0xb1 == dwOpcode || 0xb9 == dwOpcode) // Repeat? + { + fprintf(fp, " sdwCyclesRemaining -= 16;\n"); + fprintf(fp, " if (cpu.z80A == bTemp)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " break;\n"); + fprintf(fp, " }\n"); + } + + fprintf(fp, " }\n"); + + // Now figure out what's going on + + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE);\n"); + fprintf(fp, " cpu.z80F |= (pbSubSbcTable[((UINT32) cpu.z80A << 8) | bTemp] & (Z80_FLAG_SIGN | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO));\n"); + fprintf(fp, " if (cpu.z80BC)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " cpu.z80F |= Z80_FLAG_OVERFLOW_PARITY;\n"); + + fprintf(fp, " }\n"); + } + else + assert(0); +} + +void INIRINDRINIINDHandler(UINT32 dwOpcode) +{ + UINT32 dwTempLabel = 0; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + dwTempLabel = dwGlobalLabel; + dwGlobalLabel++; + + if (0xba == dwOpcode || 0xb2 == dwOpcode) + fprintf(fp, "loopIt%ld:\n", dwTempLabel); + + // Fetch what's at (C) and put it in (HL) + + fprintf(fp, " push cx ; Save BC\n"); + + if (b16BitIo == FALSE) + fprintf(fp, " xor ch, ch ; We want 8 bit ports\n"); + + ReadValueFromIo("cx", "*dl"); // Put our value in DL + fprintf(fp, " pop cx ; Restore BC\n"); + + WriteValueToMemory("bx", "dl"); + + if (0xa2 == dwOpcode || 0xb2 == dwOpcode) + fprintf(fp, " inc bx ; Increment HL\n"); + else + if (0xaa == dwOpcode || 0xba == dwOpcode) + fprintf(fp, " dec bx ; Decrement HL\n"); + + // Now we decrement B + + fprintf(fp, " dec ch ; Decrement B (of C)\n"); + + // Emit this instruction if we repeat + + if (0xba == dwOpcode || 0xb2 == dwOpcode) + { + fprintf(fp, " jz near finalExit%ld\n", dwTempLabel); + + // Otherwise, we need to loop again + + if (FALSE == bNoTiming) + { + fprintf(fp, " sub edi, dword 21\n"); + fprintf(fp, " js loopExit%ld\n", dwTempLabel); + } + + fprintf(fp, " jmp loopIt%ld\n\n", dwTempLabel); + fprintf(fp, "loopExit%ld:\n", dwTempLabel); + fprintf(fp, " sub esi, 2\n"); + fprintf(fp, " jmp noMoreExec\n\n"); + } + + // Now let's fix up the flags + + fprintf(fp, "finalExit%ld:\n", dwTempLabel); + fprintf(fp, " jnz clearFlag%ld\n", dwTempLabel); + fprintf(fp, " or ah, 040h ; Set the Zero flag!\n"); + fprintf(fp, " jmp short continue%ld\n", dwTempLabel); + fprintf(fp, "clearFlag%ld:\n", dwTempLabel); + fprintf(fp, " and ah, 0bfh ; Clear the zero flag\n"); + fprintf(fp, "continue%ld:\n", dwTempLabel); + fprintf(fp, " or ah, 02h ; Set negative!\n"); + fprintf(fp, " xor edx, edx\n"); + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (0xb2 == dwOpcode || 0xba == dwOpcode) // Repeat instruction? + { + fprintf(fp, " while ((sdwCyclesRemaining > 0) && (cpu.z80B))\n"); + } + + fprintf(fp, " {\n"); + + ReadValueFromIo("cpu.z80B", "bTemp"); + WriteValueToMemory("cpu.z80HL", "bTemp"); + + if (0xb2 == dwOpcode || 0xa2 == dwOpcode) + { + fprintf(fp, " cpu.z80HL++;\n"); + fprintf(fp, " cpu.z80HL &= 0xffff;\n"); + } + else + { + fprintf(fp, " cpu.z80HL--;\n"); + fprintf(fp, " cpu.z80HL &= 0xffff;\n"); + } + + fprintf(fp, " sdwCyclesRemaining -= 16;\n"); + + fprintf(fp, " cpu.z80B--;\n"); + fprintf(fp, " }\n"); + + // Now figure out what's going on + + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE);\n"); + fprintf(fp, " cpu.z80F |= (bPostORFlags[bTemp] & (Z80_FLAG_SIGN | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY));\n"); + fprintf(fp, " if (cpu.z80B)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " cpu.z80F |= Z80_FLAG_OVERFLOW_PARITY;\n"); + + fprintf(fp, " pbPC -= 2;\n"); + + fprintf(fp, " }\n"); + } + else + assert(0); +} + +void OTIROTDROUTIOUTDHandler(UINT32 dwOpcode) +{ + UINT32 dwTempLabel = 0; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + dwTempLabel = dwGlobalLabel; + dwGlobalLabel++; + + if (0xbb == dwOpcode || 0xb3 == dwOpcode) + fprintf(fp, "loopIt%ld:\n", dwTempLabel); + + // Fetch what's at (HL) and put it in DL + + ReadValueFromMemory("bx", "dl"); + + fprintf(fp, " push cx ; Save BC\n"); + if (b16BitIo == FALSE) + fprintf(fp, " xor ch, ch ; No 16 bit for this instruction!\n"); + WriteValueToIo("cx", "dl"); + fprintf(fp, " pop cx ; Restore BC now that it has been \"OUT\"ed\n"); + + if (0xa3 == dwOpcode || 0xb3 == dwOpcode) + fprintf(fp, " inc bx ; Increment HL\n"); + else + if (0xab == dwOpcode || 0xbb == dwOpcode) + fprintf(fp, " dec bx ; Decrement HL\n"); + + // Now we decrement B + + fprintf(fp, " dec ch ; Decrement B (of C)\n"); + + // Emit this instruction if we repeat + + if (0xbb == dwOpcode || 0xb3 == dwOpcode) + { + fprintf(fp, " jz near finalExit%ld\n", dwTempLabel); + + // Otherwise, we need to loop again + + if (FALSE == bNoTiming) + { + fprintf(fp, " sub edi, dword 21\n"); + fprintf(fp, " js loopExit%ld\n", dwTempLabel); + } + + fprintf(fp, " jmp loopIt%ld\n\n", dwTempLabel); + fprintf(fp, "loopExit%ld:\n", dwTempLabel); + fprintf(fp, " sub esi, 2\n"); + fprintf(fp, " jmp noMoreExec\n\n"); + } + + // Now let's fix up the flags + + fprintf(fp, "finalExit%ld:\n", dwTempLabel); + fprintf(fp, " jnz clearFlag%ld\n", dwTempLabel); + fprintf(fp, " or ah, 040h ; Set the Zero flag!\n"); + fprintf(fp, " jmp short continue%ld\n", dwTempLabel); + fprintf(fp, "clearFlag%ld:\n", dwTempLabel); + fprintf(fp, " and ah, 0bfh ; Clear the zero flag\n"); + fprintf(fp, "continue%ld:\n", dwTempLabel); + fprintf(fp, " or ah, 02h ; Set negative!\n"); + fprintf(fp, " xor edx, edx\n"); + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (0xb3 == dwOpcode || 0xbb == dwOpcode) // Repeat instruction? + { + fprintf(fp, " while ((sdwCyclesRemaining > 0) && (cpu.z80B))\n"); + } + + fprintf(fp, " {\n"); + + ReadValueFromMemory("cpu.z80HL", "bTemp"); + WriteValueToIo("cpu.z80BC", "bTemp"); + + if (0xb3 == dwOpcode || 0xa3 == dwOpcode) + { + fprintf(fp, " cpu.z80HL++;\n"); + fprintf(fp, " cpu.z80HL &= 0xffff;\n"); + } + else + { + fprintf(fp, " cpu.z80HL--;\n"); + fprintf(fp, " cpu.z80HL &= 0xffff;\n"); + } + + fprintf(fp, " sdwCyclesRemaining -= 16;\n"); + + fprintf(fp, " cpu.z80B--;\n"); + fprintf(fp, " }\n"); + + // Now figure out what's going on + + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE);\n"); + fprintf(fp, " cpu.z80F |= (bPostORFlags[bTemp] & (Z80_FLAG_SIGN | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY));\n"); + fprintf(fp, " if (cpu.z80B)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " cpu.z80F |= Z80_FLAG_OVERFLOW_PARITY;\n"); + + fprintf(fp, " }\n"); + } + else + assert(0); +} + +void AdcSbcRegpair(UINT32 dwOpcode) +{ + UINT8 bOp = 0; + + bOp = (dwOpcode >> 4) & 0x03; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + fprintf(fp, " mov dx, %s ; Get our original register\n", pbRegPairs[bOp]); + fprintf(fp, " mov [_orgval], dx ; Store this for later half carry computation\n"); + fprintf(fp, " mov [_orgval2], bx ; Store this, too\n"); + fprintf(fp, " sahf ; Restore our flags\n"); + + if ((dwOpcode & 0xcf) == 0x4a) + fprintf(fp, " adc bx, dx ; Do the operation!\n"); + else + fprintf(fp, " sbb bx, dx ; Do the operation!\n"); + + fprintf(fp, " lahf ; Get our new flags\n"); + + if ((dwOpcode & 0xcf) != 0x4a) + { + SetOverflow(); + fprintf(fp, " and ah, 0edh ; Knock out negative & half carry flags\n"); + fprintf(fp, " or ah, 02h ; Negative!\n"); + fprintf(fp, " mov [_z80hl], bx\n"); + fprintf(fp, " xor bx, [_orgval]\n"); + fprintf(fp, " xor bx, [_orgval2]\n"); + fprintf(fp, " and bh, 10h ; Half carry?\n"); + fprintf(fp, " or ah, bh ; OR It in if so\n"); + fprintf(fp, " mov bx, [_z80hl]\n"); + } + else + { + SetOverflow(); + fprintf(fp, " and ah, 0edh ; Knock out negative & half carry flags\n"); + fprintf(fp, " mov [_z80hl], bx\n"); + fprintf(fp, " xor bx, [_orgval]\n"); + fprintf(fp, " xor bx, [_orgval2]\n"); + fprintf(fp, " and bh, 10h ; Half carry?\n"); + fprintf(fp, " or ah, bh ; OR It in if so\n"); + fprintf(fp, " mov bx, [_z80hl]\n"); + } + + fprintf(fp, " xor edx, edx ; Make sure we don't hose things\n"); + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if ((dwOpcode & 0xcf) == 0x4a) // ADC + { + fprintf(fp, " dwTemp = cpu.z80HL + %s + (cpu.z80F & Z80_FLAG_CARRY);\n", pbRegPairsC[bOp]); + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN);\n"); + fprintf(fp, " cpu.z80F |= ((dwTemp >> 8) & Z80_FLAG_SIGN);\n"); + fprintf(fp, " if (0 == (dwTemp & 0xffff))\n"); + fprintf(fp, " {\n"); + fprintf(fp, " cpu.z80F |= Z80_FLAG_ZERO;\n"); + fprintf(fp, " }\n"); + fprintf(fp, " cpu.z80F |= (((cpu.z80HL ^ dwTemp ^ %s) >> 8) & Z80_FLAG_HALF_CARRY);\n", pbRegPairsC[bOp]); + fprintf(fp, " cpu.z80F |= ((((%s ^ cpu.z80HL ^ 0x8000) & (%s ^ dwTemp)) >> 13) & Z80_FLAG_OVERFLOW_PARITY);\n", pbRegPairsC[bOp], pbRegPairsC[bOp]); + fprintf(fp, " cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY);\n"); + fprintf(fp, " cpu.z80HL = dwTemp & 0xffff;\n"); + return; + } + else // SBC + { + fprintf(fp, " dwTemp = cpu.z80HL - %s - (cpu.z80F & Z80_FLAG_CARRY);\n", pbRegPairsC[bOp]); + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN);\n"); + fprintf(fp, " cpu.z80F |= ((dwTemp >> 8) & Z80_FLAG_SIGN);\n"); + fprintf(fp, " if (0 == (dwTemp & 0xffff))\n"); + fprintf(fp, " {\n"); + fprintf(fp, " cpu.z80F |= Z80_FLAG_ZERO;\n"); + fprintf(fp, " }\n"); + fprintf(fp, " cpu.z80F |= (((cpu.z80HL ^ dwTemp ^ %s) >> 8) & Z80_FLAG_HALF_CARRY);\n", pbRegPairsC[bOp]); + fprintf(fp, " cpu.z80F |= ((((%s ^ cpu.z80HL) & (%s ^ dwTemp)) >> 13) & Z80_FLAG_OVERFLOW_PARITY);\n", pbRegPairsC[bOp], pbRegPairsC[bOp]); + fprintf(fp, " cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY);\n"); + fprintf(fp, " cpu.z80HL = dwTemp & 0xffff;\n"); + return; + } + } + else + assert(0); +} + +void RetIRetNHandler(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if (bThroughCallHandler) + { + fprintf(fp, " call PopWord\n"); + fprintf(fp, " xor esi, esi\n"); + fprintf(fp, " mov si, dx\n"); + fprintf(fp, " add esi, ebp\n"); + } + else + { + fprintf(fp, " mov dx, word [_z80sp] ; Get our current stack pointer\n"); + fprintf(fp, " mov si, [edx+ebp] ; Get our return address\n"); + fprintf(fp, " and esi, 0ffffh ; Only within 64K!\n"); + fprintf(fp, " add esi, ebp ; Add in our base address\n"); + fprintf(fp, " add word [_z80sp], 02h ; Remove our two bytes from the stack\n"); + } + + if (dwOpcode == 0x45) + { + fprintf(fp, " xor edx, edx\n"); + fprintf(fp, " mov dl, [_z80iff] ; Get interrupt flags\n"); + fprintf(fp, " shr dl, 1 ; Move IFF2->IFF1\n"); + fprintf(fp, " and [_z80iff], dword (~IFF1) ; Get rid of IFF 1\n"); + fprintf(fp, " and dl, IFF1 ; Just want the IFF 1 value now\n"); + fprintf(fp, " or dword [_z80iff], edx\n"); + } + + fprintf(fp, " xor edx, edx ; Make sure we don't hose things\n"); + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (0x4d == dwOpcode) // RETI + { + fprintf(fp, " pbSP = cpu.z80Base + cpu.z80sp; /* Normalize our stack PTR */\n"); + fprintf(fp, " dwAddr = *pbSP++; /* Pop LSB */\n"); + fprintf(fp, " dwAddr |= ((UINT32) *pbSP << 8); /* Pop MSB */\n"); + fprintf(fp, " cpu.z80sp += 2; /* Pop the word off */\n"); + fprintf(fp, " pbPC = (cpu.z80Base + dwAddr); /* Point PC to our return address */\n"); + } + else + if (0x45 == dwOpcode) // RETN + { + fprintf(fp, " pbSP = cpu.z80Base + cpu.z80sp; /* Normalize our stack PTR */\n"); + fprintf(fp, " dwAddr = *pbSP++; /* Pop LSB */\n"); + fprintf(fp, " dwAddr |= ((UINT32) *pbSP << 8); /* Pop MSB */\n"); + fprintf(fp, " cpu.z80sp += 2; /* Pop the word off */\n"); + fprintf(fp, " pbPC = (cpu.z80Base + dwAddr); /* Point PC to our return address */\n"); + fprintf(fp, " cpu.z80iff &= ~(IFF1); /* Keep IFF2 around */\n"); + fprintf(fp, " cpu.z80iff |= ((cpu.z80iff >> 1) & IFF1); /* IFF2->IFF1 */\n"); + } + else + { + InvalidInstructionC(2); + } + } + else + assert(0); +} + +void ExtendedOutHandler(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if (b16BitIo == FALSE) + fprintf(fp, " mov dl, cl ; Address in DX... (C)\n"); + else + fprintf(fp, " mov dx, cx ; Address in DX... (BC)\n"); + + WriteValueToIo("dx", pbMathReg[(dwOpcode >> 3) & 0x07]); + + fprintf(fp, " xor edx, edx\n"); + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (b16BitIo == FALSE) + fprintf(fp, " dwAddr = cpu.z80C;\n"); + else + fprintf(fp, " dwAddr = cpu.z80BC;\n"); + + WriteValueToIo("dwAddr", pbMathRegC[(dwOpcode >> 3) & 0x07]); + } + else + assert(0); +} + +void ExtendedInHandler(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if (b16BitIo == FALSE) + fprintf(fp, " mov dl, cl ; Address in DX... (C)\n"); + else + fprintf(fp, " mov dx, cx ; Address in DX... (BC)\n"); + + ReadValueFromIo("dx", pbMathReg[(dwOpcode >> 3) & 0x07]); + + fprintf(fp, ";\n; Remember, this variant of the IN instruction modifies the flags\n;\n\n"); + fprintf(fp, " sahf ; Restore our flags\n"); + fprintf(fp, " mov dh, ah ; Save flags for later\n"); + + if (0x50 == dwOpcode || 0x58 == dwOpcode) + { + fprintf(fp, " mov dl, %s\n", pbMathReg[(dwOpcode >> 3) & 0x07]); + fprintf(fp, " or dl, dl\n"); + } + else + fprintf(fp, " or %s, %s;\n", pbMathReg[(dwOpcode >> 3) & 0x07], pbMathReg[(dwOpcode >> 3) & 0x07]); + + fprintf(fp, " lahf\n"); + fprintf(fp, " and dh, 029h ; Only keep carry and two unused flags\n"); + fprintf(fp, " and ah, 0d4h\n"); + fprintf(fp, " or ah, dh\n"); + + fprintf(fp, " xor edx, edx\n"); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (b16BitIo == FALSE) + fprintf(fp, " dwAddr = cpu.z80C;\n"); + else + fprintf(fp, " dwAddr = cpu.z80BC;\n"); + + ReadValueFromIo("dwAddr", pbMathRegC[(dwOpcode >> 3) & 0x07]); + + // Set flags! + + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE);\n"); + fprintf(fp, " cpu.z80F |= bPostORFlags[%s];\n", pbMathRegC[(dwOpcode >> 3) & 0x07]); + } + else + assert(0); +} + +void NegHandler(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + fprintf(fp, " sahf\n"); + fprintf(fp, " sub dh, al\n"); + fprintf(fp, " lahf\n"); + fprintf(fp, " mov al, dh\n"); + + SetOverflow(); + fprintf(fp, " or ah, 02h\n"); + fprintf(fp, " xor edx, edx\n"); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + SetSubFlagsSZHVC("0", "cpu.z80A"); + fprintf(fp, " cpu.z80A = 0 - cpu.z80A;\n"); + } + else + assert(0); +} + +void ExtendedRegIntoMemory(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + fprintf(fp, " mov dx, [esi] ; Get our address to write to\n"); + fprintf(fp, " add esi, 2 ; Next address, please...\n"); + + if (dwOpcode == 0x43) + WriteValueToMemory("dx", "cl"); + if (dwOpcode == 0x53) + WriteValueToMemory("dx", "byte [_z80de]"); + if (dwOpcode == 0x63) + WriteValueToMemory("dx", "bl"); + if (dwOpcode == 0x73) + WriteValueToMemory("dx", "byte [_z80sp]"); + + fprintf(fp, " inc dx\n"); + + if (dwOpcode == 0x43) + WriteValueToMemory("dx", "ch"); + if (dwOpcode == 0x53) + WriteValueToMemory("dx", "byte [_z80de + 1]"); + if (dwOpcode == 0x63) + WriteValueToMemory("dx", "bh"); + if (dwOpcode == 0x73) + WriteValueToMemory("dx", "byte [_z80sp + 1]"); + + fprintf(fp, " xor edx, edx ; Zero our upper word\n"); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " dwTemp = *pbPC++;\n"); + fprintf(fp, " dwTemp |= ((UINT32) *pbPC++ << 8);\n"); + + if (0x43 == dwOpcode) // LD (xxxxh), BC + WriteWordToMemory("dwTemp", "cpu.z80BC"); + if (0x53 == dwOpcode) // LD (xxxxh), DE + WriteWordToMemory("dwTemp", "cpu.z80DE"); + if (0x63 == dwOpcode) // LD (xxxxh), HL + WriteWordToMemory("dwTemp", "cpu.z80HL"); + if (0x73 == dwOpcode) // LD (xxxxh), SP + WriteWordToMemory("dwTemp", "cpu.z80sp"); + } + else + assert(0); +} + +void LdRegpair(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + fprintf(fp, " mov dx, [esi] ; Get address to load\n"); + fprintf(fp, " add esi, 2 ; Skip over it so we don't execute it\n"); + + if (dwOpcode == 0x4b) + ReadValueFromMemory("dx", "cl"); + if (dwOpcode == 0x5b) + ReadValueFromMemory("dx", "byte [_z80de]"); + if (dwOpcode == 0x7b) + ReadValueFromMemory("dx", "byte [_z80sp]"); + + fprintf(fp, " inc dx\n"); + + if (dwOpcode == 0x4b) + ReadValueFromMemory("dx", "ch"); + if (dwOpcode == 0x5b) + ReadValueFromMemory("dx", "byte [_z80de + 1]"); + if (dwOpcode == 0x7b) + ReadValueFromMemory("dx", "byte [_z80sp + 1]"); + + fprintf(fp, " xor edx, edx\n"); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " dwTemp = *pbPC++;\n"); + fprintf(fp, " dwTemp |= ((UINT32) *pbPC++ << 8);\n"); + + if (0x4b == dwOpcode) + ReadWordFromMemory("dwTemp", "cpu.z80BC"); + if (0x5b == dwOpcode) + ReadWordFromMemory("dwTemp", "cpu.z80DE"); + if (0x7b == dwOpcode) + ReadWordFromMemory("dwTemp", "cpu.z80sp"); + } + else + assert(0); +} + +void LDILDRLDIRLDDRHandler(UINT32 dwOpcode) +{ + UINT32 dwOrgGlobal = 0; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if (dwOpcode == 0xb0 || dwOpcode == 0xb8) + { + dwOrgGlobal = dwGlobalLabel; + fprintf(fp, "ldRepeat%ld:\n", dwGlobalLabel); + } + + ReadValueFromMemory("bx", "dl"); + + // Here we write the byte back to the target + + WriteValueToMemory("[_z80de]", "dl"); + + // Now we decide what to do + + if ((dwOpcode & 0x0f) == 0) + { + fprintf(fp, " inc bx ; Increment HL\n"); + fprintf(fp, " inc word [_z80de] ; Increment DE\n"); + } + else + { + fprintf(fp, " dec bx ; Decrement HL\n"); + fprintf(fp, " dec word [_z80de] ; Decrement DE\n"); + } + + fprintf(fp, " dec cx ; Decrement BC\n"); + + if (dwOpcode == 0xb0 || dwOpcode == 0xb8) + { + if (FALSE == bNoTiming) + { + fprintf(fp, " jz noMore%ld\n", dwGlobalLabel); + fprintf(fp, " sub edi, dword 16 ; 16 T-States per iteration\n"); + fprintf(fp, " js noMore%ld\n", dwGlobalLabel); + } + else + { + fprintf(fp, " jz noMore%ld\n", dwGlobalLabel); + } + + fprintf(fp, " jmp ldRepeat%ld ; Loop until we're done!\n", dwOrgGlobal); + fprintf(fp, "noMore%ld:\n", dwGlobalLabel); + } + + fprintf(fp, " and ah, 0e9h ; Knock out H & N and P/V\n"); + fprintf(fp, " or cx, cx ; Flag BC\n"); + fprintf(fp, " jz atZero%ld ; We're done!\n", dwGlobalLabel); + + if (dwOpcode == 0xb0 || dwOpcode == 0xb8) + { + // It's a repeat, so let's readjust ESI, shall we? + + fprintf(fp, " or ah, 04h ; Non-zero - we're still going!\n"); + fprintf(fp, " sub esi, 2 ; Adjust back to the beginning of the instruction\n"); + fprintf(fp, " jmp noMoreExec\n\n"); + } + else + if (dwOpcode == 0xa0 || dwOpcode == 0xa8) + { + fprintf(fp, " or ah, 04h ; Non-zero - we're still going!\n"); + } + + fprintf(fp, "atZero%ld:\n", dwGlobalLabel); + ++dwGlobalLabel; + + fprintf(fp, " xor edx, edx ; Make sure we don't hose things\n"); + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + // This is the actual move + + if (0xb0 == dwOpcode || 0xb8 == dwOpcode) // Repeat instruction? + { + fprintf(fp, " while ((sdwCyclesRemaining > 0) && (cpu.z80BC))\n"); + + fprintf(fp, " {\n"); + } + + ReadValueFromMemory("cpu.z80HL", "bTemp"); + WriteValueToMemory("cpu.z80DE", "bTemp"); + + if ((dwOpcode & 0x0f) == 0) + { + fprintf(fp, " ++cpu.z80HL;\n"); + fprintf(fp, " ++cpu.z80DE;\n"); + } + else + { + fprintf(fp, " --cpu.z80HL;\n"); + fprintf(fp, " --cpu.z80DE;\n"); + } + + fprintf(fp, " --cpu.z80BC;\n"); + fprintf(fp, " cpu.z80HL &= 0xffff;\n"); + fprintf(fp, " cpu.z80DE &= 0xffff;\n"); + fprintf(fp, " cpu.z80BC &= 0xffff;\n"); + + if (0xb0 == dwOpcode || 0xb8 == dwOpcode) // Repeat instruction? + { + fprintf(fp, " sdwCyclesRemaining -= 21;\n"); + + fprintf(fp, " }\n"); + } + + // Time for a flag fixup! + + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY);\n"); + fprintf(fp, " if (cpu.z80BC)\n"); + fprintf(fp, " {\n"); + + if (0xb0 == dwOpcode || 0xb8 == dwOpcode) + { + fprintf(fp, " pbPC -= 2; /* Back up so we hit this instruction again */\n"); + } + + fprintf(fp, " cpu.z80F |= Z80_FLAG_OVERFLOW_PARITY;\n"); + fprintf(fp, " }\n"); + + if (0xb0 == dwOpcode || 0xb8 == dwOpcode) // Repeat instruction? + { + fprintf(fp, " sdwCyclesRemaining -= 16;\n"); + } + } + else + assert(0); +} + +void IMHandler(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if (dwOpcode == 0x46) + fprintf(fp, " mov dword [_z80interruptMode], 0 ; IM 0\n"); + + if (dwOpcode == 0x56) + { + fprintf(fp, " mov dword [_z80interruptMode], 1 ; Interrupt mode 1\n"); + fprintf(fp, " mov word [_z80intAddr], 038h ; Interrupt mode 1 cmd!\n"); + } + + if (dwOpcode == 0x5e) + fprintf(fp, " mov dword [_z80interruptMode], 2 ; IM 2\n"); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (0x46 == dwOpcode) // IM 0 + fprintf(fp, " cpu.z80interruptMode = 0;\n"); + + if (0x56 == dwOpcode) // IM 1 + { + fprintf(fp, " cpu.z80interruptMode = 1;\n"); + fprintf(fp, " cpu.z80intAddr = 0x38;\n"); + } + + if (0x5e == dwOpcode) // IM 2 + fprintf(fp, " cpu.z80interruptMode = 2;\n"); + } + else + assert(0); + +} + +void IRHandler(UINT32 dwOpcode) +{ + char *src, *dst; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + switch(dwOpcode) + { + case 0x57: + dst = "al"; src="[_z80i]"; break; + case 0x5F: + dst = "al"; src="[_z80r]"; break; + case 0x47: + dst = "[_z80i]"; src="al"; break; + case 0x4F: + dst = "[_z80r]"; src="al"; break; + } + + ProcBegin(dwOpcode); + + fprintf(fp, " mov %s, %s\n",dst,src); + + if (dwOpcode == 0x5f) + { + fprintf(fp, " and ah, 029h ; No N, H, Z, or S!\n"); + fprintf(fp, " or al,al ; Get appropriate flags\n"); + fprintf(fp, " o16 pushf\n"); + fprintf(fp, " pop dx\n"); + fprintf(fp, " and dl, 0c0h\n"); + fprintf(fp, " or ah, dl ; OR In our S & Z flags\n"); + + fprintf(fp, " mov dl, [_z80iff]\n"); + fprintf(fp, " and dl, IFF2\n"); + fprintf(fp, " shl dl, 1\n"); + fprintf(fp, " or ah, dl\n"); + + // Randomize R + + fprintf(fp, " mov edx, [dwLastRSample]\n"); + fprintf(fp, " sub edx, edi\n"); + fprintf(fp, " add edx, [_z80rCounter]\n"); + fprintf(fp, " shr edx, 2\n"); + fprintf(fp, " and edx, 07fh\n"); + fprintf(fp, " and byte [_z80r], 80h\n"); + fprintf(fp, " or byte [_z80r], dl\n"); + + fprintf(fp, " xor edx, edx\n"); + fprintf(fp, " mov [dwLastRSample], edi\n"); + } + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (0x5f == dwOpcode) // LD A, R + { + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE);\n"); + fprintf(fp, " cpu.z80F |= bPostORFlags[cpu.z80r];\n"); + fprintf(fp, " cpu.z80F = (cpu.z80F & ~(Z80_FLAG_OVERFLOW_PARITY)) | ((cpu.z80iff & IFF2) << 1);\n"); + fprintf(fp, " cpu.z80A = cpu.z80r;\n"); + + // Now randomize a little + + fprintf(fp, " bTemp = (cpu.z80r + (cpu.z80B + sdwCyclesRemaining + 1 + cpu.z80H)) ^ cpu.z80A;\n"); + fprintf(fp, " cpu.z80r = (cpu.z80r & 0x80) | (bTemp & 0x7f);\n"); + } + else + if (0x47 == dwOpcode) // LD I, A + { + fprintf(fp, " cpu.z80i = cpu.z80A;\n"); + } + else + if (0x57 == dwOpcode) // LD A, I + { + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO | Z80_FLAG_SIGN);\n"); + fprintf(fp, " cpu.z80F |= ((cpu.z80iff & IFF2) << 1);\n"); + fprintf(fp, " cpu.z80A = cpu.z80i;\n"); + fprintf(fp, " cpu.z80F |= bPostORFlags[cpu.z80A];\n"); + } + else + if (0x4f == dwOpcode) // LD R, A + { + fprintf(fp, " cpu.z80r = cpu.z80A;\n"); + } + else + { + InvalidInstructionC(2); + } + } + else + assert(0); +} + +// DD/FD Area + +void DDFDCBHandler(UINT32 dwOpcode) +{ + UINT32 dwData = 0; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp, "%sInst%.2x:\n", majorOp, dwOpcode); + fprintf(fp, " mov dx, [esi] ; Get our instruction (and offset)\n"); + fprintf(fp, " add esi, 2 ; Increment our PC\n"); + + fprintf(fp, " mov byte [_orgval], dl ; Store our value\n"); + fprintf(fp, " or dl, dl\n"); + fprintf(fp, " js notNeg%ld\n", dwGlobalLabel); + fprintf(fp, " mov byte [_orgval + 1], 00h;\n"); + + fprintf(fp, " jmp short jumpHandler%ld\n", dwGlobalLabel); + fprintf(fp, "notNeg%ld:\n", dwGlobalLabel); + fprintf(fp, " mov byte [_orgval + 1], 0ffh; It's negative\n"); + fprintf(fp, "jumpHandler%ld:\n", dwGlobalLabel++); + fprintf(fp, " shl ebx, 16 ; Save BX away\n"); + fprintf(fp, " mov bx, [_z80%s]\n", mz80Index); + fprintf(fp, " add [_orgval], bx\n"); + fprintf(fp, " shr ebx, 16 ; Restore BX\n"); + fprintf(fp, " mov dl, dh ; Get our instruction\n"); + fprintf(fp, " xor dh, dh ; Zero this\n"); + fprintf(fp, " jmp dword [z80ddfdcbInstructions+edx*4]\n\n"); + } + else + if (MZ80_C == bWhat) + { + if (strcmp("cpu.z80IX", mz80Index) == 0) + dwData = 0; + else + dwData = 1; + + fprintf(fp, " DDFDCBHandler(%d);\n", dwData); + } + else + assert(0); +} + +void LoadIndexReg(UINT32 dwOpcode) +{ + UINT8 string[150]; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + sprintf(string, "[_z80%s]", mz80Index); + + fprintf(fp, " mov dx, [esi] ; Get our address to store\n"); + fprintf(fp, " add esi, 2\n"); + + ReadWordFromMemory("dx", string); + fprintf(fp, " xor edx, edx\n"); + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " dwAddr = *pbPC++;\n"); + fprintf(fp, " dwAddr |= ((UINT32) *pbPC++ << 8);\n"); + ReadWordFromMemory("dwAddr", mz80Index); + } + else + assert(0); +} + +void StoreIndexReg(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + fprintf(fp, " mov dx, [esi] ; Get our address to store\n"); + fprintf(fp, " add esi, 2\n"); + fprintf(fp, " mov [_orgval], dx\n"); + + fprintf(fp, " mov dl, [_z80%s]\n", mz80Index); + WriteValueToMemory("[_orgval]", "dl"); + + fprintf(fp, " inc word [_orgval]\n"); + + fprintf(fp, " mov dl, [_z80%s + 1]\n", mz80Index); + WriteValueToMemory("[_orgval]", "dl"); + fprintf(fp, " xor edx, edx\n"); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " dwAddr = *pbPC++;\n"); + fprintf(fp, " dwAddr |= ((UINT32) *pbPC++ << 8);\n"); + WriteWordToMemory("dwAddr", mz80Index); + } + else + assert(0); +} + +void LdIndexPtrReg(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + IndexedOffset(mz80Index); + + // DX Contains the address + + WriteValueToMemory("dx", pbMathReg[dwOpcode & 0x07]); + fprintf(fp, " xor edx, edx\n"); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " sdwAddr = (INT8) *pbPC++; // Get the offset\n"); + fprintf(fp, " sdwAddr = ((INT32) %s + sdwAddr) & 0xffff;\n", mz80Index); + + WriteValueToMemory("sdwAddr", pbMathRegC[dwOpcode & 0x07]); + } + else + assert(0); +} + +void UndocMathIndex(UINT32 dwOpcode) +{ + UINT32 dwOpcode1 = 0; + UINT8 *pbIndexReg = NULL; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if (dwOpcode & 1) + fprintf(fp, " mov dl, byte [_z80%s]\n", mz80Index); + else + fprintf(fp, " mov dl, byte [_z80%s + 1]\n", mz80Index); + + // Info is in DL - let's do the math operation + + fprintf(fp, " sahf ; Store our flags in x86 flag reg\n"); + + dwOpcode1 = (dwOpcode & 0xf8); // Only the operation + + if (dwOpcode1 == 0x80) + fprintf(fp, " add al, dl\n"); + else + if (dwOpcode1 == 0x88) + fprintf(fp, " adc al, dl\n"); + else + if (dwOpcode1 == 0x90) + fprintf(fp, " sub al, dl\n"); + else + if (dwOpcode1 == 0x98) + fprintf(fp, " sbb al, dl\n"); + else + if (dwOpcode1 == 0xa0) + fprintf(fp, " and al, dl\n"); + else + if (dwOpcode1 == 0xa8) + fprintf(fp, " xor al, dl\n"); + else + if (dwOpcode1 == 0xb0) + fprintf(fp, " or al, dl\n"); + else + if (dwOpcode1 == 0xb8) + fprintf(fp, " cmp al, dl\n"); + else + assert(0); + + fprintf(fp, " lahf ; Get flags back into AH\n"); + + if (dwOpcode1 != 0xa8 && dwOpcode1 != 0xa0 && dwOpcode1 != 0xb0) + { + SetOverflow(); + } + + if (dwOpcode1 == 0xa8) + fprintf(fp, " and ah, 0ech ; Only these flags matter!\n"); + + if (dwOpcode1 == 0xa0) + { + fprintf(fp, " and ah, 0ech ; Only these flags matter!\n"); + fprintf(fp, " or ah, 010h ; Half carry gets set\n"); + } + + if (dwOpcode1 == 0xb0) + fprintf(fp, " and ah, 0ech ; No H, N, or C\n"); + + if (dwOpcode1 == 0xb8) + fprintf(fp, " or ah, 02h ; Negative gets set on a compare\n"); + + if (dwOpcode1 == 0x80 || dwOpcode1 == 0x88) + fprintf(fp, " and ah, 0fdh ; No N!\n"); + + if (dwOpcode1 == 0x90 || dwOpcode1 == 0x98) + fprintf(fp, " or ah, 02h ; N Gets set!\n"); + + if (dwOpcode1 == 0xb0) + fprintf(fp, " and ah, 0ech ; No H, N, or C\n"); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (dwOpcode & 1) + pbIndexReg = mz80IndexHalfLow; + else + pbIndexReg = mz80IndexHalfHigh; + + dwOpcode1 = (dwOpcode & 0xf8); // Only the operation + + if (0x80 == dwOpcode1) // ADD + { + fprintf(fp, " bTemp2 = cpu.z80A + %s;\n", pbIndexReg); + SetAddFlagsSZHVC("cpu.z80A", pbIndexReg); + } + else + if (0x88 == dwOpcode1) // ADC + { + fprintf(fp, " bTemp2 = cpu.z80A + %s + (cpu.z80F & Z80_FLAG_CARRY);\n", pbIndexReg); + SetAdcFlagsSZHVC("cpu.z80A", pbIndexReg); + } + else + if (0x90 == dwOpcode1) // SUB + { + fprintf(fp, " bTemp2 = cpu.z80A - %s;\n", pbIndexReg); + SetSubFlagsSZHVC("cpu.z80A", pbIndexReg); + } + else + if (0x98 == dwOpcode1) // SBC + { + fprintf(fp, " bTemp2 = cpu.z80A - %s - (cpu.z80F & Z80_FLAG_CARRY);\n", pbIndexReg); + SetSbcFlagsSZHVC("cpu.z80A", pbIndexReg); + } + else + if (0xa0 == dwOpcode1) // AND + { + fprintf(fp, " cpu.z80A &= %s;\n", pbIndexReg); + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN);\n"); + fprintf(fp, " cpu.z80F |= bPostANDFlags[cpu.z80A];\n\n"); + } + else + if (0xa8 == dwOpcode1) // XOR + { + fprintf(fp, " cpu.z80A ^= %s;\n", pbIndexReg); + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN);\n"); + fprintf(fp, " cpu.z80F |= bPostORFlags[cpu.z80A];\n\n"); + } + else + if (0xb0 == dwOpcode1) // OR + { + fprintf(fp, " cpu.z80A |= %s;\n", pbIndexReg); + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN);\n"); + fprintf(fp, " cpu.z80F |= bPostORFlags[cpu.z80A];\n\n"); + } + else + if (0xb8 == dwOpcode1) // CP - Don't do anything! Just flags! + { + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN);\n"); + fprintf(fp, " cpu.z80F |= bPostORFlags[cpu.z80A];\n\n"); + } + else + { + assert(0); + } + + InvalidInstructionC(2); + } + else + assert(0); +} + +void UndocLoadHalfIndexReg(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + fprintf(fp, " mov dl, [esi] ; Get immediate byte to load\n"); + fprintf(fp, " inc esi ; Next byte\n"); + + if (dwOpcode == 0x26) + fprintf(fp, " mov byte [_z80%s + 1], dl\n", mz80Index); + if (dwOpcode == 0x2e) + fprintf(fp, " mov byte [_z80%s], dl\n", mz80Index); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (dwOpcode & 0x08) + fprintf(fp, " %s = *pbPC++;\n", mz80IndexHalfLow); + else + fprintf(fp, " %s = *pbPC++;\n", mz80IndexHalfHigh); + } + else + assert(0); +} + +void UndocIncDecIndexReg(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + fprintf(fp, " sahf\n"); + + if (dwOpcode == 0x24) + fprintf(fp, " inc byte [_z80%s + 1]\n", mz80Index); + if (dwOpcode == 0x25) + fprintf(fp, " dec byte [_z80%s + 1]\n", mz80Index); + + if (dwOpcode == 0x2c) + fprintf(fp, " inc byte [_z80%s]\n", mz80Index); + if (dwOpcode == 0x2d) + fprintf(fp, " dec byte [_z80%s]\n", mz80Index); + + fprintf(fp, " lahf\n"); + SetOverflow(); + + if ((0x24 == dwOpcode) || (0x2c == dwOpcode)) + fprintf(fp, " and ah, 0fdh ; Knock out N!\n"); + else + fprintf(fp, " or ah, 02h ; Set negative!\n"); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE);\n"); + + if (0x24 == dwOpcode || 0x2c == dwOpcode) + { + if (dwOpcode & 0x08) + fprintf(fp, " cpu.z80F |= bPostIncFlags[%s++];\n", mz80IndexHalfLow); + else + fprintf(fp, " cpu.z80F |= bPostIncFlags[%s++];\n", mz80IndexHalfHigh); + } + else + { + if (dwOpcode & 0x08) + fprintf(fp, " cpu.z80F |= bPostDecFlags[%s--];\n", mz80IndexHalfLow); + else + fprintf(fp, " cpu.z80F |= bPostDecFlags[%s--];\n", mz80IndexHalfHigh); + } + } + else + assert(0); +} + +void ExIndexed(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if( bThroughCallHandler ) + { + fprintf(fp, " mov dx, word [_z80%s]\n", mz80Index); + fprintf(fp, " push dx\n"); + fprintf(fp, " call PopWord\n"); + fprintf(fp, " mov [_z80%s], dx\n", mz80Index); + fprintf(fp, " pop dx\n"); + fprintf(fp, " mov [_wordval], dx\n" ); + fprintf(fp, " call PushWord\n" ); + } + else + { + fprintf(fp, " mov [cyclesRemaining], edi\n"); + fprintf(fp, " mov dx, word [_z80sp]\n"); + fprintf(fp, " xor edi, edi\n"); + fprintf(fp, " mov di, [_z80%s]\n", mz80Index); + fprintf(fp, " xchg di, [ebp+edx]\n"); + fprintf(fp, " mov [_z80%s], di\n", mz80Index); + fprintf(fp, " xor edx, edx\n"); + fprintf(fp, " mov edi, [cyclesRemaining]\n"); + } + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + ReadWordFromMemory("cpu.z80sp", "dwAddr"); + WriteWordToMemory("cpu.z80sp", mz80Index); + fprintf(fp, " %s = dwAddr;\n", mz80Index); + } + else + assert(0); +} + +void IncDecIndexReg(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if (dwOpcode == 0x23) + fprintf(fp, " inc word [_z80%s] ; Increment our mz80Index register\n", mz80Index); + else + fprintf(fp, " dec word [_z80%s] ; Increment our mz80Index register\n", mz80Index); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (0x23 == dwOpcode) + { + fprintf(fp, " %s++;\n", mz80Index); + } + else + { + fprintf(fp, " %s--;\n", mz80Index); + } + + fprintf(fp, " %s &= 0xffff;\n", mz80Index); + } + else + assert(0); +} + +void LdRegIndexOffset(UINT32 dwOpcode) +{ + UINT32 dwOpcode1 = 0; + + dwOpcode1 = (dwOpcode & 0x38) >> 3; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + IndexedOffset(mz80Index); + + ReadValueFromMemory("dx", pbMathReg[dwOpcode1]); + + fprintf(fp, " xor edx, edx ; Make sure we don't hose things\n"); + dwGlobalLabel++; + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " sdwAddr = (INT8) *pbPC++; // Get the offset\n"); + fprintf(fp, " sdwAddr = ((INT32) %s + sdwAddr) & 0xffff;\n", mz80Index); + + ReadValueFromMemory("sdwAddr", pbMathRegC[dwOpcode1]); + } + else + assert(0); +} + +void LdByteToIndex(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + fprintf(fp, " mov dx, [esi] ; Get our address\n"); + fprintf(fp, " add esi, 2 ; Skip over our storage bytes\n"); + fprintf(fp, " mov [cyclesRemaining], edi\n"); + fprintf(fp, " mov di, dx ; Store it here for later\n"); + fprintf(fp, " xor dh, dh\n"); + fprintf(fp, " or dl, dl\n"); + fprintf(fp, " jns noNegate%ld\n", dwGlobalLabel); + fprintf(fp, " dec dh\n"); + fprintf(fp, "noNegate%ld:\n", dwGlobalLabel); + fprintf(fp, " add dx, [_z80%s] ; Add in our index\n", mz80Index); + fprintf(fp, " mov [_orgval], dx ; Store our address to write to\n"); + fprintf(fp, " mov dx, di\n"); + fprintf(fp, " xchg dh, dl\n"); + fprintf(fp, " mov edi, [cyclesRemaining]\n"); + + WriteValueToMemory("[_orgval]", "dl"); + + fprintf(fp, " xor edx, edx\n"); + ++dwGlobalLabel; + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " sdwAddr = (INT8) *pbPC++; // Get the offset\n"); + fprintf(fp, " sdwAddr = ((INT32) %s + sdwAddr) & 0xffff;\n", mz80Index); + + WriteValueToMemory("sdwAddr", "*pbPC++"); + } + else + assert(0); +} + + +void SPToIndex(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + fprintf(fp, " mov dx, [_z80%s] ; Get our source register\n", mz80Index); + fprintf(fp, " mov word [_z80sp], dx ; Store our new SP\n"); + fprintf(fp, " xor edx, edx\n"); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " cpu.z80sp = %s;\n", mz80Index); + } + else + assert(0); +} + +void AddIndexHandler(UINT32 dwOpcode) +{ + UINT8 bRegPair; + + bRegPair = dwOpcode >> 4; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + fprintf(fp, " mov dh, ah ; Get our flags\n"); + fprintf(fp, " and dh, 0ech ; Preserve the top three and bits 2 & 3\n"); + + fprintf(fp, " mov [cyclesRemaining], edi\n"); + fprintf(fp, " mov di, [_z80%s] ; Get our value\n", mz80Index); + fprintf(fp, " mov [_orgval], di ; Store our original value\n"); + fprintf(fp, " add di, %s\n", pbIndexedRegPairs[(dwOpcode & 0x30) >> 4]); + fprintf(fp, " lahf\n"); + fprintf(fp, " mov [_z80%s], di ; Store our register back\n", mz80Index); + + fprintf(fp, " mov di, [_orgval] ; Get original\n"); + fprintf(fp, " xor di, word [_z80%s] ; XOR It with our computed value\n", mz80Index); + fprintf(fp, " xor di, %s\n", pbIndexedRegPairs[(dwOpcode & 0x30) >> 4]); + fprintf(fp, " and di, 1000h ; Just our half carry\n"); + fprintf(fp, " or dx, di ; Or in our flags\n"); + fprintf(fp, " and ah, 01h ; Just carry\n"); + fprintf(fp, " or ah, dh\n"); + fprintf(fp, " mov edi, [cyclesRemaining]\n"); + fprintf(fp, " xor edx, edx\n"); + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (bRegPair != 2) + { + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY);\n"); + fprintf(fp, " dwTemp = %s + %s;\n", mz80Index, pbRegPairsC[bRegPair]); + fprintf(fp, " cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY) | (((%s ^ dwTemp ^ %s) >> 8) & Z80_FLAG_HALF_CARRY);\n", mz80Index, pbRegPairsC[bRegPair]); + fprintf(fp, " %s = dwTemp & 0xffff;\n", mz80Index); + } + else + { + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY);\n"); + fprintf(fp, " dwTemp = %s + %s;\n", mz80Index, mz80Index); + fprintf(fp, " cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY) | (((%s ^ dwTemp ^ %s) >> 8) & Z80_FLAG_HALF_CARRY);\n", mz80Index, pbRegPairsC[bRegPair]); + fprintf(fp, " %s = dwTemp & 0xffff;\n", mz80Index); + } + } + else + assert(0); +} + +void JPIXIYHandler(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + fprintf(fp, " mov dx, [_z80%s] ; Get our value\n", mz80Index); + fprintf(fp, " mov esi, edx ; New PC!\n"); + fprintf(fp, " add esi, ebp ; Add in our base\n"); + fprintf(fp, " xor edx, edx\n"); + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " pbPC = cpu.z80Base + %s;\n", mz80Index); + } + else + assert(0); +} + +void IncDecIndexed(UINT32 dwOpcode) +{ + UINT8 szIndex[30]; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + IndexedOffset(mz80Index); + + fprintf(fp, " mov [_orgval], dx\n"); + + ReadValueFromMemory("dx", "dl"); + + fprintf(fp, " sahf\n"); + + if (dwOpcode == 0x34) + fprintf(fp, " inc dl\n"); + else + fprintf(fp, " dec dl\n"); + fprintf(fp, " lahf\n"); + + fprintf(fp, " o16 pushf\n"); + fprintf(fp, " shl edx, 16\n"); + fprintf(fp, " and ah, 0fbh ; Knock out parity/overflow\n"); + fprintf(fp, " pop dx\n"); + fprintf(fp, " and dh, 08h ; Just the overflow\n"); + fprintf(fp, " shr dh, 1 ; Shift it into position\n"); + fprintf(fp, " or ah, dh ; OR It in with the real flags\n"); + + fprintf(fp, " shr edx, 16\n"); + + if (dwOpcode == 0x34) + fprintf(fp, " and ah, 0fdh ; Knock out N!\n"); + else + fprintf(fp, " or ah, 02h ; Make it N!\n"); + + WriteValueToMemory("[_orgval]", "dl"); + + fprintf(fp, " xor edx, edx\n"); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " sdwAddr = (INT8) *pbPC++; /* Get LSB first */\n"); + fprintf(fp, " dwAddr = (sdwAddr + (INT32) %s) & 0xffff;\n", mz80Index); + + ReadValueFromMemory("dwAddr", "bTemp"); + + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE);\n"); + + if (0x34 == dwOpcode) + { + fprintf(fp ," cpu.z80F |= bPostIncFlags[bTemp++];\n"); + } + else + { + fprintf(fp ," cpu.z80F |= bPostDecFlags[bTemp--];\n"); + } + + WriteValueToMemory("dwAddr", "bTemp"); + } + else + assert(0); +} + +void MathOperationIndexed(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + IndexedOffset(mz80Index); + ReadValueFromMemory("dx", "dl"); + + fprintf(fp, " sahf\n"); + + if (dwOpcode == 0x86) // Add + fprintf(fp, " add al, dl\n"); + if (dwOpcode == 0x8e) // Adc + fprintf(fp, " adc al, dl\n"); + if (dwOpcode == 0x96) // Sub + fprintf(fp, " sub al, dl\n"); + if (dwOpcode == 0x9e) // Sbc + fprintf(fp, " sbb al, dl\n"); + if (dwOpcode == 0xa6) // And + fprintf(fp, " and al, dl\n"); + if (dwOpcode == 0xae) // Xor + fprintf(fp, " xor al, dl\n"); + if (dwOpcode == 0xb6) // Or + fprintf(fp, " or al, dl\n"); + if (dwOpcode == 0xbe) // Cp + fprintf(fp, " cmp al, dl\n"); + + fprintf(fp, " lahf\n"); + + if (dwOpcode == 0x86 || dwOpcode == 0x8e) + { + SetOverflow(); + fprintf(fp, " and ah, 0fdh ; Knock out negative\n"); + } + + if (dwOpcode == 0x96 || dwOpcode == 0x9e || dwOpcode == 0xbe) + { + SetOverflow(); + fprintf(fp, " or ah, 02h ; Set negative\n"); + } + + if (dwOpcode == 0xae || dwOpcode == 0xb6) + fprintf(fp, " and ah, 0ech ; Knock out H, N, and C\n"); + + if (dwOpcode == 0xa6) + { + fprintf(fp, " and ah,0fch ; Knock out N & C\n"); + fprintf(fp, " or ah, 10h ; Set half carry\n"); + } + + fprintf(fp, " xor edx, edx\n"); + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " sdwAddr = (INT8) *pbPC++; /* Get LSB first */\n"); + fprintf(fp, " dwAddr = (sdwAddr + (INT32) %s) & 0xffff;\n", mz80Index); + + ReadValueFromMemory("dwAddr", "bTemp"); + + if (0x86 == dwOpcode) // ADD A, (IX/IY+nn) + { + SetAddFlagsSZHVC("cpu.z80A", "bTemp"); + fprintf(fp, " cpu.z80A += bTemp;\n"); + } + else + if (0x8e == dwOpcode) // ADC A, (IX/IY+nn) + { + fprintf(fp, " bTemp2 = (cpu.z80F & Z80_FLAG_CARRY);\n"); + SetAdcFlagsSZHVC("cpu.z80A", "bTemp"); + fprintf(fp, " cpu.z80A += bTemp + bTemp2;\n"); + } + else + if (0x96 == dwOpcode) // SUB A, (IX/IY+nn) + { + SetSubFlagsSZHVC("cpu.z80A", "bTemp"); + fprintf(fp, " cpu.z80A -= bTemp;\n"); + } + else + if (0x9e == dwOpcode) // SBC A, (IX/IY+nn) + { + fprintf(fp, " bTemp2 = cpu.z80A;\n"); + fprintf(fp, " cpu.z80A = cpu.z80A - bTemp - (cpu.z80F & Z80_FLAG_CARRY);\n"); + SetSbcFlagsSZHVC("bTemp2", "bTemp"); + } + else + if (0xa6 == dwOpcode) // AND A, (IX/IY+nn) + { + fprintf(fp, " cpu.z80A &= bTemp;\n"); + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN);\n"); + fprintf(fp, " cpu.z80F |= bPostANDFlags[cpu.z80A];\n\n"); + } + else + if (0xae == dwOpcode) // XOR A, (IX/IY+nn) + { + fprintf(fp, " cpu.z80A ^= bTemp;\n"); + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN);\n"); + fprintf(fp, " cpu.z80F |= bPostORFlags[cpu.z80A];\n\n"); + } + else + if (0xb6 == dwOpcode) // OR A, (IX/IY+nn) + { + fprintf(fp, " cpu.z80A |= bTemp;\n"); + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN);\n"); + fprintf(fp, " cpu.z80F |= bPostORFlags[cpu.z80A];\n\n"); + } + else + if (0xbe == dwOpcode) // CP A, (IX/IY+nn) + { + SetSubFlagsSZHVC("cpu.z80A", "bTemp"); + } + else + InvalidInstructionC(2); + } + else + assert(0); +} + +void UndocIndexToReg(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if ((dwOpcode & 0x07) == 2 || (dwOpcode & 0x07) == 3) + fprintf(fp, " mov dx, [_z80de] ; Get DE\n"); + + if ((dwOpcode & 0x07) == 4) + fprintf(fp, " mov dh, byte [_z80%s + 1]\n", mz80Index); + if ((dwOpcode & 0x07) == 5) + fprintf(fp, " mov dl, byte [_z80%s]\n", mz80Index); + + fprintf(fp, " mov byte [_z80%s + %ld], %s\n", mz80Index, 1 - ((dwOpcode & 0x08) >> 3), pbLocalReg[dwOpcode & 0x07]); + fprintf(fp, " xor edx, edx\n"); + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (dwOpcode != 0x64 && dwOpcode != 0x65 && dwOpcode != 0x6c && dwOpcode != 0x6d) + { + if (dwOpcode & 0x08) + fprintf(fp, " %s = %s;\n", mz80IndexHalfLow, pbLocalRegC[dwOpcode & 0x07]); + else + fprintf(fp, " %s = %s;\n", mz80IndexHalfHigh, pbLocalRegC[dwOpcode & 0x07]); + } + else // IX/IY High/low weirdness afoot... + { + // We don't generate any code for ld indexH, indexH and ld indexL, indexL + + if (0x65 == dwOpcode) // LD indexH, indexL + { + fprintf(fp, " %s = %s;\n", mz80IndexHalfHigh, mz80IndexHalfLow); + } + else + if (0x6c == dwOpcode) // LD indexH, indexL + { + fprintf(fp, " %s = %s;\n", mz80IndexHalfLow, mz80IndexHalfHigh); + } + } + } + else + assert(0); +} + +void UndocRegToIndex(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + if ((dwOpcode & 0x38) == 0x10 || (dwOpcode & 0x38) == 0x18) + fprintf(fp, " mov dx, [_z80de] ; Get a usable copy of DE here\n"); + + fprintf(fp, " mov %s, byte [_z80%s + %ld]\n", pbLocalReg[(dwOpcode >> 3) & 0x07], mz80Index, 1 - (dwOpcode & 1)); + + if ((dwOpcode & 0x38) == 0x10 || (dwOpcode & 0x38) == 0x18) + fprintf(fp, " mov [_z80de], dx ; Put it back!\n"); + + fprintf(fp, " xor edx, edx\n"); + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (dwOpcode & 1) + fprintf(fp, " %s = %s;\n", pbLocalRegC[(dwOpcode >> 3) & 0x07], mz80IndexHalfLow); + else + fprintf(fp, " %s = %s;\n", pbLocalRegC[(dwOpcode >> 3) & 0x07], mz80IndexHalfHigh); + } + else + assert(0); +} + +void LoadImmediate(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + fprintf(fp, " mov dx, [esi] ; Get our word to load\n"); + fprintf(fp, " add esi, 2 ; Advance past the word\n"); + fprintf(fp, " mov [_z80%s], dx ; Store our new value\n", mz80Index); + fprintf(fp, " xor edx, edx\n"); + + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, " %s = *pbPC++;\n", mz80Index); + fprintf(fp, " %s |= ((UINT32) *pbPC++ << 8);\n", mz80Index); + } + else + assert(0); +} + +void PushPopOperationsIndexed(UINT32 dwOpcode) +{ + UINT8 bRegPair; + UINT8 bRegBaseLsb[25]; + UINT8 bRegBaseMsb[25]; + UINT8 string[150]; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + sprintf(bRegBaseLsb, "byte [_z80%s]", mz80Index); + sprintf(bRegBaseMsb, "byte [_z80%s + 1]", mz80Index); + + sprintf(string, "[_z80%s]", mz80Index); + + ProcBegin(dwOpcode); + + if (dwOpcode == 0xe5) // Push IX/IY + { + fprintf(fp, " sub word [_z80sp], 2\n"); + fprintf(fp, " mov dx, [_z80sp]\n"); + + WriteWordToMemory("dx", string); + } + else // Pop + { + fprintf(fp, " mov dx, [_z80sp]\n"); + ReadWordFromMemory("dx", string); + fprintf(fp, " add word [_z80sp], 2\n"); + } + + fprintf(fp, " xor edx, edx\n"); + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (0xe5 == dwOpcode) // Push IX/IY + { + fprintf(fp, " cpu.z80sp -= 2;\n"); + fprintf(fp, " pbSP = (cpu.z80Base + cpu.z80sp); /* Normalize the stack pointer */\n"); + + WriteWordToMemory("cpu.z80sp", mz80Index); + } + else + if (0xe1 == dwOpcode) // Pop IX/IY + { + ReadWordFromMemory("cpu.z80sp", mz80Index); + + fprintf(fp, " cpu.z80sp += 2;\n"); + fprintf(fp, " pbSP = (cpu.z80Base + cpu.z80sp); /* Normalize the stack pointer */\n"); + return; + } + } + else + assert(0); +} + +// DDFD XXCB Instructions + +void ddcbBitWise(UINT32 dwOpcode) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + ProcBegin(dwOpcode); + + // NOTE: _orgval contains the address to get from. It includes the offset + // already computed plus the mz80Index register. + + // Read our byte + + fprintf(fp, " mov dx, [_orgval] ; Get our target address\n"); + ReadValueFromMemory("dx", "dl"); + + // Do the operation + + if (dwOpcode != 0x06 && dwOpcode != 0x0e && + dwOpcode != 0x16 && dwOpcode != 0x1e && + dwOpcode != 0x26 && dwOpcode != 0x2e && + dwOpcode != 0x3e && (dwOpcode & 0xc7) != 0x86 && + (dwOpcode & 0xc7) != 0xc6) + { + fprintf(fp, " mov dh, ah ; Store our original flags\n"); + fprintf(fp, " and dh, 29h ; Keep our old flags\n"); + } + + if ((dwOpcode & 0xc7) != 0x86 && (dwOpcode & 0xc7) != 0xc6) + fprintf(fp, " sahf ; Restore our flags\n"); + + if (dwOpcode == 0x06) + fprintf(fp, " rol dl, 1\n"); + if (dwOpcode == 0x0e) + fprintf(fp, " ror dl, 1\n"); + if (dwOpcode == 0x16) + fprintf(fp, " rcl dl, 1\n"); + if (dwOpcode == 0x1e) + fprintf(fp, " rcr dl, 1\n"); + if (dwOpcode == 0x26) + fprintf(fp, " shl dl, 1\n"); + if (dwOpcode == 0x2e) + fprintf(fp, " sar dl, 1\n"); + if (dwOpcode == 0x3e) + fprintf(fp, " shr dl, 1\n"); + + // BIT, AND, and OR + + if ((dwOpcode & 0xc7) == 0x46) + fprintf(fp, " test dl, 0%.2xh ; Is it set?\n", (1 << ((dwOpcode >> 3) & 0x07))); + else + if ((dwOpcode & 0xc7) == 0x86) + fprintf(fp, " and dl, 0%.2xh ; Reset the bit\n", + 0xff - (1 << ((dwOpcode >> 3) & 0x07))); + else + if ((dwOpcode & 0xc7) == 0xc6) + fprintf(fp, " or dl, 0%.2xh ; Set the bit\n", + (1 << ((dwOpcode >> 3) & 0x07))); + + if ((dwOpcode & 0xc7) != 0x86 && (dwOpcode & 0xc7) != 0xc6) + fprintf(fp, " lahf ; Get our flags back\n"); + + // Do the flag fixup (if any) + + if (dwOpcode == 0x26 || dwOpcode == 0x2e || ((dwOpcode & 0xc7) == 0x46)) + fprintf(fp, " and ah, 0edh ; No Half carry or negative!\n"); + + if (dwOpcode == 0x06 || dwOpcode == 0x0e || + dwOpcode == 0x16 || dwOpcode == 0x1e || + dwOpcode == 0x3e) + fprintf(fp, " and ah, 0edh ; Knock out H & N\n"); + + // BIT! + + if ((dwOpcode & 0xc7) == 0x46) + { + fprintf(fp, " or ah, 10h ; OR In our half carry\n"); + fprintf(fp, " and ah, 0d0h ; New flags\n"); + fprintf(fp, " or ah, dh ; OR In our old flags\n"); + } + + // Now write our data back if it's not a BIT instruction + + if ((dwOpcode & 0xc7) != 0x46) // If it's not a BIT, write it back + WriteValueToMemory("[_orgval]", "dl"); + + fprintf(fp, " xor edx, edx\n"); + FetchNextInstruction(dwOpcode); + } + else + if (MZ80_C == bWhat) + { + if (0x06 == dwOpcode) // RLC + { + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY);\n"); + fprintf(fp, " bTemp2 = (bTemp >> 7);\n"); + fprintf(fp, " bTemp = (bTemp << 1) | bTemp2;\n"); + fprintf(fp, " cpu.z80F |= bTemp2 | bPostORFlags[bTemp];\n"); + WriteValueToMemory("dwAddr", "bTemp"); + } + else + if (0x0e == dwOpcode) // RRC + { + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY);\n"); + fprintf(fp, " cpu.z80F |= (bTemp & Z80_FLAG_CARRY);\n"); + fprintf(fp, " bTemp = (bTemp >> 1) | (bTemp << 7);\n"); + fprintf(fp, " cpu.z80F |= bPostORFlags[bTemp];\n"); + WriteValueToMemory("dwAddr", "bTemp"); + } + else + if (0x16 == dwOpcode) // RL + { + fprintf(fp, " bTemp2 = cpu.z80F & Z80_FLAG_CARRY;\n"); + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY);\n"); + fprintf(fp, " cpu.z80F |= (bTemp >> 7);\n"); + fprintf(fp, " bTemp = (bTemp << 1) | bTemp2;\n"); + fprintf(fp, " cpu.z80F |= bPostORFlags[bTemp];\n"); + WriteValueToMemory("dwAddr", "bTemp"); + } + else + if (0x1e == dwOpcode) // RR + { + fprintf(fp, " bTemp2 = (cpu.z80F & Z80_FLAG_CARRY) << 7;\n"); + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY);\n"); + fprintf(fp, " cpu.z80F |= (bTemp & Z80_FLAG_CARRY);\n"); + fprintf(fp, " bTemp = (bTemp >> 1) | bTemp2;\n"); + fprintf(fp, " cpu.z80F |= bPostORFlags[bTemp];\n"); + WriteValueToMemory("dwAddr", "bTemp"); + } + else + if (0x26 == dwOpcode) // SLA + { + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY);\n"); + fprintf(fp, " cpu.z80F |= (bTemp >> 7);\n"); + fprintf(fp, " bTemp = (bTemp << 1);\n"); + fprintf(fp, " cpu.z80F |= bPostORFlags[bTemp];\n"); + WriteValueToMemory("dwAddr", "bTemp"); + } + else + if (0x2e == dwOpcode) // SRA + { + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY);\n"); + fprintf(fp, " cpu.z80F |= (bTemp & Z80_FLAG_CARRY);\n"); + fprintf(fp, " bTemp = (bTemp >> 1) | (bTemp & 0x80);\n"); + fprintf(fp, " cpu.z80F |= bPostORFlags[bTemp];\n"); + WriteValueToMemory("dwAddr", "bTemp"); + } + else + if (0x3e == dwOpcode) // SRL + { + fprintf(fp, " cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY);\n"); + fprintf(fp, " cpu.z80F |= (bTemp & Z80_FLAG_CARRY);\n"); + fprintf(fp, " bTemp = (bTemp >> 1);\n"); + fprintf(fp, " cpu.z80F |= bPostORFlags[bTemp];\n"); + WriteValueToMemory("dwAddr", "bTemp"); + } + else + if ((dwOpcode & 0xc0) == 0x40) // BIT + { + fprintf(fp, " cpu.z80F = (cpu.z80F & ~(Z80_FLAG_ZERO | Z80_FLAG_NEGATIVE)) | Z80_FLAG_HALF_CARRY;\n"); + fprintf(fp, " if (!(bTemp & 0x%.2x))\n", 1 << ((dwOpcode >> 3) & 0x07)); + fprintf(fp, " {\n"); + fprintf(fp, " cpu.z80F |= Z80_FLAG_ZERO;\n"); + fprintf(fp, " }\n"); + } + else + if ((dwOpcode & 0xc0) == 0x80) // RES + { + fprintf(fp, " bTemp &= 0x%.2x;\n", ~(1 << ((dwOpcode >> 3) & 0x07)) & 0xff); + WriteValueToMemory("dwAddr", "bTemp"); + } + else + if ((dwOpcode & 0xc0) == 0xC0) // SET + { + fprintf(fp, " bTemp |= 0x%.2x;\n", 1 << ((dwOpcode >> 3) & 0x07)); + WriteValueToMemory("dwAddr", "bTemp"); + } + else + InvalidInstructionC(4); + } + else + assert(0); +} + +GetTicksCode() +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp, " global _%sGetElapsedTicks\n", cpubasename); + fprintf(fp, " global %sGetElapsedTicks_\n", cpubasename); + fprintf(fp, " global %sGetElapsedTicks\n", cpubasename); + + Alignment(); + sprintf(procname, "%sGetElapsedTicks_", cpubasename); + ProcBegin(0xffffffff); + fprintf(fp, "_%sGetElapsedTicks:\n", cpubasename); + fprintf(fp, "%sGetElapsedTicks:\n", cpubasename); + + if (bUseStack) + fprintf(fp, " mov eax, [esp+4] ; Get our context address\n"); + + fprintf(fp, " or eax, eax ; Should we clear it?\n"); + fprintf(fp, " jz getTicks\n"); + fprintf(fp, " xor eax, eax\n"); + fprintf(fp, " xchg eax, [dwElapsedTicks]\n"); + fprintf(fp, " ret\n"); + fprintf(fp, "getTicks:\n"); + fprintf(fp, " mov eax, [dwElapsedTicks]\n"); + fprintf(fp, " ret\n"); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, "/* This will return the elapsed ticks */\n\n"); + fprintf(fp, "UINT32 %sGetElapsedTicks(UINT32 dwClear)\n", cpubasename); + fprintf(fp, "{\n"); + fprintf(fp, " UINT32 dwTemp = dwElapsedTicks;\n\n"); + fprintf(fp, " if (dwClear)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " dwElapsedTicks = 0;\n"); + fprintf(fp, " }\n\n"); + fprintf(fp, " return(dwTemp);\n"); + fprintf(fp, "}\n\n"); + } + else + { + assert(0); + } +} + +ReleaseTimesliceCode() +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp, " global _%sReleaseTimeslice\n", cpubasename); + fprintf(fp, " global %sReleaseTimeslice_\n", cpubasename); + fprintf(fp, " global %sReleaseTimeslice\n", cpubasename); + + Alignment(); + sprintf(procname, "%sReleaseTimeslice_", cpubasename); + ProcBegin(0xffffffff); + fprintf(fp, "_%sReleaseTimeslice:\n", cpubasename); + fprintf(fp, "%sReleaseTimeslice:\n", cpubasename); + + fprintf(fp, " mov eax, [cyclesRemaining]\n"); + fprintf(fp, " sub [dwOriginalExec], eax\n"); + fprintf(fp, " mov [cyclesRemaining], dword 0\n"); + + fprintf(fp, " ret\n\n"); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, "/* Releases mz80 from its current timeslice */\n\n"); + fprintf(fp, "void %sReleaseTimeslice(void)\n", cpubasename); + fprintf(fp, "{\n"); + fprintf(fp, " dwOriginalCycles -= sdwCyclesRemaining;\n"); + fprintf(fp, " sdwCyclesRemaining = 0;\n"); + fprintf(fp, "}\n\n"); + } + else + { + assert(0); + } +} + +DataSegment() +{ + UINT32 dwLoop = 0; + UINT8 bUsed[256]; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + if (bOS2) + fprintf(fp, " section .DATA32 use32 flat class=data\n"); + else + fprintf(fp, " section .data use32 flat class=data\n"); + + Alignment(); + fprintf(fp, " global _%scontextBegin\n", cpubasename); + fprintf(fp, "_%scontextBegin:\n", cpubasename); + + fprintf(fp, " global _z80pc\n"); + fprintf(fp, " global z80pc_\n"); + + if (bPlain) + fprintf(fp, " global z80pc\n"); + + fprintf(fp, " global _z80nmiAddr\n"); + fprintf(fp, " global _z80intAddr\n"); + fprintf(fp, " global z80intAddr\n"); + + fprintf(fp, "\n"); + fprintf(fp, "; DO NOT CHANGE THE ORDER OF AF, BC, DE, HL and THE PRIME REGISTERS!\n"); + fprintf(fp, "\n"); + fprintf(fp, "_z80Base dd 0 ; Base address for Z80 stuff\n"); + fprintf(fp, "_z80MemRead dd 0 ; Offset of memory read structure array\n"); + fprintf(fp, "_z80MemWrite dd 0 ; Offset of memory write structure array\n"); + fprintf(fp, "_z80IoRead dd 0 ; Base address for I/O reads list\n"); + fprintf(fp, "_z80IoWrite dd 0 ; Base address for I/O write list\n"); + fprintf(fp, "_z80clockticks dd 0 ; # Of clock tips that have elapsed\n"); + fprintf(fp, "_z80iff dd 0 ; Non-zero if we're in an interrupt\n"); + fprintf(fp, "_z80interruptMode dd 0 ; Interrupt mode\n"); + fprintf(fp, "_z80halted dd 0 ; 0=Not halted, 1=Halted\n"); +#ifdef MZ80_TRAP + fprintf(fp, "_z80trapList dd 0 ; pointer to trap list\n"); + fprintf(fp, "_z80trapAddr dw 0 ; PC where trap occurred\n"); +#endif + fprintf(fp, "_z80af dd 0 ; A Flag & Flags\n"); + fprintf(fp, "_z80bc dd 0 ; BC\n"); + fprintf(fp, "_z80de dd 0 ; DE\n"); + fprintf(fp, "_z80hl dd 0 ; HL\n"); + fprintf(fp, "_z80afprime dd 0 ; A Flag & Flags prime\n"); + fprintf(fp, "_z80bcprime dd 0 ; BC prime\n"); + fprintf(fp, "_z80deprime dd 0 ; DE prime\n"); + fprintf(fp, "_z80hlprime dd 0 ; HL prime\n"); + fprintf(fp, "\n"); + fprintf(fp, "; The order of the following registers can be changed without adverse\n"); + fprintf(fp, "; effect. Keep the WORD and DWORDs on boundaries of two for faster access\n"); + fprintf(fp, "\n"); + fprintf(fp, "_z80ix dd 0 ; IX\n"); + fprintf(fp, "_z80iy dd 0 ; IY\n"); + fprintf(fp, "_z80sp dd 0 ; Stack pointer\n"); + + if (bPlain) + fprintf(fp,"z80pc:\n"); + + fprintf(fp, "z80pc_:\n"); + fprintf(fp, "_z80pc dd 0 ; PC\n"); + fprintf(fp, "_z80nmiAddr dd 0 ; Address to jump to for NMI\n"); + fprintf(fp, "z80intAddr:\n"); + fprintf(fp, "_z80intAddr dd 0 ; Address to jump to for INT\n"); + fprintf(fp, "_z80rCounter dd 0 ; R Register counter\n"); + fprintf(fp, "_z80i db 0 ; I register\n"); + fprintf(fp, "_z80r db 0 ; R register\n"); + fprintf(fp, "_z80intPending db 0 ; Non-zero if an interrupt is pending\n"); + fprintf(fp, "\n"); + fprintf(fp, "_%scontextEnd:\n", cpubasename); + Alignment(); + fprintf(fp, "dwElapsedTicks dd 0 ; # Of ticks elapsed\n"); + fprintf(fp, "cyclesRemaining dd 0 ; # Of cycles remaining\n"); + fprintf(fp, "dwOriginalExec dd 0 ; # Of cycles originally executing\n"); + fprintf(fp, "dwLastRSample dd 0 ; Last sample for R computation\n"); + fprintf(fp, "dwEITiming dd 0 ; Used when we cause an interrupt\n"); + fprintf(fp, "_orgval dw 0 ; Scratch area\n"); + fprintf(fp, "_orgval2 dw 0 ; Scratch area\n"); + fprintf(fp, "_wordval dw 0 ; Scratch area\n"); + fprintf(fp, "_intData db 0 ; Interrupt data when an interrupt is pending\n"); + fprintf(fp, "bEIExit db 0 ; Are we exiting because of an EI instruction?\n"); + fprintf(fp, "\n"); + + // Debugger junk + + fprintf(fp, "RegTextPC db 'PC',0\n"); + fprintf(fp, "RegTextAF db 'AF',0\n"); + fprintf(fp, "RegTextBC db 'BC',0\n"); + fprintf(fp, "RegTextDE db 'DE',0\n"); + fprintf(fp, "RegTextHL db 'HL',0\n"); + fprintf(fp, "RegTextAFP db 'AF',27h,0\n"); + fprintf(fp, "RegTextBCP db 'BC',27h,0\n"); + fprintf(fp, "RegTextDEP db 'DE',27h,0\n"); + fprintf(fp, "RegTextHLP db 'HL',27h,0\n"); + fprintf(fp, "RegTextIX db 'IX',0\n"); + fprintf(fp, "RegTextIY db 'IY',0\n"); + fprintf(fp, "RegTextSP db 'SP',0\n"); + fprintf(fp, "RegTextI db 'I',0\n"); + fprintf(fp, "RegTextR db 'R',0\n"); + + // 8 Byte textual info + + fprintf(fp, "RegTextA db 'A',0\n"); + fprintf(fp, "RegTextB db 'B',0\n"); + fprintf(fp, "RegTextC db 'C',0\n"); + fprintf(fp, "RegTextD db 'D',0\n"); + fprintf(fp, "RegTextE db 'E',0\n"); + fprintf(fp, "RegTextH db 'H',0\n"); + fprintf(fp, "RegTextL db 'L',0\n"); + fprintf(fp, "RegTextF db 'F',0\n"); + + // Individual flags + + fprintf(fp, "RegTextCarry db 'Carry',0\n"); + fprintf(fp, "RegTextNegative db 'Negative',0\n"); + fprintf(fp, "RegTextParity db 'Parity',0\n"); + fprintf(fp, "RegTextOverflow db 'Overflow',0\n"); + fprintf(fp, "RegTextHalfCarry db 'HalfCarry',0\n"); + fprintf(fp, "RegTextZero db 'Zero',0\n"); + fprintf(fp, "RegTextSign db 'Sign',0\n"); + fprintf(fp, "RegTextIFF1 db 'IFF1',0\n"); + fprintf(fp, "RegTextIFF2 db 'IFF2',0\n\n"); + + // Timing for interrupt modes + + fprintf(fp, "intModeTStates:\n"); + fprintf(fp, " db 13 ; IM 0 - 13 T-States\n"); + fprintf(fp, " db 11 ; IM 1 - 11 T-States\n"); + fprintf(fp, " db 11 ; IM 2 - 11 T-States\n\n"); + + // Now the master reg/flag table + + fprintf(fp, "\n;\n"); + fprintf(fp, "; Info is in: pointer to text, address, shift value, mask value, size of data chunk\n"); + fprintf(fp, ";\n\n"); + fprintf(fp, "RegTable:\n"); + + // Pointer to text, address, shift value, mask, size + + fprintf(fp, " dd RegTextPC, _z80pc - _%scontextBegin, 0, 0ffffh\n", cpubasename); + fprintf(fp, " dd RegTextSP, _z80sp - _%scontextBegin, 0, 0ffffh\n", cpubasename); + fprintf(fp, " dd RegTextAF, _z80af - _%scontextBegin, 0, 0ffffh\n", cpubasename); + fprintf(fp, " dd RegTextBC, _z80bc - _%scontextBegin, 0, 0ffffh\n", cpubasename); + fprintf(fp, " dd RegTextDE, _z80de - _%scontextBegin, 0, 0ffffh\n", cpubasename); + fprintf(fp, " dd RegTextHL, _z80hl - _%scontextBegin, 0, 0ffffh\n", cpubasename); + fprintf(fp, " dd RegTextAFP, _z80af - _%scontextBegin, 0, 0ffffh\n", cpubasename); + fprintf(fp, " dd RegTextBCP, _z80bc - _%scontextBegin, 0, 0ffffh\n", cpubasename); + fprintf(fp, " dd RegTextDEP, _z80de - _%scontextBegin, 0, 0ffffh\n", cpubasename); + fprintf(fp, " dd RegTextHLP, _z80hl - _%scontextBegin, 0, 0ffffh\n", cpubasename); + fprintf(fp, " dd RegTextIX, _z80ix - _%scontextBegin, 0, 0ffffh\n", cpubasename); + fprintf(fp, " dd RegTextIY, _z80iy - _%scontextBegin, 0, 0ffffh\n", cpubasename); + fprintf(fp, " dd RegTextI, _z80i - _%scontextBegin, 0, 0ffh\n", cpubasename); + fprintf(fp, " dd RegTextR, _z80r - _%scontextBegin, 0, 0ffh\n", cpubasename); + + // Individual regs + + fprintf(fp, " dd RegTextA, (_z80af + 1) - _%scontextBegin, 0, 0ffh\n", cpubasename); + fprintf(fp, " dd RegTextF, _z80af - _%scontextBegin, 0, 0ffh\n", cpubasename); + fprintf(fp, " dd RegTextB, (_z80bc + 1) - _%scontextBegin, 0, 0ffh\n", cpubasename); + fprintf(fp, " dd RegTextC, _z80bc - _%scontextBegin, 0, 0ffh\n", cpubasename); + fprintf(fp, " dd RegTextD, (_z80de + 1) - _%scontextBegin, 0, 0ffh\n", cpubasename); + fprintf(fp, " dd RegTextE, _z80de - _%scontextBegin, 0, 0ffh\n", cpubasename); + fprintf(fp, " dd RegTextH, (_z80hl + 1) - _%scontextBegin, 0, 0ffh\n", cpubasename); + fprintf(fp, " dd RegTextL, _z80hl - _%scontextBegin, 0, 0ffh\n", cpubasename); + + // IFF register + + fprintf(fp, " dd RegTextIFF1, _z80iff - _%scontextBegin, 0, 01h\n", cpubasename); + fprintf(fp, " dd RegTextIFF2, _z80iff - _%scontextBegin, 1, 01h\n", cpubasename); + + // Individual flags + + fprintf(fp, " dd RegTextCarry, _z80af - _%scontextBegin, 0, 01h\n", cpubasename); + fprintf(fp, " dd RegTextNegative, _z80af - _%scontextBegin, 1, 01h\n", cpubasename); + fprintf(fp, " dd RegTextParity, _z80af - _%scontextBegin, 2, 01h\n", cpubasename); + fprintf(fp, " dd RegTextOverflow, _z80af - _%scontextBegin, 2, 01h\n", cpubasename); + fprintf(fp, " dd RegTextHalfCarry, _z80af - _%scontextBegin, 4, 01h\n", cpubasename); + fprintf(fp, " dd RegTextZero, _z80af - _%scontextBegin, 6, 01h\n", cpubasename); + fprintf(fp, " dd RegTextSign, _z80af - _%scontextBegin, 7, 01h\n", cpubasename); + + // Now we write out our tables + + Alignment(); + + for (dwLoop = 0; dwLoop < 256; dwLoop++) + bUsed[dwLoop] = 0; + + // Now rip through and find out what is and isn't used + + dwLoop = 0; + + while (StandardOps[dwLoop].Emitter) + { + assert(StandardOps[dwLoop].bOpCode < 0x100); + if (bUsed[StandardOps[dwLoop].bOpCode]) + { + fprintf(stderr, "Oops! %.2x\n", dwLoop); + fclose(fp); + exit(1); + } + bUsed[StandardOps[dwLoop].bOpCode] = 1; + dwLoop++; + } + + // Now that that's taken care of, emit the table + + fprintf(fp, "z80regular:\n"); + + dwLoop = 0; + + while (dwLoop < 0x100) + { + fprintf(fp, " dd "); + if (bUsed[dwLoop]) + fprintf(fp, "RegInst%.2x", dwLoop); + else + fprintf(fp, "invalidInsByte"); + fprintf(fp, "\n"); + dwLoop++; + } + fprintf(fp, "\n"); + + // Now rip through and find out what is and isn't used (CB Ops) + + for (dwLoop = 0; dwLoop < 0x100; dwLoop++) + bUsed[dwLoop] = 0; + + dwLoop = 0; + + while (CBOps[dwLoop].Emitter) + { + assert(CBOps[dwLoop].bOpCode < 0x100); + if (bUsed[CBOps[dwLoop].bOpCode]) + { + fprintf(stderr, "Oops CB! %.2x\n", dwLoop); + fclose(fp); + exit(1); + } + bUsed[CBOps[dwLoop].bOpCode] = 1; + dwLoop++; + } + + dwLoop = 0; + + // Let's emit the CB prefixes + + fprintf(fp, "z80PrefixCB:\n"); + + while (dwLoop < 0x100) + { + fprintf(fp, " dd "); + if (bUsed[dwLoop]) + fprintf(fp, "CBInst%.2x", dwLoop); + else + fprintf(fp, "invalidInsWord"); + fprintf(fp, "\n"); + dwLoop++; + } + fprintf(fp, "\n"); + + // Now rip through and find out what is and isn't used (ED Ops) + + for (dwLoop = 0; dwLoop < 0x100; dwLoop++) + bUsed[dwLoop] = 0; + + dwLoop = 0; + + while (EDOps[dwLoop].Emitter) + { + assert(EDOps[dwLoop].bOpCode < 0x100); + if (bUsed[EDOps[dwLoop].bOpCode]) + { + fprintf(stderr, "Oops ED! %.2x\n", dwLoop); + fclose(fp); + exit(1); + } + bUsed[EDOps[dwLoop].bOpCode] = 1; + dwLoop++; + } + + dwLoop = 0; + + // Let's emit the ED prefixes + + fprintf(fp, "z80PrefixED:\n"); + + while (dwLoop < 0x100) + { + fprintf(fp, " dd "); + if (bUsed[dwLoop]) + fprintf(fp, "EDInst%.2x", dwLoop); + else + fprintf(fp, "invalidInsWord"); + fprintf(fp, "\n"); + dwLoop++; + } + fprintf(fp, "\n"); + + // Now rip through and find out what is and isn't used (DD Ops) + + for (dwLoop = 0; dwLoop < 0x100; dwLoop++) + bUsed[dwLoop] = 0; + + dwLoop = 0; + + while (DDFDOps[dwLoop].Emitter) + { + assert(DDFDOps[dwLoop].bOpCode < 0x100); + if (bUsed[DDFDOps[dwLoop].bOpCode]) + { + fprintf(stderr, "Oops DD! %.2x\n", bUsed[DDFDOps[dwLoop].bOpCode]); + fclose(fp); + exit(1); + } + bUsed[DDFDOps[dwLoop].bOpCode] = 1; + dwLoop++; + } + + dwLoop = 0; + + // Let's emit the DD prefixes + + fprintf(fp, "z80PrefixDD:\n"); + + while (dwLoop < 0x100) + { + fprintf(fp, " dd "); + if (bUsed[dwLoop]) + fprintf(fp, "DDInst%.2x", dwLoop); + else + fprintf(fp, "invalidInsWord"); + fprintf(fp, "\n"); + dwLoop++; + } + fprintf(fp, "\n"); + + // Now rip through and find out what is and isn't used (FD Ops) + + for (dwLoop = 0; dwLoop < 0x100; dwLoop++) + bUsed[dwLoop] = 0; + + dwLoop = 0; + + while (DDFDOps[dwLoop].Emitter) + { + assert(DDFDOps[dwLoop].bOpCode < 0x100); + if (bUsed[DDFDOps[dwLoop].bOpCode]) + { + fprintf(stderr, "Oops FD! %.2x\n", dwLoop); + fclose(fp); + exit(1); + } + bUsed[DDFDOps[dwLoop].bOpCode] = 1; + dwLoop++; + } + + for (dwLoop = 0; dwLoop < 0x100; dwLoop++) + bUsed[dwLoop] = 0; + + // Let's emit the DDFD prefixes + + for (dwLoop = 0; dwLoop < 0x100; dwLoop++) + bUsed[dwLoop] = 0; + + dwLoop = 0; + + while (DDFDOps[dwLoop].Emitter) + { + assert(DDFDOps[dwLoop].bOpCode < 0x100); + if (bUsed[DDFDOps[dwLoop].bOpCode]) + { + fprintf(stderr, "Oops FD! %.2x\n", dwLoop); + exit(1); + } + bUsed[DDFDOps[dwLoop].bOpCode] = 1; + dwLoop++; + } + + dwLoop = 0; + + // Let's emit the DDFD prefixes + + fprintf(fp, "z80PrefixFD:\n"); + + while (dwLoop < 0x100) + { + fprintf(fp, " dd "); + if (bUsed[dwLoop]) + fprintf(fp, "FDInst%.2x", dwLoop); + else + fprintf(fp, "invalidInsWord"); + fprintf(fp, "\n"); + dwLoop++; + } + + for (dwLoop = 0; dwLoop < 0x100; dwLoop++) + bUsed[dwLoop] = 0; + + dwLoop = 0; + + while (DDFDCBOps[dwLoop].Emitter) + { + assert(DDFDCBOps[dwLoop].bOpCode < 0x100); + if (bUsed[DDFDCBOps[dwLoop].bOpCode]) + { + fprintf(stderr, "Oops CBFDDD! %.2x\n", bUsed[DDFDCBOps[dwLoop].bOpCode]); + fclose(fp); + exit(1); + } + bUsed[DDFDCBOps[dwLoop].bOpCode] = 1; + dwLoop++; + } + + // Let's emit the DDFD prefixes + + dwLoop = 0; + + fprintf(fp, "z80ddfdcbInstructions:\n"); + + while (dwLoop < 0x100) + { + fprintf(fp, " dd "); + if (bUsed[dwLoop]) + fprintf(fp, "DDFDCBInst%.2x", dwLoop); + else + fprintf(fp, "invalidInsWord"); + fprintf(fp, "\n"); + dwLoop++; + } + fprintf(fp, "\n"); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, "/* Modular global variables go here*/\n\n"); + fprintf(fp, "static CONTEXTMZ80 cpu; /* CPU Context */\n"); + fprintf(fp, "static UINT8 *pbPC; /* Program counter normalized */\n"); + fprintf(fp, "static UINT8 *pbSP; /* Stack pointer normalized */\n"); + fprintf(fp, "static struct MemoryReadByte *psMemRead; /* Read memory structure */\n"); + fprintf(fp, "static struct MemoryWriteByte *psMemWrite; /* Write memory structure */\n"); + fprintf(fp, "static struct z80PortRead *psIoRead; /* Read I/O structure */\n"); + fprintf(fp, "static struct z80PortWrite *psIoWrite; /* Write memory structure */\n"); + fprintf(fp, "static INT32 sdwCyclesRemaining; /* Used as a countdown */\n"); + fprintf(fp, "static UINT32 dwReturnCode; /* Return code from exec() */\n"); + fprintf(fp, "static UINT32 dwOriginalCycles; /* How many cycles did we start with? */\n"); + fprintf(fp, "static UINT32 dwElapsedTicks; /* How many ticks did we elapse? */\n"); + fprintf(fp, "static INT32 sdwAddr; /* Temporary address storage */\n"); + fprintf(fp, "static UINT32 dwAddr; /* Temporary stack address */\n"); + fprintf(fp, "static UINT8 *pbAddAdcTable; /* Pointer to add/adc flag table */\n"); + fprintf(fp, "static UINT8 *pbSubSbcTable; /* Pointer to sub/sbc flag table */\n"); + fprintf(fp, "static UINT32 dwTemp; /* Temporary value */\n\n"); + fprintf(fp, "static UINT8 bTemp; /* Temporary value */\n\n"); + fprintf(fp, "static UINT8 bTemp2; /* Temporary value */\n\n"); + + fprintf(fp, "/* Precomputed flag tables */\n\n"); + + fprintf(fp, "static UINT8 bPostIncFlags[0x100] = \n"); + fprintf(fp, "{\n"); + fprintf(fp, " 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,\n"); + fprintf(fp, " 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,\n"); + fprintf(fp, " 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,\n"); + fprintf(fp, " 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,\n"); + fprintf(fp, " 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,\n"); + fprintf(fp, " 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,\n"); + fprintf(fp, " 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,\n"); + fprintf(fp, " 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,\n"); + fprintf(fp, " 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x90,\n"); + fprintf(fp, " 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x90,\n"); + fprintf(fp, " 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x90,\n"); + fprintf(fp, " 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x90,\n"); + fprintf(fp, " 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x90,\n"); + fprintf(fp, " 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x90,\n"); + fprintf(fp, " 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x90,\n"); + fprintf(fp, " 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x50\n"); + fprintf(fp, "};\n\n"); + + fprintf(fp, "static UINT8 bPostDecFlags[0x100] = \n"); + fprintf(fp, "{\n"); + fprintf(fp, " 0x92,0x42,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,\n"); + fprintf(fp, " 0x12,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,\n"); + fprintf(fp, " 0x12,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,\n"); + fprintf(fp, " 0x12,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,\n"); + fprintf(fp, " 0x12,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,\n"); + fprintf(fp, " 0x12,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,\n"); + fprintf(fp, " 0x12,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,\n"); + fprintf(fp, " 0x12,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,\n"); + fprintf(fp, " 0x16,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,\n"); + fprintf(fp, " 0x92,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,\n"); + fprintf(fp, " 0x92,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,\n"); + fprintf(fp, " 0x92,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,\n"); + fprintf(fp, " 0x92,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,\n"); + fprintf(fp, " 0x92,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,\n"); + fprintf(fp, " 0x92,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,\n"); + fprintf(fp, " 0x92,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82\n"); + fprintf(fp, "};\n\n"); + + fprintf(fp, "static UINT8 bPostORFlags[0x100] = \n"); + fprintf(fp, "{\n"); + fprintf(fp, " 0x44,0x00,0x00,0x04,0x00,0x04,0x04,0x00,0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04,\n"); + fprintf(fp, " 0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04,0x04,0x00,0x00,0x04,0x00,0x04,0x04,0x00,\n"); + fprintf(fp, " 0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04,0x04,0x00,0x00,0x04,0x00,0x04,0x04,0x00,\n"); + fprintf(fp, " 0x04,0x00,0x00,0x04,0x00,0x04,0x04,0x00,0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04,\n"); + fprintf(fp, " 0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04,0x04,0x00,0x00,0x04,0x00,0x04,0x04,0x00,\n"); + fprintf(fp, " 0x04,0x00,0x00,0x04,0x00,0x04,0x04,0x00,0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04,\n"); + fprintf(fp, " 0x04,0x00,0x00,0x04,0x00,0x04,0x04,0x00,0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04,\n"); + fprintf(fp, " 0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04,0x04,0x00,0x00,0x04,0x00,0x04,0x04,0x00,\n"); + fprintf(fp, " 0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84,0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80,\n"); + fprintf(fp, " 0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80,0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84,\n"); + fprintf(fp, " 0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80,0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84,\n"); + fprintf(fp, " 0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84,0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80,\n"); + fprintf(fp, " 0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80,0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84,\n"); + fprintf(fp, " 0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84,0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80,\n"); + fprintf(fp, " 0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84,0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80,\n"); + fprintf(fp, " 0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80,0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84\n"); + fprintf(fp, "};\n\n"); + + fprintf(fp, "static UINT8 bPostANDFlags[0x100] = \n"); + fprintf(fp, "{\n"); + fprintf(fp, " 0x54,0x10,0x10,0x14,0x10,0x14,0x14,0x10,0x10,0x14,0x14,0x10,0x14,0x10,0x10,0x14,\n"); + fprintf(fp, " 0x10,0x14,0x14,0x10,0x14,0x10,0x10,0x14,0x14,0x10,0x10,0x14,0x10,0x14,0x14,0x10,\n"); + fprintf(fp, " 0x10,0x14,0x14,0x10,0x14,0x10,0x10,0x14,0x14,0x10,0x10,0x14,0x10,0x14,0x14,0x10,\n"); + fprintf(fp, " 0x14,0x10,0x10,0x14,0x10,0x14,0x14,0x10,0x10,0x14,0x14,0x10,0x14,0x10,0x10,0x14,\n"); + fprintf(fp, " 0x10,0x14,0x14,0x10,0x14,0x10,0x10,0x14,0x14,0x10,0x10,0x14,0x10,0x14,0x14,0x10,\n"); + fprintf(fp, " 0x14,0x10,0x10,0x14,0x10,0x14,0x14,0x10,0x10,0x14,0x14,0x10,0x14,0x10,0x10,0x14,\n"); + fprintf(fp, " 0x14,0x10,0x10,0x14,0x10,0x14,0x14,0x10,0x10,0x14,0x14,0x10,0x14,0x10,0x10,0x14,\n"); + fprintf(fp, " 0x10,0x14,0x14,0x10,0x14,0x10,0x10,0x14,0x14,0x10,0x10,0x14,0x10,0x14,0x14,0x10,\n"); + fprintf(fp, " 0x90,0x94,0x94,0x90,0x94,0x90,0x90,0x94,0x94,0x90,0x90,0x94,0x90,0x94,0x94,0x90,\n"); + fprintf(fp, " 0x94,0x90,0x90,0x94,0x90,0x94,0x94,0x90,0x90,0x94,0x94,0x90,0x94,0x90,0x90,0x94,\n"); + fprintf(fp, " 0x94,0x90,0x90,0x94,0x90,0x94,0x94,0x90,0x90,0x94,0x94,0x90,0x94,0x90,0x90,0x94,\n"); + fprintf(fp, " 0x90,0x94,0x94,0x90,0x94,0x90,0x90,0x94,0x94,0x90,0x90,0x94,0x90,0x94,0x94,0x90,\n"); + fprintf(fp, " 0x94,0x90,0x90,0x94,0x90,0x94,0x94,0x90,0x90,0x94,0x94,0x90,0x94,0x90,0x90,0x94,\n"); + fprintf(fp, " 0x90,0x94,0x94,0x90,0x94,0x90,0x90,0x94,0x94,0x90,0x90,0x94,0x90,0x94,0x94,0x90,\n"); + fprintf(fp, " 0x90,0x94,0x94,0x90,0x94,0x90,0x90,0x94,0x94,0x90,0x90,0x94,0x90,0x94,0x94,0x90,\n"); + fprintf(fp, " 0x94,0x90,0x90,0x94,0x90,0x94,0x94,0x90,0x90,0x94,0x94,0x90,0x94,0x90,0x90,0x94\n"); + fprintf(fp, "};\n\n"); + + fprintf(fp, "static UINT16 wDAATable[0x800] = \n"); + fprintf(fp, "{\n"); + fprintf(fp, " 0x5400,0x1001,0x1002,0x1403,0x1004,0x1405,0x1406,0x1007,\n"); + fprintf(fp, " 0x1008,0x1409,0x1010,0x1411,0x1412,0x1013,0x1414,0x1015,\n"); + fprintf(fp, " 0x1010,0x1411,0x1412,0x1013,0x1414,0x1015,0x1016,0x1417,\n"); + fprintf(fp, " 0x1418,0x1019,0x1020,0x1421,0x1422,0x1023,0x1424,0x1025,\n"); + fprintf(fp, " 0x1020,0x1421,0x1422,0x1023,0x1424,0x1025,0x1026,0x1427,\n"); + fprintf(fp, " 0x1428,0x1029,0x1430,0x1031,0x1032,0x1433,0x1034,0x1435,\n"); + fprintf(fp, " 0x1430,0x1031,0x1032,0x1433,0x1034,0x1435,0x1436,0x1037,\n"); + fprintf(fp, " 0x1038,0x1439,0x1040,0x1441,0x1442,0x1043,0x1444,0x1045,\n"); + fprintf(fp, " 0x1040,0x1441,0x1442,0x1043,0x1444,0x1045,0x1046,0x1447,\n"); + fprintf(fp, " 0x1448,0x1049,0x1450,0x1051,0x1052,0x1453,0x1054,0x1455,\n"); + fprintf(fp, " 0x1450,0x1051,0x1052,0x1453,0x1054,0x1455,0x1456,0x1057,\n"); + fprintf(fp, " 0x1058,0x1459,0x1460,0x1061,0x1062,0x1463,0x1064,0x1465,\n"); + fprintf(fp, " 0x1460,0x1061,0x1062,0x1463,0x1064,0x1465,0x1466,0x1067,\n"); + fprintf(fp, " 0x1068,0x1469,0x1070,0x1471,0x1472,0x1073,0x1474,0x1075,\n"); + fprintf(fp, " 0x1070,0x1471,0x1472,0x1073,0x1474,0x1075,0x1076,0x1477,\n"); + fprintf(fp, " 0x1478,0x1079,0x9080,0x9481,0x9482,0x9083,0x9484,0x9085,\n"); + fprintf(fp, " 0x9080,0x9481,0x9482,0x9083,0x9484,0x9085,0x9086,0x9487,\n"); + fprintf(fp, " 0x9488,0x9089,0x9490,0x9091,0x9092,0x9493,0x9094,0x9495,\n"); + fprintf(fp, " 0x9490,0x9091,0x9092,0x9493,0x9094,0x9495,0x9496,0x9097,\n"); + fprintf(fp, " 0x9098,0x9499,0x5500,0x1101,0x1102,0x1503,0x1104,0x1505,\n"); + fprintf(fp, " 0x5500,0x1101,0x1102,0x1503,0x1104,0x1505,0x1506,0x1107,\n"); + fprintf(fp, " 0x1108,0x1509,0x1110,0x1511,0x1512,0x1113,0x1514,0x1115,\n"); + fprintf(fp, " 0x1110,0x1511,0x1512,0x1113,0x1514,0x1115,0x1116,0x1517,\n"); + fprintf(fp, " 0x1518,0x1119,0x1120,0x1521,0x1522,0x1123,0x1524,0x1125,\n"); + fprintf(fp, " 0x1120,0x1521,0x1522,0x1123,0x1524,0x1125,0x1126,0x1527,\n"); + fprintf(fp, " 0x1528,0x1129,0x1530,0x1131,0x1132,0x1533,0x1134,0x1535,\n"); + fprintf(fp, " 0x1530,0x1131,0x1132,0x1533,0x1134,0x1535,0x1536,0x1137,\n"); + fprintf(fp, " 0x1138,0x1539,0x1140,0x1541,0x1542,0x1143,0x1544,0x1145,\n"); + fprintf(fp, " 0x1140,0x1541,0x1542,0x1143,0x1544,0x1145,0x1146,0x1547,\n"); + fprintf(fp, " 0x1548,0x1149,0x1550,0x1151,0x1152,0x1553,0x1154,0x1555,\n"); + fprintf(fp, " 0x1550,0x1151,0x1152,0x1553,0x1154,0x1555,0x1556,0x1157,\n"); + fprintf(fp, " 0x1158,0x1559,0x1560,0x1161,0x1162,0x1563,0x1164,0x1565,\n"); + fprintf(fp, " 0x1560,0x1161,0x1162,0x1563,0x1164,0x1565,0x1566,0x1167,\n"); + fprintf(fp, " 0x1168,0x1569,0x1170,0x1571,0x1572,0x1173,0x1574,0x1175,\n"); + fprintf(fp, " 0x1170,0x1571,0x1572,0x1173,0x1574,0x1175,0x1176,0x1577,\n"); + fprintf(fp, " 0x1578,0x1179,0x9180,0x9581,0x9582,0x9183,0x9584,0x9185,\n"); + fprintf(fp, " 0x9180,0x9581,0x9582,0x9183,0x9584,0x9185,0x9186,0x9587,\n"); + fprintf(fp, " 0x9588,0x9189,0x9590,0x9191,0x9192,0x9593,0x9194,0x9595,\n"); + fprintf(fp, " 0x9590,0x9191,0x9192,0x9593,0x9194,0x9595,0x9596,0x9197,\n"); + fprintf(fp, " 0x9198,0x9599,0x95a0,0x91a1,0x91a2,0x95a3,0x91a4,0x95a5,\n"); + fprintf(fp, " 0x95a0,0x91a1,0x91a2,0x95a3,0x91a4,0x95a5,0x95a6,0x91a7,\n"); + fprintf(fp, " 0x91a8,0x95a9,0x91b0,0x95b1,0x95b2,0x91b3,0x95b4,0x91b5,\n"); + fprintf(fp, " 0x91b0,0x95b1,0x95b2,0x91b3,0x95b4,0x91b5,0x91b6,0x95b7,\n"); + fprintf(fp, " 0x95b8,0x91b9,0x95c0,0x91c1,0x91c2,0x95c3,0x91c4,0x95c5,\n"); + fprintf(fp, " 0x95c0,0x91c1,0x91c2,0x95c3,0x91c4,0x95c5,0x95c6,0x91c7,\n"); + fprintf(fp, " 0x91c8,0x95c9,0x91d0,0x95d1,0x95d2,0x91d3,0x95d4,0x91d5,\n"); + fprintf(fp, " 0x91d0,0x95d1,0x95d2,0x91d3,0x95d4,0x91d5,0x91d6,0x95d7,\n"); + fprintf(fp, " 0x95d8,0x91d9,0x91e0,0x95e1,0x95e2,0x91e3,0x95e4,0x91e5,\n"); + fprintf(fp, " 0x91e0,0x95e1,0x95e2,0x91e3,0x95e4,0x91e5,0x91e6,0x95e7,\n"); + fprintf(fp, " 0x95e8,0x91e9,0x95f0,0x91f1,0x91f2,0x95f3,0x91f4,0x95f5,\n"); + fprintf(fp, " 0x95f0,0x91f1,0x91f2,0x95f3,0x91f4,0x95f5,0x95f6,0x91f7,\n"); + fprintf(fp, " 0x91f8,0x95f9,0x5500,0x1101,0x1102,0x1503,0x1104,0x1505,\n"); + fprintf(fp, " 0x5500,0x1101,0x1102,0x1503,0x1104,0x1505,0x1506,0x1107,\n"); + fprintf(fp, " 0x1108,0x1509,0x1110,0x1511,0x1512,0x1113,0x1514,0x1115,\n"); + fprintf(fp, " 0x1110,0x1511,0x1512,0x1113,0x1514,0x1115,0x1116,0x1517,\n"); + fprintf(fp, " 0x1518,0x1119,0x1120,0x1521,0x1522,0x1123,0x1524,0x1125,\n"); + fprintf(fp, " 0x1120,0x1521,0x1522,0x1123,0x1524,0x1125,0x1126,0x1527,\n"); + fprintf(fp, " 0x1528,0x1129,0x1530,0x1131,0x1132,0x1533,0x1134,0x1535,\n"); + fprintf(fp, " 0x1530,0x1131,0x1132,0x1533,0x1134,0x1535,0x1536,0x1137,\n"); + fprintf(fp, " 0x1138,0x1539,0x1140,0x1541,0x1542,0x1143,0x1544,0x1145,\n"); + fprintf(fp, " 0x1140,0x1541,0x1542,0x1143,0x1544,0x1145,0x1146,0x1547,\n"); + fprintf(fp, " 0x1548,0x1149,0x1550,0x1151,0x1152,0x1553,0x1154,0x1555,\n"); + fprintf(fp, " 0x1550,0x1151,0x1152,0x1553,0x1154,0x1555,0x1556,0x1157,\n"); + fprintf(fp, " 0x1158,0x1559,0x1560,0x1161,0x1162,0x1563,0x1164,0x1565,\n"); + fprintf(fp, " 0x1406,0x1007,0x1008,0x1409,0x140a,0x100b,0x140c,0x100d,\n"); + fprintf(fp, " 0x100e,0x140f,0x1010,0x1411,0x1412,0x1013,0x1414,0x1015,\n"); + fprintf(fp, " 0x1016,0x1417,0x1418,0x1019,0x101a,0x141b,0x101c,0x141d,\n"); + fprintf(fp, " 0x141e,0x101f,0x1020,0x1421,0x1422,0x1023,0x1424,0x1025,\n"); + fprintf(fp, " 0x1026,0x1427,0x1428,0x1029,0x102a,0x142b,0x102c,0x142d,\n"); + fprintf(fp, " 0x142e,0x102f,0x1430,0x1031,0x1032,0x1433,0x1034,0x1435,\n"); + fprintf(fp, " 0x1436,0x1037,0x1038,0x1439,0x143a,0x103b,0x143c,0x103d,\n"); + fprintf(fp, " 0x103e,0x143f,0x1040,0x1441,0x1442,0x1043,0x1444,0x1045,\n"); + fprintf(fp, " 0x1046,0x1447,0x1448,0x1049,0x104a,0x144b,0x104c,0x144d,\n"); + fprintf(fp, " 0x144e,0x104f,0x1450,0x1051,0x1052,0x1453,0x1054,0x1455,\n"); + fprintf(fp, " 0x1456,0x1057,0x1058,0x1459,0x145a,0x105b,0x145c,0x105d,\n"); + fprintf(fp, " 0x105e,0x145f,0x1460,0x1061,0x1062,0x1463,0x1064,0x1465,\n"); + fprintf(fp, " 0x1466,0x1067,0x1068,0x1469,0x146a,0x106b,0x146c,0x106d,\n"); + fprintf(fp, " 0x106e,0x146f,0x1070,0x1471,0x1472,0x1073,0x1474,0x1075,\n"); + fprintf(fp, " 0x1076,0x1477,0x1478,0x1079,0x107a,0x147b,0x107c,0x147d,\n"); + fprintf(fp, " 0x147e,0x107f,0x9080,0x9481,0x9482,0x9083,0x9484,0x9085,\n"); + fprintf(fp, " 0x9086,0x9487,0x9488,0x9089,0x908a,0x948b,0x908c,0x948d,\n"); + fprintf(fp, " 0x948e,0x908f,0x9490,0x9091,0x9092,0x9493,0x9094,0x9495,\n"); + fprintf(fp, " 0x9496,0x9097,0x9098,0x9499,0x949a,0x909b,0x949c,0x909d,\n"); + fprintf(fp, " 0x909e,0x949f,0x5500,0x1101,0x1102,0x1503,0x1104,0x1505,\n"); + fprintf(fp, " 0x1506,0x1107,0x1108,0x1509,0x150a,0x110b,0x150c,0x110d,\n"); + fprintf(fp, " 0x110e,0x150f,0x1110,0x1511,0x1512,0x1113,0x1514,0x1115,\n"); + fprintf(fp, " 0x1116,0x1517,0x1518,0x1119,0x111a,0x151b,0x111c,0x151d,\n"); + fprintf(fp, " 0x151e,0x111f,0x1120,0x1521,0x1522,0x1123,0x1524,0x1125,\n"); + fprintf(fp, " 0x1126,0x1527,0x1528,0x1129,0x112a,0x152b,0x112c,0x152d,\n"); + fprintf(fp, " 0x152e,0x112f,0x1530,0x1131,0x1132,0x1533,0x1134,0x1535,\n"); + fprintf(fp, " 0x1536,0x1137,0x1138,0x1539,0x153a,0x113b,0x153c,0x113d,\n"); + fprintf(fp, " 0x113e,0x153f,0x1140,0x1541,0x1542,0x1143,0x1544,0x1145,\n"); + fprintf(fp, " 0x1146,0x1547,0x1548,0x1149,0x114a,0x154b,0x114c,0x154d,\n"); + fprintf(fp, " 0x154e,0x114f,0x1550,0x1151,0x1152,0x1553,0x1154,0x1555,\n"); + fprintf(fp, " 0x1556,0x1157,0x1158,0x1559,0x155a,0x115b,0x155c,0x115d,\n"); + fprintf(fp, " 0x115e,0x155f,0x1560,0x1161,0x1162,0x1563,0x1164,0x1565,\n"); + fprintf(fp, " 0x1566,0x1167,0x1168,0x1569,0x156a,0x116b,0x156c,0x116d,\n"); + fprintf(fp, " 0x116e,0x156f,0x1170,0x1571,0x1572,0x1173,0x1574,0x1175,\n"); + fprintf(fp, " 0x1176,0x1577,0x1578,0x1179,0x117a,0x157b,0x117c,0x157d,\n"); + fprintf(fp, " 0x157e,0x117f,0x9180,0x9581,0x9582,0x9183,0x9584,0x9185,\n"); + fprintf(fp, " 0x9186,0x9587,0x9588,0x9189,0x918a,0x958b,0x918c,0x958d,\n"); + fprintf(fp, " 0x958e,0x918f,0x9590,0x9191,0x9192,0x9593,0x9194,0x9595,\n"); + fprintf(fp, " 0x9596,0x9197,0x9198,0x9599,0x959a,0x919b,0x959c,0x919d,\n"); + fprintf(fp, " 0x919e,0x959f,0x95a0,0x91a1,0x91a2,0x95a3,0x91a4,0x95a5,\n"); + fprintf(fp, " 0x95a6,0x91a7,0x91a8,0x95a9,0x95aa,0x91ab,0x95ac,0x91ad,\n"); + fprintf(fp, " 0x91ae,0x95af,0x91b0,0x95b1,0x95b2,0x91b3,0x95b4,0x91b5,\n"); + fprintf(fp, " 0x91b6,0x95b7,0x95b8,0x91b9,0x91ba,0x95bb,0x91bc,0x95bd,\n"); + fprintf(fp, " 0x95be,0x91bf,0x95c0,0x91c1,0x91c2,0x95c3,0x91c4,0x95c5,\n"); + fprintf(fp, " 0x95c6,0x91c7,0x91c8,0x95c9,0x95ca,0x91cb,0x95cc,0x91cd,\n"); + fprintf(fp, " 0x91ce,0x95cf,0x91d0,0x95d1,0x95d2,0x91d3,0x95d4,0x91d5,\n"); + fprintf(fp, " 0x91d6,0x95d7,0x95d8,0x91d9,0x91da,0x95db,0x91dc,0x95dd,\n"); + fprintf(fp, " 0x95de,0x91df,0x91e0,0x95e1,0x95e2,0x91e3,0x95e4,0x91e5,\n"); + fprintf(fp, " 0x91e6,0x95e7,0x95e8,0x91e9,0x91ea,0x95eb,0x91ec,0x95ed,\n"); + fprintf(fp, " 0x95ee,0x91ef,0x95f0,0x91f1,0x91f2,0x95f3,0x91f4,0x95f5,\n"); + fprintf(fp, " 0x95f6,0x91f7,0x91f8,0x95f9,0x95fa,0x91fb,0x95fc,0x91fd,\n"); + fprintf(fp, " 0x91fe,0x95ff,0x5500,0x1101,0x1102,0x1503,0x1104,0x1505,\n"); + fprintf(fp, " 0x1506,0x1107,0x1108,0x1509,0x150a,0x110b,0x150c,0x110d,\n"); + fprintf(fp, " 0x110e,0x150f,0x1110,0x1511,0x1512,0x1113,0x1514,0x1115,\n"); + fprintf(fp, " 0x1116,0x1517,0x1518,0x1119,0x111a,0x151b,0x111c,0x151d,\n"); + fprintf(fp, " 0x151e,0x111f,0x1120,0x1521,0x1522,0x1123,0x1524,0x1125,\n"); + fprintf(fp, " 0x1126,0x1527,0x1528,0x1129,0x112a,0x152b,0x112c,0x152d,\n"); + fprintf(fp, " 0x152e,0x112f,0x1530,0x1131,0x1132,0x1533,0x1134,0x1535,\n"); + fprintf(fp, " 0x1536,0x1137,0x1138,0x1539,0x153a,0x113b,0x153c,0x113d,\n"); + fprintf(fp, " 0x113e,0x153f,0x1140,0x1541,0x1542,0x1143,0x1544,0x1145,\n"); + fprintf(fp, " 0x1146,0x1547,0x1548,0x1149,0x114a,0x154b,0x114c,0x154d,\n"); + fprintf(fp, " 0x154e,0x114f,0x1550,0x1151,0x1152,0x1553,0x1154,0x1555,\n"); + fprintf(fp, " 0x1556,0x1157,0x1158,0x1559,0x155a,0x115b,0x155c,0x115d,\n"); + fprintf(fp, " 0x115e,0x155f,0x1560,0x1161,0x1162,0x1563,0x1164,0x1565,\n"); + fprintf(fp, " 0x5600,0x1201,0x1202,0x1603,0x1204,0x1605,0x1606,0x1207,\n"); + fprintf(fp, " 0x1208,0x1609,0x1204,0x1605,0x1606,0x1207,0x1208,0x1609,\n"); + fprintf(fp, " 0x1210,0x1611,0x1612,0x1213,0x1614,0x1215,0x1216,0x1617,\n"); + fprintf(fp, " 0x1618,0x1219,0x1614,0x1215,0x1216,0x1617,0x1618,0x1219,\n"); + fprintf(fp, " 0x1220,0x1621,0x1622,0x1223,0x1624,0x1225,0x1226,0x1627,\n"); + fprintf(fp, " 0x1628,0x1229,0x1624,0x1225,0x1226,0x1627,0x1628,0x1229,\n"); + fprintf(fp, " 0x1630,0x1231,0x1232,0x1633,0x1234,0x1635,0x1636,0x1237,\n"); + fprintf(fp, " 0x1238,0x1639,0x1234,0x1635,0x1636,0x1237,0x1238,0x1639,\n"); + fprintf(fp, " 0x1240,0x1641,0x1642,0x1243,0x1644,0x1245,0x1246,0x1647,\n"); + fprintf(fp, " 0x1648,0x1249,0x1644,0x1245,0x1246,0x1647,0x1648,0x1249,\n"); + fprintf(fp, " 0x1650,0x1251,0x1252,0x1653,0x1254,0x1655,0x1656,0x1257,\n"); + fprintf(fp, " 0x1258,0x1659,0x1254,0x1655,0x1656,0x1257,0x1258,0x1659,\n"); + fprintf(fp, " 0x1660,0x1261,0x1262,0x1663,0x1264,0x1665,0x1666,0x1267,\n"); + fprintf(fp, " 0x1268,0x1669,0x1264,0x1665,0x1666,0x1267,0x1268,0x1669,\n"); + fprintf(fp, " 0x1270,0x1671,0x1672,0x1273,0x1674,0x1275,0x1276,0x1677,\n"); + fprintf(fp, " 0x1678,0x1279,0x1674,0x1275,0x1276,0x1677,0x1678,0x1279,\n"); + fprintf(fp, " 0x9280,0x9681,0x9682,0x9283,0x9684,0x9285,0x9286,0x9687,\n"); + fprintf(fp, " 0x9688,0x9289,0x9684,0x9285,0x9286,0x9687,0x9688,0x9289,\n"); + fprintf(fp, " 0x9690,0x9291,0x9292,0x9693,0x9294,0x9695,0x9696,0x9297,\n"); + fprintf(fp, " 0x9298,0x9699,0x1334,0x1735,0x1736,0x1337,0x1338,0x1739,\n"); + fprintf(fp, " 0x1340,0x1741,0x1742,0x1343,0x1744,0x1345,0x1346,0x1747,\n"); + fprintf(fp, " 0x1748,0x1349,0x1744,0x1345,0x1346,0x1747,0x1748,0x1349,\n"); + fprintf(fp, " 0x1750,0x1351,0x1352,0x1753,0x1354,0x1755,0x1756,0x1357,\n"); + fprintf(fp, " 0x1358,0x1759,0x1354,0x1755,0x1756,0x1357,0x1358,0x1759,\n"); + fprintf(fp, " 0x1760,0x1361,0x1362,0x1763,0x1364,0x1765,0x1766,0x1367,\n"); + fprintf(fp, " 0x1368,0x1769,0x1364,0x1765,0x1766,0x1367,0x1368,0x1769,\n"); + fprintf(fp, " 0x1370,0x1771,0x1772,0x1373,0x1774,0x1375,0x1376,0x1777,\n"); + fprintf(fp, " 0x1778,0x1379,0x1774,0x1375,0x1376,0x1777,0x1778,0x1379,\n"); + fprintf(fp, " 0x9380,0x9781,0x9782,0x9383,0x9784,0x9385,0x9386,0x9787,\n"); + fprintf(fp, " 0x9788,0x9389,0x9784,0x9385,0x9386,0x9787,0x9788,0x9389,\n"); + fprintf(fp, " 0x9790,0x9391,0x9392,0x9793,0x9394,0x9795,0x9796,0x9397,\n"); + fprintf(fp, " 0x9398,0x9799,0x9394,0x9795,0x9796,0x9397,0x9398,0x9799,\n"); + fprintf(fp, " 0x97a0,0x93a1,0x93a2,0x97a3,0x93a4,0x97a5,0x97a6,0x93a7,\n"); + fprintf(fp, " 0x93a8,0x97a9,0x93a4,0x97a5,0x97a6,0x93a7,0x93a8,0x97a9,\n"); + fprintf(fp, " 0x93b0,0x97b1,0x97b2,0x93b3,0x97b4,0x93b5,0x93b6,0x97b7,\n"); + fprintf(fp, " 0x97b8,0x93b9,0x97b4,0x93b5,0x93b6,0x97b7,0x97b8,0x93b9,\n"); + fprintf(fp, " 0x97c0,0x93c1,0x93c2,0x97c3,0x93c4,0x97c5,0x97c6,0x93c7,\n"); + fprintf(fp, " 0x93c8,0x97c9,0x93c4,0x97c5,0x97c6,0x93c7,0x93c8,0x97c9,\n"); + fprintf(fp, " 0x93d0,0x97d1,0x97d2,0x93d3,0x97d4,0x93d5,0x93d6,0x97d7,\n"); + fprintf(fp, " 0x97d8,0x93d9,0x97d4,0x93d5,0x93d6,0x97d7,0x97d8,0x93d9,\n"); + fprintf(fp, " 0x93e0,0x97e1,0x97e2,0x93e3,0x97e4,0x93e5,0x93e6,0x97e7,\n"); + fprintf(fp, " 0x97e8,0x93e9,0x97e4,0x93e5,0x93e6,0x97e7,0x97e8,0x93e9,\n"); + fprintf(fp, " 0x97f0,0x93f1,0x93f2,0x97f3,0x93f4,0x97f5,0x97f6,0x93f7,\n"); + fprintf(fp, " 0x93f8,0x97f9,0x93f4,0x97f5,0x97f6,0x93f7,0x93f8,0x97f9,\n"); + fprintf(fp, " 0x5700,0x1301,0x1302,0x1703,0x1304,0x1705,0x1706,0x1307,\n"); + fprintf(fp, " 0x1308,0x1709,0x1304,0x1705,0x1706,0x1307,0x1308,0x1709,\n"); + fprintf(fp, " 0x1310,0x1711,0x1712,0x1313,0x1714,0x1315,0x1316,0x1717,\n"); + fprintf(fp, " 0x1718,0x1319,0x1714,0x1315,0x1316,0x1717,0x1718,0x1319,\n"); + fprintf(fp, " 0x1320,0x1721,0x1722,0x1323,0x1724,0x1325,0x1326,0x1727,\n"); + fprintf(fp, " 0x1728,0x1329,0x1724,0x1325,0x1326,0x1727,0x1728,0x1329,\n"); + fprintf(fp, " 0x1730,0x1331,0x1332,0x1733,0x1334,0x1735,0x1736,0x1337,\n"); + fprintf(fp, " 0x1338,0x1739,0x1334,0x1735,0x1736,0x1337,0x1338,0x1739,\n"); + fprintf(fp, " 0x1340,0x1741,0x1742,0x1343,0x1744,0x1345,0x1346,0x1747,\n"); + fprintf(fp, " 0x1748,0x1349,0x1744,0x1345,0x1346,0x1747,0x1748,0x1349,\n"); + fprintf(fp, " 0x1750,0x1351,0x1352,0x1753,0x1354,0x1755,0x1756,0x1357,\n"); + fprintf(fp, " 0x1358,0x1759,0x1354,0x1755,0x1756,0x1357,0x1358,0x1759,\n"); + fprintf(fp, " 0x1760,0x1361,0x1362,0x1763,0x1364,0x1765,0x1766,0x1367,\n"); + fprintf(fp, " 0x1368,0x1769,0x1364,0x1765,0x1766,0x1367,0x1368,0x1769,\n"); + fprintf(fp, " 0x1370,0x1771,0x1772,0x1373,0x1774,0x1375,0x1376,0x1777,\n"); + fprintf(fp, " 0x1778,0x1379,0x1774,0x1375,0x1376,0x1777,0x1778,0x1379,\n"); + fprintf(fp, " 0x9380,0x9781,0x9782,0x9383,0x9784,0x9385,0x9386,0x9787,\n"); + fprintf(fp, " 0x9788,0x9389,0x9784,0x9385,0x9386,0x9787,0x9788,0x9389,\n"); + fprintf(fp, " 0x9790,0x9391,0x9392,0x9793,0x9394,0x9795,0x9796,0x9397,\n"); + fprintf(fp, " 0x9398,0x9799,0x9394,0x9795,0x9796,0x9397,0x9398,0x9799,\n"); + fprintf(fp, " 0x97fa,0x93fb,0x97fc,0x93fd,0x93fe,0x97ff,0x5600,0x1201,\n"); + fprintf(fp, " 0x1202,0x1603,0x1204,0x1605,0x1606,0x1207,0x1208,0x1609,\n"); + fprintf(fp, " 0x160a,0x120b,0x160c,0x120d,0x120e,0x160f,0x1210,0x1611,\n"); + fprintf(fp, " 0x1612,0x1213,0x1614,0x1215,0x1216,0x1617,0x1618,0x1219,\n"); + fprintf(fp, " 0x121a,0x161b,0x121c,0x161d,0x161e,0x121f,0x1220,0x1621,\n"); + fprintf(fp, " 0x1622,0x1223,0x1624,0x1225,0x1226,0x1627,0x1628,0x1229,\n"); + fprintf(fp, " 0x122a,0x162b,0x122c,0x162d,0x162e,0x122f,0x1630,0x1231,\n"); + fprintf(fp, " 0x1232,0x1633,0x1234,0x1635,0x1636,0x1237,0x1238,0x1639,\n"); + fprintf(fp, " 0x163a,0x123b,0x163c,0x123d,0x123e,0x163f,0x1240,0x1641,\n"); + fprintf(fp, " 0x1642,0x1243,0x1644,0x1245,0x1246,0x1647,0x1648,0x1249,\n"); + fprintf(fp, " 0x124a,0x164b,0x124c,0x164d,0x164e,0x124f,0x1650,0x1251,\n"); + fprintf(fp, " 0x1252,0x1653,0x1254,0x1655,0x1656,0x1257,0x1258,0x1659,\n"); + fprintf(fp, " 0x165a,0x125b,0x165c,0x125d,0x125e,0x165f,0x1660,0x1261,\n"); + fprintf(fp, " 0x1262,0x1663,0x1264,0x1665,0x1666,0x1267,0x1268,0x1669,\n"); + fprintf(fp, " 0x166a,0x126b,0x166c,0x126d,0x126e,0x166f,0x1270,0x1671,\n"); + fprintf(fp, " 0x1672,0x1273,0x1674,0x1275,0x1276,0x1677,0x1678,0x1279,\n"); + fprintf(fp, " 0x127a,0x167b,0x127c,0x167d,0x167e,0x127f,0x9280,0x9681,\n"); + fprintf(fp, " 0x9682,0x9283,0x9684,0x9285,0x9286,0x9687,0x9688,0x9289,\n"); + fprintf(fp, " 0x928a,0x968b,0x928c,0x968d,0x968e,0x928f,0x9690,0x9291,\n"); + fprintf(fp, " 0x9292,0x9693,0x1334,0x1735,0x1736,0x1337,0x1338,0x1739,\n"); + fprintf(fp, " 0x173a,0x133b,0x173c,0x133d,0x133e,0x173f,0x1340,0x1741,\n"); + fprintf(fp, " 0x1742,0x1343,0x1744,0x1345,0x1346,0x1747,0x1748,0x1349,\n"); + fprintf(fp, " 0x134a,0x174b,0x134c,0x174d,0x174e,0x134f,0x1750,0x1351,\n"); + fprintf(fp, " 0x1352,0x1753,0x1354,0x1755,0x1756,0x1357,0x1358,0x1759,\n"); + fprintf(fp, " 0x175a,0x135b,0x175c,0x135d,0x135e,0x175f,0x1760,0x1361,\n"); + fprintf(fp, " 0x1362,0x1763,0x1364,0x1765,0x1766,0x1367,0x1368,0x1769,\n"); + fprintf(fp, " 0x176a,0x136b,0x176c,0x136d,0x136e,0x176f,0x1370,0x1771,\n"); + fprintf(fp, " 0x1772,0x1373,0x1774,0x1375,0x1376,0x1777,0x1778,0x1379,\n"); + fprintf(fp, " 0x137a,0x177b,0x137c,0x177d,0x177e,0x137f,0x9380,0x9781,\n"); + fprintf(fp, " 0x9782,0x9383,0x9784,0x9385,0x9386,0x9787,0x9788,0x9389,\n"); + fprintf(fp, " 0x938a,0x978b,0x938c,0x978d,0x978e,0x938f,0x9790,0x9391,\n"); + fprintf(fp, " 0x9392,0x9793,0x9394,0x9795,0x9796,0x9397,0x9398,0x9799,\n"); + fprintf(fp, " 0x979a,0x939b,0x979c,0x939d,0x939e,0x979f,0x97a0,0x93a1,\n"); + fprintf(fp, " 0x93a2,0x97a3,0x93a4,0x97a5,0x97a6,0x93a7,0x93a8,0x97a9,\n"); + fprintf(fp, " 0x97aa,0x93ab,0x97ac,0x93ad,0x93ae,0x97af,0x93b0,0x97b1,\n"); + fprintf(fp, " 0x97b2,0x93b3,0x97b4,0x93b5,0x93b6,0x97b7,0x97b8,0x93b9,\n"); + fprintf(fp, " 0x93ba,0x97bb,0x93bc,0x97bd,0x97be,0x93bf,0x97c0,0x93c1,\n"); + fprintf(fp, " 0x93c2,0x97c3,0x93c4,0x97c5,0x97c6,0x93c7,0x93c8,0x97c9,\n"); + fprintf(fp, " 0x97ca,0x93cb,0x97cc,0x93cd,0x93ce,0x97cf,0x93d0,0x97d1,\n"); + fprintf(fp, " 0x97d2,0x93d3,0x97d4,0x93d5,0x93d6,0x97d7,0x97d8,0x93d9,\n"); + fprintf(fp, " 0x93da,0x97db,0x93dc,0x97dd,0x97de,0x93df,0x93e0,0x97e1,\n"); + fprintf(fp, " 0x97e2,0x93e3,0x97e4,0x93e5,0x93e6,0x97e7,0x97e8,0x93e9,\n"); + fprintf(fp, " 0x93ea,0x97eb,0x93ec,0x97ed,0x97ee,0x93ef,0x97f0,0x93f1,\n"); + fprintf(fp, " 0x93f2,0x97f3,0x93f4,0x97f5,0x97f6,0x93f7,0x93f8,0x97f9,\n"); + fprintf(fp, " 0x97fa,0x93fb,0x97fc,0x93fd,0x93fe,0x97ff,0x5700,0x1301,\n"); + fprintf(fp, " 0x1302,0x1703,0x1304,0x1705,0x1706,0x1307,0x1308,0x1709,\n"); + fprintf(fp, " 0x170a,0x130b,0x170c,0x130d,0x130e,0x170f,0x1310,0x1711,\n"); + fprintf(fp, " 0x1712,0x1313,0x1714,0x1315,0x1316,0x1717,0x1718,0x1319,\n"); + fprintf(fp, " 0x131a,0x171b,0x131c,0x171d,0x171e,0x131f,0x1320,0x1721,\n"); + fprintf(fp, " 0x1722,0x1323,0x1724,0x1325,0x1326,0x1727,0x1728,0x1329,\n"); + fprintf(fp, " 0x132a,0x172b,0x132c,0x172d,0x172e,0x132f,0x1730,0x1331,\n"); + fprintf(fp, " 0x1332,0x1733,0x1334,0x1735,0x1736,0x1337,0x1338,0x1739,\n"); + fprintf(fp, " 0x173a,0x133b,0x173c,0x133d,0x133e,0x173f,0x1340,0x1741,\n"); + fprintf(fp, " 0x1742,0x1343,0x1744,0x1345,0x1346,0x1747,0x1748,0x1349,\n"); + fprintf(fp, " 0x134a,0x174b,0x134c,0x174d,0x174e,0x134f,0x1750,0x1351,\n"); + fprintf(fp, " 0x1352,0x1753,0x1354,0x1755,0x1756,0x1357,0x1358,0x1759,\n"); + fprintf(fp, " 0x175a,0x135b,0x175c,0x135d,0x135e,0x175f,0x1760,0x1361,\n"); + fprintf(fp, " 0x1362,0x1763,0x1364,0x1765,0x1766,0x1367,0x1368,0x1769,\n"); + fprintf(fp, " 0x176a,0x136b,0x176c,0x136d,0x136e,0x176f,0x1370,0x1771,\n"); + fprintf(fp, " 0x1772,0x1373,0x1774,0x1375,0x1376,0x1777,0x1778,0x1379,\n"); + fprintf(fp, " 0x137a,0x177b,0x137c,0x177d,0x177e,0x137f,0x9380,0x9781,\n"); + fprintf(fp, " 0x9782,0x9383,0x9784,0x9385,0x9386,0x9787,0x9788,0x9389,\n"); + fprintf(fp, " 0x938a,0x978b,0x938c,0x978d,0x978e,0x938f,0x9790,0x9391,\n"); + fprintf(fp, " 0x9392,0x9793,0x9394,0x9795,0x9796,0x9397,0x9398,0x9799 \n"); + fprintf(fp, "};\n\n"); + + fprintf(fp, "void DDFDCBHandler(UINT32 dwWhich);\n\n"); + + fprintf(fp, "\n"); + } + else + { + assert(0); + } +} + +CodeSegmentBegin() +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp, " section .text use32 flat class=code\n"); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, "static void InvalidInstruction(UINT32 dwCount)\n"); + fprintf(fp, "{\n"); + + fprintf(fp, " pbPC -= dwCount; /* Invalid instruction - back up */\n"); + fprintf(fp, " dwReturnCode = (UINT32) pbPC - (UINT32) cpu.z80Base;\n"); + fprintf(fp, " dwOriginalCycles -= sdwCyclesRemaining;\n"); + fprintf(fp, " sdwCyclesRemaining = 0;\n"); + + fprintf(fp, "}\n\n"); + } + else + { + assert(0); + } +} + +CodeSegmentEnd() +{ +} + +ProgramEnd() +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp, " end\n"); + } + else + if (MZ80_C == bWhat) + { + } + else + { + assert(0); + } +} + +EmitRegularInstructions() +{ + UINT32 dwLoop = 0; + UINT32 dwLoop2 = 0; + + bCurrentMode = TIMING_REGULAR; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + while (dwLoop < 0x100) + { + dwLoop2 = 0; + sprintf(procname, "RegInst%.2x", dwLoop); + + while (StandardOps[dwLoop2].bOpCode != dwLoop && StandardOps[dwLoop2].bOpCode != 0xffffffff) + dwLoop2++; + + assert(dwLoop2 < 0x100); + if (StandardOps[dwLoop2].Emitter + && StandardOps[dwLoop2].bOpCode != 0xffffffff) + StandardOps[dwLoop2].Emitter((UINT32) dwLoop); + + dwLoop++; + } + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, "/* Main execution entry point */\n\n"); + + fprintf(fp, "UINT32 %sexec(UINT32 dwCycles)\n", cpubasename); + fprintf(fp, "{\n"); + fprintf(fp, " UINT8 bOpcode;\n\n"); + + fprintf(fp, " dwReturnCode = 0x80000000; /* Assume it'll work */\n"); + + fprintf(fp, " sdwCyclesRemaining = dwCycles;\n"); + fprintf(fp, " dwOriginalCycles = dwCycles;\n"); + + fprintf(fp, " if (cpu.z80halted)\n"); + fprintf(fp, " {\n"); + + fprintf(fp, " dwElapsedTicks += dwCycles;\n"); + fprintf(fp, " return(0x80000000);\n"); + + fprintf(fp, " }\n\n"); + + + fprintf(fp, " pbPC = cpu.z80Base + cpu.z80pc;\n\n"); + + fprintf(fp, " while (sdwCyclesRemaining > 0)\n"); + + fprintf(fp, " {\n"); + fprintf(fp, " bOpcode = *pbPC++;\n"); + fprintf(fp, " switch (bOpcode)\n"); + fprintf(fp, " {\n"); + + while (dwLoop < 0x100) + { + dwLoop2 = 0; + + fprintf(fp, " case 0x%.2x:\n", dwLoop); + fprintf(fp, " {\n"); + + while (StandardOps[dwLoop2].bOpCode != dwLoop && StandardOps[dwLoop2].bOpCode != 0xffffffff) + dwLoop2++; + + if (bTimingRegular[dwLoop]) + { + fprintf(fp, " sdwCyclesRemaining -= %ld;\n", bTimingRegular[dwLoop]); + } + + if (StandardOps[dwLoop2].Emitter) + { + StandardOps[dwLoop2].Emitter(dwLoop); + } + + fprintf(fp, " break;\n"); + fprintf(fp, " }\n"); + ++dwLoop; + } + + fprintf(fp, " }\n"); + fprintf(fp, " }\n\n"); + + fprintf(fp, " dwElapsedTicks += (dwOriginalCycles - sdwCyclesRemaining);\n\n"); + + fprintf(fp, " cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base;\n"); + + fprintf(fp, " return(dwReturnCode); /* Indicate success */\n"); + fprintf(fp, "}\n\n"); + } + else + { + assert(0); + } +} + +EmitCBInstructions() +{ + UINT32 dwLoop = 0; + UINT32 dwLoop2 = 0; + + bCurrentMode = TIMING_CB; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + while (dwLoop < 0x100) + { + sprintf(procname, "CBInst%.2x", dwLoop); + dwLoop2 = 0; + + while (CBOps[dwLoop2].bOpCode != dwLoop && CBOps[dwLoop2].bOpCode != 0xffffffff) + dwLoop2++; + + assert(dwLoop2 < 0x100); + if (CBOps[dwLoop2].Emitter && CBOps[dwLoop2].bOpCode != 0xffffffff) + CBOps[dwLoop2].Emitter((UINT32) dwLoop); + + dwLoop++; + } + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, "void CBHandler(void)\n"); + fprintf(fp, "{\n"); + fprintf(fp, " switch (*pbPC++)\n"); + fprintf(fp, " {\n"); + + while (dwLoop < 0x100) + { + dwLoop2 = 0; + + fprintf(fp, " case 0x%.2x:\n", dwLoop); + fprintf(fp, " {\n"); + + while (CBOps[dwLoop2].bOpCode != dwLoop && CBOps[dwLoop2].bOpCode != 0xffffffff) + dwLoop2++; + + if (bTimingCB[dwLoop]) + { + fprintf(fp, " sdwCyclesRemaining -= %ld;\n", bTimingCB[dwLoop]); + } + + if (CBOps[dwLoop2].Emitter) + { + CBOps[dwLoop2].Emitter(dwLoop); + } + else + { + InvalidInstructionC(2); + } + + fprintf(fp, " break;\n"); + fprintf(fp, " }\n"); + ++dwLoop; + } + + fprintf(fp, " }\n"); + fprintf(fp, "}\n"); + } + else + { + assert(0); + } +} + +EmitEDInstructions() +{ + UINT32 dwLoop = 0; + UINT32 dwLoop2 = 0; + + bCurrentMode = TIMING_ED; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + while (dwLoop < 0x100) + { + sprintf(procname, "EDInst%.2x", dwLoop); + dwLoop2 = 0; + + while (EDOps[dwLoop2].bOpCode != dwLoop && EDOps[dwLoop2].bOpCode != 0xffffffff) + dwLoop2++; + + assert(dwLoop2 < 0x100); + if (EDOps[dwLoop2].Emitter && EDOps[dwLoop2].bOpCode != 0xffffffff) + EDOps[dwLoop2].Emitter((UINT32) dwLoop); + + dwLoop++; + } + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, "void EDHandler(void)\n"); + fprintf(fp, "{\n"); + fprintf(fp, " switch (*pbPC++)\n"); + fprintf(fp, " {\n"); + + while (dwLoop < 0x100) + { + dwLoop2 = 0; + + fprintf(fp, " case 0x%.2x:\n", dwLoop); + fprintf(fp, " {\n"); + + while (EDOps[dwLoop2].bOpCode != dwLoop && EDOps[dwLoop2].bOpCode != 0xffffffff) + dwLoop2++; + + if (bTimingED[dwLoop]) + { + fprintf(fp, " sdwCyclesRemaining -= %ld;\n", bTimingED[dwLoop]); + } + + if (EDOps[dwLoop2].Emitter) + { + EDOps[dwLoop2].Emitter(dwLoop); + } + else + { + InvalidInstructionC(2); + } + + fprintf(fp, " break;\n"); + fprintf(fp, " }\n"); + ++dwLoop; + } + + fprintf(fp, " }\n"); + fprintf(fp, "}\n"); + } + else + { + assert(0); + } + + fprintf(fp, "\n"); +} + +EmitDDInstructions() +{ + UINT32 dwLoop = 0; + UINT32 dwLoop2 = 0; + + bCurrentMode = TIMING_DDFD; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + while (dwLoop < 0x100) + { + sprintf(procname, "DDInst%.2x", dwLoop); + dwLoop2 = 0; + + while (DDFDOps[dwLoop2].bOpCode != dwLoop && DDFDOps[dwLoop2].bOpCode != 0xffffffff) + dwLoop2++; + + assert(dwLoop2 < 0x100); + if (DDFDOps[dwLoop2].Emitter && DDFDOps[dwLoop2].bOpCode != 0xffffffff) + DDFDOps[dwLoop2].Emitter((UINT32) dwLoop); + + dwLoop++; + } + + bCurrentMode = TIMING_XXCB; + + dwLoop = 0; + + while (dwLoop < 0x100) + { + sprintf(procname, "DDFDCBInst%.2x", dwLoop); + dwLoop2 = 0; + + while (DDFDCBOps[dwLoop2].bOpCode != dwLoop && DDFDCBOps[dwLoop2].bOpCode != 0xffffffff) + dwLoop2++; + + assert(dwLoop2 < 0x100); + if (DDFDCBOps[dwLoop2].Emitter && DDFDCBOps[dwLoop2].bOpCode != 0xffffffff) + DDFDCBOps[dwLoop2].Emitter((UINT32) dwLoop); + + dwLoop++; + } + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, "void DDHandler(void)\n"); + fprintf(fp, "{\n"); + fprintf(fp, " switch (*pbPC++)\n"); + fprintf(fp, " {\n"); + + while (dwLoop < 0x100) + { + dwLoop2 = 0; + + fprintf(fp, " case 0x%.2x:\n", dwLoop); + fprintf(fp, " {\n"); + + while (DDFDOps[dwLoop2].bOpCode != dwLoop && DDFDOps[dwLoop2].bOpCode != 0xffffffff) + dwLoop2++; + + if (bTimingDDFD[dwLoop]) + { + fprintf(fp, " sdwCyclesRemaining -= %ld;\n", bTimingDDFD[dwLoop]); + } + + if (DDFDOps[dwLoop2].Emitter) + { + DDFDOps[dwLoop2].Emitter(dwLoop); + } + else + { + InvalidInstructionC(2); + } + + fprintf(fp, " break;\n"); + fprintf(fp, " }\n"); + ++dwLoop; + } + + fprintf(fp, " }\n"); + fprintf(fp, "}\n"); + + // DDFD Handler + + bCurrentMode = TIMING_XXCB; + + dwLoop = 0; + + fprintf(fp, "void DDFDCBHandler(UINT32 dwWhich)\n"); + fprintf(fp, "{\n"); + fprintf(fp, " if (dwWhich)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " dwAddr = (UINT32) ((INT32) cpu.z80IY + ((INT32) *pbPC++)) & 0xffff;\n"); + fprintf(fp, " }\n"); + fprintf(fp, " else\n"); + fprintf(fp, " {\n"); + fprintf(fp, " dwAddr = (UINT32) ((INT32) cpu.z80IX + ((INT32) *pbPC++)) & 0xffff;\n"); + fprintf(fp, " }\n\n"); + + ReadValueFromMemory("dwAddr", "bTemp"); + + fprintf(fp, " switch (*pbPC++)\n"); + fprintf(fp, " {\n"); + + while (dwLoop < 0x100) + { + dwLoop2 = 0; + + fprintf(fp, " case 0x%.2x:\n", dwLoop); + fprintf(fp, " {\n"); + + while (DDFDCBOps[dwLoop2].bOpCode != dwLoop && DDFDCBOps[dwLoop2].bOpCode != 0xffffffff) + dwLoop2++; + + if (bTimingXXCB[dwLoop]) + { + fprintf(fp, " sdwCyclesRemaining -= %ld;\n", bTimingXXCB[dwLoop]); + } + + if (DDFDCBOps[dwLoop2].Emitter) + { + DDFDCBOps[dwLoop2].Emitter(dwLoop); + } + else + { + InvalidInstructionC(4); + } + + fprintf(fp, " break;\n"); + fprintf(fp, " }\n"); + ++dwLoop; + } + + fprintf(fp, " }\n"); + fprintf(fp, "}\n"); + } + else + { + assert(0); + } +} + +EmitFDInstructions() +{ + UINT32 dwLoop = 0; + UINT32 dwLoop2 = 0; + + bCurrentMode = TIMING_DDFD; + + if (MZ80_ASSEMBLY_X86 == bWhat) + { + while (dwLoop < 0x100) + { + sprintf(procname, "FDInst%.2x", dwLoop); + dwLoop2 = 0; + + while (DDFDOps[dwLoop2].bOpCode != dwLoop && DDFDOps[dwLoop2].bOpCode != 0xffffffff) + dwLoop2++; + + assert(dwLoop2 < 0x100); + if (DDFDOps[dwLoop2].Emitter && DDFDOps[dwLoop2].bOpCode != 0xffffffff) + DDFDOps[dwLoop2].Emitter((UINT32) dwLoop); + + dwLoop++; + } + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, "void FDHandler(void)\n"); + fprintf(fp, "{\n"); + fprintf(fp, " switch (*pbPC++)\n"); + fprintf(fp, " {\n"); + + while (dwLoop < 0x100) + { + dwLoop2 = 0; + + fprintf(fp, " case 0x%.2x:\n", dwLoop); + fprintf(fp, " {\n"); + + while (DDFDOps[dwLoop2].bOpCode != dwLoop && DDFDOps[dwLoop2].bOpCode != 0xffffffff) + dwLoop2++; + + if (bTimingDDFD[dwLoop]) + { + fprintf(fp, " sdwCyclesRemaining -= %ld;\n", bTimingDDFD[dwLoop]); + } + + if (DDFDOps[dwLoop2].Emitter) + { + DDFDOps[dwLoop2].Emitter(dwLoop); + } + else + { + InvalidInstructionC(2); + } + + fprintf(fp, " break;\n"); + fprintf(fp, " }\n"); + ++dwLoop; + } + + fprintf(fp, " }\n"); + fprintf(fp, "}\n"); + } + else + { + assert(0); + } +} + +/* These are the meta routines */ + +void ReadMemoryByteHandler() +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + Alignment(); + fprintf(fp, "; This is a generic read memory byte handler when a foreign\n"); + fprintf(fp, "; handler is to be called\n\n"); + fprintf(fp, "; EDI=Handler address, EDX=Address\n"); + fprintf(fp, "; On return, EDX & EDI are undisturbed and AL=Byte read\n\n"); + fprintf(fp, "ReadMemoryByte:\n"); + + fprintf(fp, " mov [_z80af], ax ; Save AF\n"); + fprintf(fp, " cmp [edi+8], dword 0 ; Null handler?\n"); + fprintf(fp, " je directReadHandler ; Yep! It's a direct read!\n\n"); + + fprintf(fp, " mov [_z80hl], bx ; Save HL\n"); + fprintf(fp, " mov [_z80bc], cx ; Save BC\n"); + + fprintf(fp, " sub esi, ebp ; Our program counter\n", cpubasename); + fprintf(fp, " mov [_z80pc], si ; Save our program counter\n", cpubasename); + + // Now adjust the proper timing + + fprintf(fp, " mov esi, [dwOriginalExec] \n"); + fprintf(fp, " sub esi, [cyclesRemaining]\n"); + fprintf(fp, " add [dwElapsedTicks], esi\n"); + fprintf(fp, " add [_z80rCounter], esi\n"); + fprintf(fp, " sub [dwOriginalExec], esi\n"); + + fprintf(fp, " push edi ; Save our structure address\n"); + fprintf(fp, " push edx ; And our desired address\n"); + + if (FALSE == bUseStack) + { + fprintf(fp, " mov eax, edx ; Get our desired address reg\n"); + fprintf(fp, " mov edx, edi ; Pointer to the structure\n"); + } + + fprintf(fp, " call dword [edi + 8] ; Go call our handler\n"); + + fprintf(fp, " pop edx ; Restore our address\n"); + fprintf(fp, " pop edi ; Restore our handler's address\n"); + + fprintf(fp, " xor ebx, ebx ; Zero our future HL\n"); + fprintf(fp, " xor esi, esi ; Zero it!\n"); + fprintf(fp, " mov ebp, [_z80Base] ; Base pointer comes back\n", cpubasename); + fprintf(fp, " mov si, [_z80pc] ; Get our program counter back\n", cpubasename); + fprintf(fp, " xor ecx, ecx ; Zero our future BC\n"); + fprintf(fp, " add esi, ebp ; Rebase it properly\n"); + + fprintf(fp, " mov bx, [_z80hl] ; Get HL back\n"); + fprintf(fp, " mov cx, [_z80bc] ; Get BC back\n"); + + // Note: the callee must restore AF! + + fprintf(fp, " ret\n\n"); + fprintf(fp, "directReadHandler:\n"); + fprintf(fp, " mov eax, [edi+12] ; Get our base address\n"); + fprintf(fp, " sub edx, [edi] ; Subtract our base (low) address\n"); + fprintf(fp, " mov al, [edx+eax] ; Get our data byte\n"); + fprintf(fp, " and eax, 0ffh ; Only the lower byte matters!\n"); + fprintf(fp, " add edx, [edi] ; Add our base back\n"); + fprintf(fp, " ret ; Return to caller!\n\n"); + } + else + if (MZ80_C == bWhat) + { + } + else + { + assert(0); + } +} + +void WriteMemoryByteHandler() +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + Alignment(); + fprintf(fp, "; This is a generic read memory byte handler when a foreign\n"); + fprintf(fp, "; handler is to be called.\n"); + fprintf(fp, "; EDI=Handler address, AL=Byte to write, EDX=Address\n"); + fprintf(fp, "; EDI and EDX Are undisturbed on exit\n\n"); + fprintf(fp, "WriteMemoryByte:\n"); + + fprintf(fp, " cmp [edi+8], dword 0 ; Null handler?\n"); + fprintf(fp, " je directWriteHandler\n\n"); + + + fprintf(fp, " mov [_z80hl], bx ; Save HL\n"); + fprintf(fp, " mov [_z80bc], cx ; Save BX\n"); + + fprintf(fp, " sub esi, ebp ; Our program counter\n", cpubasename); + fprintf(fp, " mov [_z80pc], si ; Save our program counter\n", cpubasename); + + // Now adjust the proper timing + + fprintf(fp, " mov esi, [dwOriginalExec] \n"); + fprintf(fp, " sub esi, [cyclesRemaining]\n"); + fprintf(fp, " add [dwElapsedTicks], esi\n"); + fprintf(fp, " add [_z80rCounter], esi\n"); + fprintf(fp, " sub [dwOriginalExec], esi\n"); + + fprintf(fp, " push edi ; Save our structure address\n"); + + if (bUseStack) + fprintf(fp, " push eax ; Data to write\n"); + + fprintf(fp, " push edx ; And our desired address\n"); + + if (FALSE == bUseStack) + { + fprintf(fp, " xchg eax, edx ; Swap address/data around\n"); + fprintf(fp, " mov ebx, edi ; Our MemoryWriteByte structure address\n"); + } + + fprintf(fp, " call dword [edi + 8] ; Go call our handler\n"); + + fprintf(fp, " pop edx ; Restore our address\n"); + + if (bUseStack) + fprintf(fp, " pop eax ; Restore our data written\n"); + + fprintf(fp, " pop edi ; Save our structure address\n"); + + fprintf(fp, " xor ebx, ebx ; Zero our future HL\n"); + fprintf(fp, " xor ecx, ecx ; Zero our future BC\n"); + fprintf(fp, " mov bx, [_z80hl] ; Get HL back\n"); + fprintf(fp, " mov cx, [_z80bc] ; Get BC back\n"); + fprintf(fp, " mov ax, [_z80af] ; Get AF back\n"); + fprintf(fp, " xor esi, esi ; Zero it!\n"); + fprintf(fp, " mov si, [_z80pc] ; Get our program counter back\n", cpubasename); + fprintf(fp, " mov ebp, [_z80Base] ; Base pointer comes back\n", cpubasename); + fprintf(fp, " add esi, ebp ; Rebase it properly\n"); + + fprintf(fp, " ret\n\n"); + + fprintf(fp, "directWriteHandler:\n"); + fprintf(fp, " sub edx, [edi] ; Subtract our offset\n"); + fprintf(fp, " add edx, [edi+12] ; Add in the base address\n"); + fprintf(fp, " mov [edx], al ; Store our byte\n"); + fprintf(fp, " sub edx, [edi+12] ; Restore our base address\n"); + fprintf(fp, " add edx, [edi] ; And put our offset back\n"); + fprintf(fp, " ret\n\n"); + } + else + if (MZ80_C == bWhat) + { + } + else + { + assert(0); + } +} + +void PushWordHandler() +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + Alignment(); + + fprintf(fp, ";\n"); + fprintf(fp, "; DX=Top of SP, [_wordval]=word value to push\n"); + fprintf(fp, ";\n\n"); + fprintf(fp, "PushWord:\n"); + fprintf(fp, " mov dx, [_z80sp]\n"); + fprintf(fp, " dec dx\n"); + WriteValueToMemory("dx", "byte [_wordval+1]"); + fprintf(fp, " dec dx\n"); + WriteValueToMemory("dx", "byte [_wordval]"); + fprintf(fp, " sub [_z80sp], word 2\n"); + fprintf(fp, " xor edx, edx\n"); + fprintf(fp, " ret\n\n"); + } +} + +void PopWordHandler() +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + Alignment(); + + fprintf(fp, ";\n"); + fprintf(fp, "; [_z80sp]=Top of SP, DX=Word value read\n"); + fprintf(fp, ";\n\n"); + fprintf(fp, "PopWord:\n"); + fprintf(fp, " mov dx, [_z80sp]\n"); + + ReadWordFromMemory("dx", "dx"); + fprintf(fp, " ret\n\n"); + } +} + +void ReadIoHandler() +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + Alignment(); + + fprintf(fp, "; This is a generic I/O read byte handler for when a foreign\n"); + fprintf(fp, "; handler is to be called\n"); + + fprintf(fp, "; EDI=Handler address, EDX=I/O Address\n"); + fprintf(fp, "; On return, EDX & EDI are undisturbed and AL=Byte read\n\n"); + fprintf(fp, "ReadIOByte:\n"); + + fprintf(fp, " mov [_z80af], ax ; Save AF\n"); + fprintf(fp, " mov [_z80hl], bx ; Save HL\n"); + fprintf(fp, " mov [_z80bc], cx ; Save BC\n"); + + fprintf(fp, " sub esi, ebp ; Our program counter\n", cpubasename); + fprintf(fp, " mov [_z80pc], si ; Save our program counter\n", cpubasename); + + // Now adjust the proper timing + + fprintf(fp, " mov esi, [dwOriginalExec] \n"); + fprintf(fp, " sub esi, [cyclesRemaining]\n"); + fprintf(fp, " add [dwElapsedTicks], esi\n"); + fprintf(fp, " add [_z80rCounter], esi\n"); + fprintf(fp, " sub [dwOriginalExec], esi\n"); + + fprintf(fp, " push edi ; Save our structure address\n"); + fprintf(fp, " push edx ; And our desired I/O port\n"); + + if (FALSE == bUseStack) + { + fprintf(fp, " mov eax, edx ; Get our desired address reg\n"); + fprintf(fp, " mov edx, edi ; Pointer to the structure\n"); + } + + fprintf(fp, " call dword [edi + 4] ; Go call our handler\n"); + + fprintf(fp, " pop edx ; Restore our address\n"); + fprintf(fp, " pop edi ; Restore our handler's address\n"); + + fprintf(fp, " xor ebx, ebx ; Zero our future HL\n"); + fprintf(fp, " xor ecx, ecx ; Zero our future BC\n"); + fprintf(fp, " xor esi, esi ; Zero it!\n"); + fprintf(fp, " mov si, [_z80pc] ; Get our program counter back\n", cpubasename); + fprintf(fp, " mov ebp, [_z80Base] ; Base pointer comes back\n", cpubasename); + fprintf(fp, " add esi, ebp ; Rebase it properly\n"); + + fprintf(fp, " mov bx, [_z80hl] ; Get HL back\n"); + fprintf(fp, " mov cx, [_z80bc] ; Get BC back\n"); + + // Note: the callee must restore AF! + + fprintf(fp, " ret\n\n"); + } + else + if (MZ80_C == bWhat) + { + } + else + { + assert(0); + } +} + +void WriteIoHandler() +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + Alignment(); + + fprintf(fp, "; This is a generic write I/O byte handler when a foreign handler is to\n"); + fprintf(fp, "; be called\n"); + fprintf(fp, "; EDI=Handler address, AL=Byte to write, EDX=I/O Address\n"); + fprintf(fp, "; EDI and EDX Are undisturbed on exit\n\n"); + fprintf(fp, "WriteIOByte:\n"); + + fprintf(fp, " mov [_z80hl], bx ; Save HL\n"); + fprintf(fp, " mov [_z80bc], cx ; Save BX\n"); + + fprintf(fp, " sub esi, ebp ; Our program counter\n", cpubasename); + fprintf(fp, " mov [_z80pc], si ; Save our program counter\n", cpubasename); + + // Now adjust the proper timing + + fprintf(fp, " mov esi, [dwOriginalExec] \n"); + fprintf(fp, " sub esi, [cyclesRemaining]\n"); + fprintf(fp, " add [dwElapsedTicks], esi\n"); + fprintf(fp, " add [_z80rCounter], esi\n"); + fprintf(fp, " sub [dwOriginalExec], esi\n"); + + fprintf(fp, " push edi ; Save our structure address\n"); + + if (bUseStack) + fprintf(fp, " push eax ; Data to write\n"); + + fprintf(fp, " push edx ; And our desired I/O address\n"); + + if (FALSE == bUseStack) + { + fprintf(fp, " xchg eax, edx ; Swap address/data around\n"); + fprintf(fp, " mov ebx, edi ; Our z80IoWrite structure address\n"); + } + + fprintf(fp, " call dword [edi + 4] ; Go call our handler\n"); + + fprintf(fp, " pop edx ; Restore our address\n"); + + if (bUseStack) + fprintf(fp, " pop eax ; Restore our data written\n"); + + fprintf(fp, " pop edi ; Save our structure address\n"); + + fprintf(fp, " xor ebx, ebx ; Zero our future HL\n"); + fprintf(fp, " xor ecx, ecx ; Zero our future BC\n"); + fprintf(fp, " mov bx, [_z80hl] ; Get HL back\n"); + fprintf(fp, " mov cx, [_z80bc] ; Get BC back\n"); + fprintf(fp, " mov ax, [_z80af] ; Get AF back\n"); + fprintf(fp, " xor esi, esi ; Zero it!\n"); + fprintf(fp, " mov si, [_z80pc] ; Get our program counter back\n", cpubasename); + fprintf(fp, " mov ebp, [_z80Base] ; Base pointer comes back\n", cpubasename); + fprintf(fp, " add esi, ebp ; Rebase it properly\n"); + + fprintf(fp, " ret\n\n"); + } + else + if (MZ80_C == bWhat) + { + } + else + { + assert(0); + } +} + +ExecCode() +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp, " global _%sexec\n", cpubasename); + fprintf(fp, " global %sexec_\n", cpubasename); + + if (bPlain) + fprintf(fp, " global %sexec\n", cpubasename); + + sprintf(procname, "%sexec_", cpubasename); + ProcBegin(0xffffffff); + + fprintf(fp, "_%sexec:\n", cpubasename); + + if (bPlain) + fprintf(fp, "%sexec:\n", cpubasename); + + if (bUseStack) + fprintf(fp, " mov eax, [esp+4] ; Get our execution cycle count\n"); + + fprintf(fp, " push ebx ; Save all registers we use\n"); + fprintf(fp, " push ecx\n"); + fprintf(fp, " push edx\n"); + fprintf(fp, " push ebp\n"); + fprintf(fp, " push esi\n"); + fprintf(fp, " push edi\n"); + fprintf(fp, "\n"); + + fprintf(fp, " mov edi, eax\n"); + fprintf(fp, " mov dword [cyclesRemaining], eax ; Store # of instructions to\n"); + fprintf(fp, " mov [dwLastRSample], eax\n"); + fprintf(fp, " mov [dwOriginalExec], eax ; Store this!\n"); + + fprintf(fp, " cmp dword [_z80halted], 0\n"); + fprintf(fp, " je goCpu\n"); + fprintf(fp, " add [_z80rCounter], eax\n"); + + if (FALSE == bNoTiming) + { + fprintf(fp, " add dword [dwElapsedTicks], eax\n"); + } + + fprintf(fp, " mov dword [cyclesRemaining], 0 ; Nothing left!\n"); + fprintf(fp, " mov eax, 80000000h ; Successful exection\n"); + fprintf(fp, " jmp popReg\n"); + fprintf(fp, "goCpu:\n"); + fprintf(fp, " cld ; Go forward!\n"); + fprintf(fp, "\n"); + fprintf(fp, " xor eax, eax ; Zero EAX 'cause we use it!\n"); + fprintf(fp, " xor ebx, ebx ; Zero EBX, too\n"); + fprintf(fp, " xor ecx, ecx ; Zero ECX\n"); + fprintf(fp, " xor edx, edx ; And EDX\n"); + fprintf(fp, " xor esi, esi ; Zero our source address\n"); + fprintf(fp, "\n"); + fprintf(fp, " mov ax, [_z80af] ; Accumulator & flags\n"); + fprintf(fp, " xchg ah, al ; Swap these for later\n"); + fprintf(fp, " mov bx, [_z80hl] ; Get our HL value\n"); + fprintf(fp, " mov cx, [_z80bc] ; And our BC value\n"); + fprintf(fp, " mov ebp, [_z80Base] ; Get the base address\n"); + fprintf(fp, " mov si, [_z80pc] ; Get our program counter\n"); + fprintf(fp, " add esi, ebp ; Add in our base address\n"); + + fprintf(fp, " cmp [_z80intPending], byte 0 ; Interrupt pending?\n"); + fprintf(fp, " jz masterExecTarget\n\n"); + fprintf(fp, " call causeInternalInterrupt\n\n"); + fprintf(fp, "masterExecTarget:\n"); + fprintf(fp, " mov dl, [esi]\n"); + fprintf(fp, " inc esi\n"); + fprintf(fp, " jmp dword [z80regular+edx*4]\n\n"); + fprintf(fp, "; We get to invalidInsWord if it's a double byte invalid opcode\n"); + fprintf(fp, "\n"); + fprintf(fp, "invalidInsWord:\n"); + + fprintf(fp, " dec esi\n"); + fprintf(fp, "\n"); + fprintf(fp, "; We get to invalidInsByte if it's a single byte invalid opcode\n"); + fprintf(fp, "\n"); + + fprintf(fp, "invalidInsByte:\n"); + fprintf(fp, " xchg ah, al ; Swap them back so they look good\n"); + fprintf(fp, " mov [_z80af], ax ; Store A & flags\n"); + fprintf(fp, " dec esi ; Back up one instruction...\n"); + fprintf(fp, " mov edx, esi ; Get our address in EAX\n"); + fprintf(fp, " sub edx, ebp ; And subtract our base for\n"); + fprintf(fp, " ; an invalid instruction\n"); + fprintf(fp, " jmp short emulateEnd\n"); + fprintf(fp, "\n"); + fprintf(fp, "noMoreExec:\n"); + fprintf(fp, " cmp [bEIExit], byte 0 ; Are we exiting because of an EI?\n"); + fprintf(fp, " jne checkEI\n"); + fprintf(fp, "noMoreExecNoEI:\n"); + fprintf(fp, " xchg ah, al ; Swap these for later\n"); + fprintf(fp, " mov [_z80af], ax ; Store A & flags\n"); + + fprintf(fp, " mov edx, [dwOriginalExec] ; Original exec time\n"); + fprintf(fp, " sub edx, edi ; Subtract # of cycles remaining\n"); + fprintf(fp, " add [_z80rCounter], edx\n"); + fprintf(fp, " add [dwElapsedTicks], edx ; Add our executed time\n"); + + fprintf(fp, " mov edx, 80000000h ; Indicate successful exec\n"); + fprintf(fp, " jmp short emulateEnd ; All finished!\n"); + fprintf(fp, "\n"); + fprintf(fp, "; Now let's tuck away the virtual registers for next time\n"); + fprintf(fp, "\n"); + fprintf(fp, "storeFlags:\n"); + fprintf(fp, " xchg ah, al ; Swap these for later\n"); + fprintf(fp, " mov [_z80af], ax ; Store A & flags\n"); + fprintf(fp, "emulateEnd:\n"); + fprintf(fp, " mov [_z80hl], bx ; Store HL\n"); + fprintf(fp, " mov [_z80bc], cx ; Store BC\n"); + fprintf(fp, " sub esi, [_z80Base] ; Knock off physical address\n"); + fprintf(fp, " mov [_z80pc], si ; And store virtual address\n"); + fprintf(fp, " mov eax, edx ; Result code return\n"); + fprintf(fp, "\n"); + fprintf(fp, "popReg:\n"); + fprintf(fp, " pop edi ; Restore registers\n"); + fprintf(fp, " pop esi\n"); + fprintf(fp, " pop ebp\n"); + fprintf(fp, " pop edx\n"); + fprintf(fp, " pop ecx\n"); + fprintf(fp, " pop ebx\n"); + fprintf(fp, "\n"); + fprintf(fp, " ret\n"); + fprintf(fp, "\n"); + Alignment(); + fprintf(fp, "checkEI:\n"); + fprintf(fp, " xor edx, edx\n"); + fprintf(fp, " mov [bEIExit], byte 0\n"); + fprintf(fp, " sub edx, edi ; Find out how much time has passed\n"); + fprintf(fp, " mov edi, [dwEITiming]\n"); + fprintf(fp, " sub edi, edx\n"); + fprintf(fp, " js noMoreExecNoEI\n"); + fprintf(fp, " xor edx, edx\n"); + + fprintf(fp, " cmp [_z80intPending], byte 0\n"); + fprintf(fp, " je near masterExecTarget\n"); + fprintf(fp, " call causeInternalInterrupt\n"); + fprintf(fp, " jmp masterExecTarget\n\n"); + + Alignment(); + fprintf(fp, "causeInternalInterrupt:\n"); + fprintf(fp, " mov dword [_z80halted], 0 ; We're not halted anymore!\n"); + fprintf(fp, " test [_z80iff], byte IFF1 ; Interrupt enabled yet?\n"); + fprintf(fp, " jz near internalInterruptsDisabled\n"); + + fprintf(fp, "\n; Interrupts enabled. Clear IFF1 and IFF2\n\n"); + + fprintf(fp, " mov [_z80intPending], byte 0\n"); + + fprintf(fp, "\n; Save off our active register sets\n\n"); + + fprintf(fp, " xchg ah, al ; Swap these for later\n"); + fprintf(fp, " mov [_z80af], ax ; Store A & flags\n"); + fprintf(fp, " mov [_z80hl], bx ; Store HL\n"); + fprintf(fp, " mov [_z80bc], cx ; Store BC\n"); + fprintf(fp, " sub esi, ebp ; Knock off physical address\n"); + fprintf(fp, " mov [_z80pc], si ; And store virtual address\n"); + + fprintf(fp, " xor eax, eax\n"); + fprintf(fp, " mov al, [_intData]\n\n"); + + fprintf(fp, "\n"); + fprintf(fp, " push edi\n"); + fprintf(fp, "\n"); + + if (bThroughCallHandler) + { + fprintf(fp, " pushad\n" ); + fprintf(fp, " xor edx, edx\n" ); + fprintf(fp, " mov ax, [_z80pc]\n"); + fprintf(fp, " mov [_wordval], ax\n"); + fprintf(fp, " push ecx\n"); + fprintf(fp, " push ebx\n"); + fprintf(fp, " push esi\n"); + + fprintf(fp, " mov ax, [_z80af]\n"); // Get AF + fprintf(fp, " mov bx, [_z80hl]\n"); // Get HL + fprintf(fp, " mov cx, [_z80bc]\n"); // Get BC + fprintf(fp, " call PushWord\n"); + + fprintf(fp, " pop esi\n"); + fprintf(fp, " pop ebx\n"); + fprintf(fp, " pop ecx\n"); + fprintf(fp, " popad\n" ); + } + else + { + fprintf(fp, " mov dx, [_z80pc]\n"); + fprintf(fp, " xor edi, edi\n"); + fprintf(fp, " mov di, word [_z80sp]\n"); + fprintf(fp, " sub di, 2\n"); + fprintf(fp, " mov word [_z80sp], di\n"); + fprintf(fp, " mov [ebp+edi], dx\n"); + } + + fprintf(fp, " cmp dword [_z80interruptMode], 2 ; Are we lower than mode 2?\n"); + fprintf(fp, " jb internalJustModeTwo\n"); + fprintf(fp, " mov ah, [_z80i] ; Get our high address here\n"); + fprintf(fp, " and eax, 0ffffh ; Only the lower part\n"); + fprintf(fp, " mov ax, [eax+ebp] ; Get our vector\n"); + fprintf(fp, " jmp short internalSetNewVector ; Go set it!\n"); + fprintf(fp, "internalJustModeTwo:\n"); + fprintf(fp, " mov ax, word [_z80intAddr]\n"); + fprintf(fp, "internalSetNewVector:\n"); + fprintf(fp, " mov [_z80pc], ax\n"); + fprintf(fp, "\n"); + fprintf(fp, " pop edi\n"); + fprintf(fp, "\n"); + fprintf(fp, " xor eax, eax ; Zero this so we can use it as an index\n"); + + fprintf(fp, " mov al, [_z80interruptMode]\n"); + fprintf(fp, " mov al, [intModeTStates+eax]\n"); + fprintf(fp, " sub edi, eax\n"); + fprintf(fp, " add [_z80rCounter], eax\n"); + + fprintf(fp, "\n; Restore all the registers and whatnot\n\n"); + + fprintf(fp, " mov ax, [_z80af] ; Accumulator & flags\n"); + fprintf(fp, " xchg ah, al ; Swap these for later\n"); + fprintf(fp, " mov bx, [_z80hl] ; Get our HL value\n"); + fprintf(fp, " mov cx, [_z80bc] ; And our BC value\n"); + fprintf(fp, " mov ebp, [_z80Base] ; Get the base address\n"); + fprintf(fp, " mov si, [_z80pc] ; Get our program counter\n"); + fprintf(fp, " add esi, ebp ; Add in our base address\n"); + + fprintf(fp, "internalInterruptsDisabled:\n"); + fprintf(fp, " xor edx, edx\n"); + fprintf(fp, " ret\n"); + } + else + if (MZ80_C == bWhat) + { + } + else + { + assert(0); + } +} + +NmiCode() +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp, " global _%snmi\n", cpubasename); + fprintf(fp, " global %snmi_\n", cpubasename); + + if (bPlain) + fprintf(fp, " global %snmi\n", cpubasename); + + sprintf(procname, "%snmi_", cpubasename); + ProcBegin(0xffffffff); + fprintf(fp, "_%snmi:\n", cpubasename); + + if (bPlain) + fprintf(fp, "%snmi:\n", cpubasename); + + fprintf(fp, " mov dword [_z80halted], 0 ; We're not halted anymore!\n"); + fprintf(fp, " mov al, [_z80iff] ; Get our IFF setting\n"); + fprintf(fp, " and al, IFF1 ; Just IFF 1\n"); + fprintf(fp, " shl al, 1 ; Makes IFF1->IFF2 and zeros IFF1\n"); + fprintf(fp, " mov [_z80iff], al ; Store it back to the interrupt state!\n"); + fprintf(fp, "\n"); + fprintf(fp, " push ebp\n"); + fprintf(fp, " push edi\n"); + fprintf(fp, " mov ebp, [_z80Base]\n"); + fprintf(fp, "\n"); + + fprintf(fp, " xor eax, eax\n"); + fprintf(fp, " mov ax, [_z80pc]\n"); + + if (bThroughCallHandler) + { + fprintf(fp, " push esi\n"); + fprintf(fp, " push ebx\n"); + fprintf(fp, " push ecx\n"); + + fprintf(fp, " mov [_wordval], ax\n"); + fprintf(fp, " mov esi, ebp\n"); + fprintf(fp, " add esi, eax\n"); + fprintf(fp, " mov ax, [_z80af]\n"); // Get AF + fprintf(fp, " mov bx, [_z80hl]\n"); // Get HL + fprintf(fp, " mov cx, [_z80bc]\n"); // Get BC + fprintf(fp, " push ebx\n"); + fprintf(fp, " push ecx\n"); + fprintf(fp, " push edx\n"); + fprintf(fp, " push esi\n"); + fprintf(fp, " push eax\n"); + fprintf(fp, " call PushWord\n"); + fprintf(fp, " pop eax\n"); + fprintf(fp, " pop esi\n"); + fprintf(fp, " pop edx\n"); + fprintf(fp, " pop ecx\n"); + fprintf(fp, " pop ebx\n"); + + fprintf(fp, " pop ecx\n"); + fprintf(fp, " pop ebx\n"); + fprintf(fp, " pop esi\n"); + } + else + { + fprintf(fp, " xor edi, edi\n"); + fprintf(fp, " mov di, word [_z80sp]\n"); + fprintf(fp, " sub di, 2\n"); + fprintf(fp, " mov word [_z80sp], di\n"); + fprintf(fp, " mov [ebp+edi], ax\n"); + } + + fprintf(fp, " mov ax, [_z80nmiAddr]\n"); + fprintf(fp, " mov [_z80pc], ax\n"); + fprintf(fp, "\n"); + fprintf(fp, " add [dwElapsedTicks], dword 11 ; 11 T-States for NMI\n"); + fprintf(fp, " add [_z80rCounter], dword 11\n"); + fprintf(fp, " pop edi\n"); + fprintf(fp, " pop ebp\n"); + fprintf(fp, "\n"); + fprintf(fp, " xor eax, eax ; Indicate we took the interrupt\n"); + fprintf(fp, " ret\n"); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, "/* NMI Handler */\n\n"); + fprintf(fp, "UINT32 %snmi(void)\n", cpubasename); + fprintf(fp, "{\n"); + + fprintf(fp, " cpu.z80halted = 0;\n"); + fprintf(fp, " pbSP = (cpu.z80Base + cpu.z80sp - 1); /* Normalize the stack pointer */\n"); + fprintf(fp, " *pbSP-- = cpu.z80pc >> 8; /* LSB */\n"); + fprintf(fp, " *pbSP = (UINT8) cpu.z80pc; /* MSB */\n"); + fprintf(fp, " cpu.z80sp -= 2; /* Back our stack up */\n"); + fprintf(fp, " cpu.z80pc = cpu.z80nmiAddr; /* Our NMI */\n"); + + fprintf(fp, " return(0);\n"); + fprintf(fp, "}\n\n"); + } + else + { + assert(0); + } +} + +IntCode() +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp, " global _%sint\n", cpubasename); + fprintf(fp, " global %sint_\n", cpubasename); + + if (bPlain) + fprintf(fp, " global %sint\n", cpubasename); + + sprintf(procname, "%sint_", cpubasename); + ProcBegin(0xffffffff); + fprintf(fp, "_%sint:\n", cpubasename); + + if (bPlain) + fprintf(fp, "%sint:\n", cpubasename); + + if (bUseStack) + fprintf(fp, " mov eax, [esp+4] ; Get our (potential) lower interrupt address\n"); + + fprintf(fp, " mov dword [_z80halted], 0 ; We're not halted anymore!\n"); + + fprintf(fp, " mov ah, IFF1 ; Is IFF1 enabled?\n"); + fprintf(fp, " and ah, [_z80iff] ; Well, is it?\n"); + fprintf(fp, " jz near interruptsDisabled\n"); + + fprintf(fp, "\n; Interrupts enabled. Clear IFF1 and IFF2\n\n"); + + fprintf(fp, " and dword [_z80iff], ~(IFF1 | IFF2);\n\n"); + fprintf(fp, " mov [_z80intPending], byte 0\n"); + + fprintf(fp, "\n"); + fprintf(fp, " push ebp\n"); + fprintf(fp, " push edi\n"); + fprintf(fp, " push edx\n"); + fprintf(fp, " mov ebp, [_z80Base]\n"); + fprintf(fp, "\n"); + + + if (bThroughCallHandler) + { + fprintf(fp, " pushad\n" ); + fprintf(fp, " xor edx, edx\n" ); + fprintf(fp, " mov ax, [_z80pc]\n"); + fprintf(fp, " mov [_wordval], ax\n"); + fprintf(fp, " push ecx\n"); + fprintf(fp, " push ebx\n"); + fprintf(fp, " push esi\n"); + + fprintf(fp, " mov ax, [_z80af]\n"); // Get AF + fprintf(fp, " mov bx, [_z80hl]\n"); // Get HL + fprintf(fp, " mov cx, [_z80bc]\n"); // Get BC + fprintf(fp, " call PushWord\n"); + + fprintf(fp, " pop esi\n"); + fprintf(fp, " pop ebx\n"); + fprintf(fp, " pop ecx\n"); + fprintf(fp, " popad\n" ); + } + else + { + fprintf(fp, " mov dx, [_z80pc]\n"); + fprintf(fp, " xor edi, edi\n"); + fprintf(fp, " mov di, word [_z80sp]\n"); + fprintf(fp, " sub di, 2\n"); + fprintf(fp, " mov word [_z80sp], di\n"); + fprintf(fp, " mov [ebp+edi], dx\n"); + } + + fprintf(fp, " cmp dword [_z80interruptMode], 2 ; Are we lower than mode 2?\n"); + fprintf(fp, " jb justModeTwo\n"); + fprintf(fp, " mov ah, [_z80i] ; Get our high address here\n"); + fprintf(fp, " and eax, 0ffffh ; Only the lower part\n"); + fprintf(fp, " mov ax, [eax+ebp] ; Get our vector\n"); + fprintf(fp, " jmp short setNewVector ; Go set it!\n"); + fprintf(fp, "justModeTwo:\n"); + fprintf(fp, " mov ax, word [_z80intAddr]\n"); + fprintf(fp, "setNewVector:\n"); + fprintf(fp, " mov [_z80pc], ax\n"); + fprintf(fp, "\n"); + fprintf(fp, " pop edx\n"); + fprintf(fp, " pop edi\n"); + fprintf(fp, " pop ebp\n"); + fprintf(fp, "\n"); + fprintf(fp, " xor eax, eax ; Zero this so we can use it as an index\n"); + + fprintf(fp, " mov al, [_z80interruptMode]\n"); + fprintf(fp, " mov al, [intModeTStates+eax]\n"); + fprintf(fp, " add [dwElapsedTicks], eax\n"); + fprintf(fp, " add [_z80rCounter], eax\n"); + fprintf(fp, " xor eax, eax ; Indicate we took the interrupt\n"); + + fprintf(fp, " jmp short z80intExit\n"); + fprintf(fp, "\n"); + fprintf(fp, "interruptsDisabled:\n"); + fprintf(fp, " mov [_z80intPending], byte 1\n"); + fprintf(fp, " mov [_intData], al ; Save this info for later\n"); + fprintf(fp, " mov eax, 0ffffffffh ; Indicate we didn't take it\n"); + fprintf(fp, "\n"); + fprintf(fp, "z80intExit:\n"); + fprintf(fp, " ret\n\n"); + + + fprintf(fp, " global _%sClearPendingInterrupt\n", cpubasename); + fprintf(fp, " global %sClearPendingInterrupt_\n", cpubasename); + + if (bPlain) + fprintf(fp, " global %sClearPendingInterrupt\n", cpubasename); + + sprintf(procname, "%sClearPendingInterrupt_", cpubasename); + ProcBegin(0xffffffff); + fprintf(fp, "_%sClearPendingInterrupt:\n", cpubasename); + + if (bPlain) + fprintf(fp, "%sClearPendingInterrupt:\n", cpubasename); + + fprintf(fp, " mov [_z80intPending], byte 0\n"); + fprintf(fp, " ret\n\n"); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, "/* Interrupt handler */\n\n"); + fprintf(fp, "UINT32 %sint(UINT32 dwLowAddr)\n", cpubasename); + fprintf(fp, "{\n"); + fprintf(fp, " cpu.z80halted = 0;\n"); + + fprintf(fp, " if (0 == (cpu.z80iff & IFF1))\n"); + fprintf(fp, " return(0xffffffff);\n"); + + fprintf(fp, " cpu.z80iff &= ~(IFF1 | IFF2);\n"); + fprintf(fp, " pbSP = (cpu.z80Base + cpu.z80sp - 1); /* Normalize the stack pointer */\n"); + fprintf(fp, " *pbSP-- = cpu.z80pc >> 8; /* LSB */\n"); + fprintf(fp, " *pbSP = (UINT8) cpu.z80pc; /* MSB */\n"); + fprintf(fp, " cpu.z80sp -= 2; /* Back our stack up */\n"); + + fprintf(fp, " if (2 == cpu.z80interruptMode)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " cpu.z80pc = ((UINT16) cpu.z80i << 8) | (dwLowAddr & 0xff);\n"); + fprintf(fp, " cpu.z80pc = ((UINT16) cpu.z80Base[cpu.z80pc + 1] << 8) | (cpu.z80Base[cpu.z80pc]);\n"); + fprintf(fp, " }\n"); + fprintf(fp, " else\n"); + fprintf(fp, " {\n"); + fprintf(fp, " cpu.z80pc = cpu.z80intAddr;\n"); + fprintf(fp, " }\n"); + + fprintf(fp, " pbPC = cpu.z80Base + cpu.z80pc; /* Normalize the address */\n"); + + fprintf(fp, " return(0);\n"); + fprintf(fp, "}\n\n"); + } + else + { + assert(0); + } +} + +ResetCode() +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp, " global _%sreset\n", cpubasename); + fprintf(fp, " global %sreset_\n", cpubasename); + + if (bPlain) + fprintf(fp, " global %sreset\n", cpubasename); + sprintf(procname, "%sreset_", cpubasename); + ProcBegin(0xffffffff); + + fprintf(fp, "_%sreset:\n", cpubasename); + + if (bPlain) + fprintf(fp, "%sreset:\n", cpubasename); + + fprintf(fp, " xor eax, eax ; Zero AX\n"); + fprintf(fp, "\n"); + fprintf(fp, " mov dword [_z80halted], eax ; We're not halted anymore!\n"); + fprintf(fp, " mov word [_z80af], 0040h ; Zero A & flags - zero flag set\n"); + fprintf(fp, " mov word [_z80bc], ax ; Zero BC\n"); + fprintf(fp, " mov word [_z80de], ax ; Zero DE\n"); + fprintf(fp, " mov word [_z80hl], ax ; Zero HL\n"); + fprintf(fp, " mov word [_z80afprime], ax ; Zero AF Prime\n"); + fprintf(fp, " mov word [_z80bcprime], ax ; Zero BC prime\n"); + fprintf(fp, " mov word [_z80deprime], ax ; Zero DE prime\n"); + fprintf(fp, " mov word [_z80hlprime], ax ; Zero HL prime\n"); + fprintf(fp, " mov byte [_z80i], al ; Zero Interrupt register\n"); + fprintf(fp, " mov byte [_z80r], al ; Zero refresh register\n"); + fprintf(fp, " mov word [_z80ix], 0ffffh ; Default mz80Index register\n"); + fprintf(fp, " mov word [_z80iy], 0ffffh ; Default mz80Index register\n"); + fprintf(fp, " mov word [_z80pc], ax ; Zero program counter\n"); + fprintf(fp, " mov word [_z80sp], ax ; And the stack pointer\n"); + fprintf(fp, " mov dword [_z80iff], eax ; IFF1/IFF2 disabled!\n"); + fprintf(fp, " mov dword [_z80interruptMode], eax ; Clear our interrupt mode (0)\n"); + fprintf(fp, " mov word [_z80intAddr], 38h ; Set default interrupt address\n"); + fprintf(fp, " mov word [_z80nmiAddr], 66h ; Set default nmi addr\n"); + fprintf(fp, "\n"); + fprintf(fp, " ret\n"); + fprintf(fp, "\n"); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, "/* This routine is mz80's reset handler */\n\n"); + fprintf(fp, "void %sreset(void)\n", cpubasename); + fprintf(fp, "{\n"); + fprintf(fp, " cpu.z80halted = 0;\n"); + fprintf(fp, " cpu.z80AF = 0;\n"); + fprintf(fp, " cpu.z80F = Z80_FLAG_ZERO;\n"); + fprintf(fp, " cpu.z80BC = 0;\n"); + fprintf(fp, " cpu.z80DE = 0;\n"); + fprintf(fp, " cpu.z80HL = 0;\n"); + fprintf(fp, " cpu.z80afprime = 0;\n"); + fprintf(fp, " cpu.z80bcprime = 0;\n"); + fprintf(fp, " cpu.z80deprime = 0;\n"); + fprintf(fp, " cpu.z80hlprime = 0;\n"); + fprintf(fp, " cpu.z80i = 0;\n"); + fprintf(fp, " cpu.z80r = 0;\n"); + fprintf(fp, " cpu.z80IX = 0xffff; /* Yes, this is intentional */\n"); + fprintf(fp, " cpu.z80IY = 0xffff; /* Yes, this is intentional */\n"); + fprintf(fp, " cpu.z80pc = 0;\n"); + fprintf(fp, " cpu.z80sp = 0;\n"); + fprintf(fp, " cpu.z80interruptMode = 0;\n"); + fprintf(fp, " cpu.z80intAddr = 0x38;\n"); + fprintf(fp, " cpu.z80nmiAddr = 0x66;\n"); + fprintf(fp, "}\n\n"); + } + else + { + assert(0); + } +} + +SetContextCode() +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp, " global _%sSetContext\n", cpubasename); + fprintf(fp, " global %sSetContext_\n", cpubasename); + + if (bPlain) + fprintf(fp, " global %sSetContext\n", cpubasename); + + sprintf(procname, "%sSetContext_", cpubasename); + ProcBegin(0xffffffff); + fprintf(fp, "_%sSetContext:\n", cpubasename); + + if (bPlain) + fprintf(fp, "%sSetContext:\n", cpubasename); + + if (bUseStack) + fprintf(fp, " mov eax, [esp+4] ; Get our context address\n"); + + fprintf(fp, " push esi ; Save registers we use\n"); + fprintf(fp, " push edi\n"); + fprintf(fp, " push ecx\n"); + fprintf(fp, " push es\n"); + fprintf(fp, " mov di, ds\n"); + fprintf(fp, " mov es, di\n"); + fprintf(fp, " mov edi, _%scontextBegin\n", cpubasename); + fprintf(fp, " mov esi, eax ; Source address in ESI\n"); + fprintf(fp, " mov ecx, (_%scontextEnd - _%scontextBegin) >> 2\n", cpubasename, cpubasename); + fprintf(fp, " rep movsd\n"); + fprintf(fp, " mov ecx, (_%scontextEnd - _%scontextBegin) & 0x03\n", cpubasename, cpubasename); + fprintf(fp, " rep movsb\n"); + fprintf(fp, " pop es\n"); + fprintf(fp, " pop ecx\n"); + fprintf(fp, " pop edi\n"); + fprintf(fp, " pop esi\n"); + fprintf(fp, " ret ; No return code\n"); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, "/* Set mz80's context */\n\n"); + fprintf(fp, "void %sSetContext(void *pData)\n", cpubasename); + fprintf(fp, "{\n"); + fprintf(fp, " memcpy(&cpu, pData, sizeof(CONTEXTMZ80));\n"); + fprintf(fp, "}\n\n"); + } + else + { + assert(0); + } +} + +GetContextCode() +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp, " global _%sGetContext\n", cpubasename); + fprintf(fp, " global %sGetContext_\n", cpubasename); + + if (bPlain) + fprintf(fp, " global %sGetContext\n", cpubasename); + + sprintf(procname, "%sGetContext_", cpubasename); + ProcBegin(0xffffffff); + fprintf(fp, "_%sGetContext:\n", cpubasename); + + if (bPlain) + fprintf(fp, "%sGetContext:\n", cpubasename); + + if (bUseStack) + fprintf(fp, " mov eax, [esp+4] ; Get our context address\n"); + + fprintf(fp, " push esi ; Save registers we use\n"); + fprintf(fp, " push edi\n"); + fprintf(fp, " push ecx\n"); + fprintf(fp, " push es\n"); + fprintf(fp, " mov di, ds\n"); + fprintf(fp, " mov es, di\n"); + + fprintf(fp, " mov esi, _%scontextBegin\n", cpubasename); + fprintf(fp, " mov edi, eax ; Source address in ESI\n"); + + fprintf(fp, " mov ecx, (_%scontextEnd - _%scontextBegin) >> 2\n", cpubasename, cpubasename); + fprintf(fp, " rep movsd\n"); + fprintf(fp, " mov ecx, (_%scontextEnd - _%scontextBegin) & 0x03\n", cpubasename, cpubasename); + fprintf(fp, " rep movsb\n"); + + fprintf(fp, " pop es\n"); + fprintf(fp, " pop ecx\n"); + fprintf(fp, " pop edi\n"); + fprintf(fp, " pop esi\n"); + fprintf(fp, " ret ; No return code\n"); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, "/* Get mz80's context */\n\n"); + fprintf(fp, "void %sGetContext(void *pData)\n", cpubasename); + fprintf(fp, "{\n"); + fprintf(fp, " memcpy(pData, &cpu, sizeof(CONTEXTMZ80));\n"); + fprintf(fp, "}\n\n"); + } + else + { + assert(0); + } +} + +GetContextSizeCode() +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp, " global _%sGetContextSize\n", cpubasename); + fprintf(fp, " global %sGetContextSize_\n", cpubasename); + + if (bPlain) + fprintf(fp, " global %sGetContextSize\n", cpubasename); + + sprintf(procname, "%sGetContextSize_", cpubasename); + ProcBegin(0xffffffff); + + fprintf(fp, "_%sGetContextSize:\n", cpubasename); + + if (bPlain) + fprintf(fp, "%sGetContextSize:\n", cpubasename); + + fprintf(fp, " mov eax, _%scontextEnd - _%scontextBegin\n", cpubasename, cpubasename); + fprintf(fp, " ret\n\n"); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, "/* Get mz80's context size */\n\n"); + fprintf(fp, "UINT32 %sGetContextSize(void)\n", cpubasename); + fprintf(fp, "{\n"); + fprintf(fp, " return(sizeof(CONTEXTMZ80));\n"); + fprintf(fp, "}\n\n"); + } + else + { + assert(0); + } +} + +void InitCode(void) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp, " global _%sinit\n", cpubasename); + fprintf(fp, " global %sinit_\n", cpubasename); + + if (bPlain) + fprintf(fp, " global %sinit\n", cpubasename); + + sprintf(procname, "%sinit_", cpubasename); + ProcBegin(0xffffffff); + + fprintf(fp, "_%sinit:\n", cpubasename); + + if (bPlain) + fprintf(fp, "%sinit:\n", cpubasename); + + fprintf(fp, " ret\n\n"); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, "/* Initialize MZ80 for action */\n\n"); + fprintf(fp, "void %sinit(void)\n", cpubasename); + fprintf(fp, "{\n"); + + fprintf(fp, " UINT32 dwLoop;\n"); + fprintf(fp, " UINT8 *pbTempPtr;\n"); + fprintf(fp, " UINT8 *pbTempPtr2;\n"); + fprintf(fp, " UINT8 bNewAdd;\n"); + fprintf(fp, " UINT8 bNewSub;\n"); + fprintf(fp, " UINT8 bFlag;\n"); + fprintf(fp, " UINT8 bLow;\n"); + fprintf(fp, " UINT8 bHigh;\n"); + fprintf(fp, " UINT8 bCarry;\n"); + fprintf(fp, "\n"); + fprintf(fp, " if (NULL == pbAddAdcTable)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " pbAddAdcTable = malloc(256*256*2);\n"); + fprintf(fp, "\n"); + fprintf(fp, " if (NULL == pbAddAdcTable)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " return;\n"); + fprintf(fp, " }\n"); + fprintf(fp, "\n"); + fprintf(fp, " pbTempPtr = pbAddAdcTable;\n\n"); + fprintf(fp, " pbSubSbcTable = malloc(256*256*2);\n"); + fprintf(fp, "\n"); + fprintf(fp, " if (NULL == pbSubSbcTable)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " return;\n"); + fprintf(fp, " }\n"); + fprintf(fp, "\n"); + fprintf(fp, " pbTempPtr2 = pbSubSbcTable;\n"); + fprintf(fp, "\n"); + fprintf(fp, " for (dwLoop = 0; dwLoop < (256*256*2); dwLoop++)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " bLow = dwLoop & 0xff;\n"); + fprintf(fp, " bHigh = (dwLoop >> 8) & 0xff;\n"); + fprintf(fp, " bCarry = (dwLoop >> 16);\n"); + fprintf(fp, "\n"); + fprintf(fp, " bFlag = 0;\n"); + fprintf(fp, " bNewAdd = bHigh + bLow + bCarry;\n"); + fprintf(fp, "\n"); + fprintf(fp, " if (0 == bNewAdd)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " bFlag |= Z80_FLAG_ZERO;\n"); + fprintf(fp, " }\n"); + fprintf(fp, " else\n"); + fprintf(fp, " {\n"); + fprintf(fp, " bFlag = bNewAdd & 0x80; /* Sign flag */\n"); + fprintf(fp, " }\n"); + fprintf(fp, "\n"); + fprintf(fp, " if (((UINT32) bLow + (UINT32) bHigh + (UINT32) bCarry) >= 0x100)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " bFlag |= Z80_FLAG_CARRY;\n"); + fprintf(fp, " }\n"); + fprintf(fp, "\n"); + fprintf(fp, " if ( ((bLow ^ bHigh ^ 0x80) & (bLow ^ (bNewAdd & 0x80))) & 0x80)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " bFlag |= Z80_FLAG_OVERFLOW_PARITY;\n"); + fprintf(fp, " }\n"); + fprintf(fp, "\n"); + fprintf(fp, " if (((bLow & 0x0f) + (bHigh & 0x0f) + bCarry) >= 0x10)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " bFlag |= Z80_FLAG_HALF_CARRY;\n"); + fprintf(fp, " }\n"); + fprintf(fp, "\n"); + fprintf(fp, " *pbTempPtr++ = bFlag; /* Store our new flag */\n\n"); + + fprintf(fp, " // Now do subtract - Zero\n"); + fprintf(fp, "\n"); + fprintf(fp, " bFlag = Z80_FLAG_NEGATIVE;\n"); + fprintf(fp, " bNewSub = bHigh - bLow - bCarry;\n"); + fprintf(fp, "\n"); + fprintf(fp, " if (0 == bNewSub)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " bFlag |= Z80_FLAG_ZERO;\n"); + fprintf(fp, " }\n"); + fprintf(fp, " else\n"); + fprintf(fp, " {\n"); + fprintf(fp, " bFlag |= bNewSub & 0x80; /* Sign flag */\n"); + fprintf(fp, " }\n"); + fprintf(fp, "\n"); + fprintf(fp, " if ( ((INT32) bHigh - (INT32) bLow - (INT32) bCarry) < 0)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " bFlag |= Z80_FLAG_CARRY;\n"); + fprintf(fp, " }\n"); + fprintf(fp, "\n"); + fprintf(fp, " if ( ((INT32) (bHigh & 0xf) - (INT32) (bLow & 0x0f) - (INT32) bCarry) < 0)\n"); + fprintf(fp, " {\n"); + fprintf(fp, " bFlag |= Z80_FLAG_HALF_CARRY;\n"); + fprintf(fp, " }\n"); + fprintf(fp, "\n"); + fprintf(fp, " if ( ((bLow ^ bHigh) & (bHigh ^ bNewSub) & 0x80) )\n"); + fprintf(fp, " {\n"); + fprintf(fp, " bFlag |= Z80_FLAG_OVERFLOW_PARITY;\n"); + fprintf(fp, " }\n"); + fprintf(fp, "\n"); + fprintf(fp, " *pbTempPtr2++ = bFlag; /* Store our sub flag */\n"); + fprintf(fp, "\n"); + fprintf(fp, " }\n"); + fprintf(fp, " }\n"); + fprintf(fp, "}\n"); + } + else + { + assert(0); + } +} + +void ShutdownCode(void) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + fprintf(fp, " global _%sshutdown\n", cpubasename); + fprintf(fp, " global %sshutdown_\n", cpubasename); + + if (bPlain) + fprintf(fp, " global %sshutdown\n", cpubasename); + + sprintf(procname, "%sshutdown_", cpubasename); + ProcBegin(0xffffffff); + + fprintf(fp, "_%sshutdown:\n", cpubasename); + + if (bPlain) + fprintf(fp, "%sshutdown:\n", cpubasename); + + fprintf(fp, " ret\n\n"); + } + else + if (MZ80_C == bWhat) + { + fprintf(fp, "/* Shut down MZ80 */\n\n"); + fprintf(fp, "void %sshutdown(void)\n", cpubasename); + fprintf(fp, "{\n"); + + fprintf(fp, "}\n\n"); + } + else + { + assert(0); + } +} + +void DebuggerCode(void) +{ + if (MZ80_ASSEMBLY_X86 == bWhat) + { + Alignment(); + + fprintf(fp, ";\n"); + fprintf(fp, "; In : EAX=Reg #, ESI=Context address\n"); + fprintf(fp, "; Out: EAX=Value of register\n"); + fprintf(fp, ";\n"); + + fprintf(fp, "getRegValueInternal:\n"); + + fprintf(fp, " push ecx\n"); + fprintf(fp, " push edx\n\n"); + + fprintf(fp, " cmp eax, CPUREG_MAXINDEX\n"); + fprintf(fp, " jae badIndex2\n\n"); + + fprintf(fp, " shl eax, 4 ; Times 16 for table entry size\n"); + fprintf(fp, " add eax, RegTable ; Now it's the memory location\n"); + + fprintf(fp, " mov edx, [eax+4] ; Get the offset of the register\n"); + fprintf(fp, " mov edx, [edx + esi] ; Get our value\n"); + + fprintf(fp, " mov ecx, [eax+8] ; Get our shift value\n"); + fprintf(fp, " shr edx, cl ; Shift it right by a value\n"); + + fprintf(fp, " and edx, [eax+12] ; Mask off any unneeded bits\n"); + fprintf(fp, " mov eax, edx ; Put our value in EAX\n"); + fprintf(fp, " jmp short indexExit ; Index's exit!\n"); + + fprintf(fp, "badIndex2:\n"); + fprintf(fp, " mov eax, 0ffffffffh\n\n"); + fprintf(fp, "indexExit:\n"); + fprintf(fp, " pop edx\n"); + fprintf(fp, " pop ecx\n"); + fprintf(fp, " ret\n\n"); + + Alignment(); + + fprintf(fp, ";\n"); + fprintf(fp, "; In : EAX=Value, EDX=Reg #, ESI=Context address\n"); + fprintf(fp, "; Out: EAX=Value of register\n"); + fprintf(fp, ";\n"); + + fprintf(fp, "convertValueToText:\n"); + + fprintf(fp, " push ecx\n"); + fprintf(fp, " push edx\n\n"); + + fprintf(fp, " cmp edx, CPUREG_MAXINDEX\n"); + fprintf(fp, " jae badIndex3\n\n"); + + fprintf(fp, " shl edx, 4 ; Times 16 for table entry size\n"); + fprintf(fp, " add edx, RegTable ; Now it's the memory location\n"); + fprintf(fp, " mov edx, [edx + 12] ; Shift mask\n"); + fprintf(fp, " xor ecx, ecx ; Zero our shift\n"); + + fprintf(fp, "shiftLoop:\n"); + fprintf(fp, " test edx, 0f0000000h ; High nibble nonzero yet?\n"); + fprintf(fp, " jnz convertLoop ; Yup!\n"); + fprintf(fp, " shl edx, 4 ; Move over, bacon\n"); + fprintf(fp, " shl eax, 4 ; Move the value over, too\n"); + fprintf(fp, " jmp short shiftLoop ; Keep shiftin'\n\n"); + + fprintf(fp, "convertLoop:\n"); + fprintf(fp, " mov ecx, eax ; Get our value\n"); + fprintf(fp, " shr ecx, 28 ; Only the top nibble\n"); + fprintf(fp, " add cl, '0' ; Convert to ASCII\n"); + fprintf(fp, " cmp cl, '9' ; Greater than 9?\n"); + fprintf(fp, " jbe noAdd ; Nope! Don't add it\n"); + fprintf(fp, " add cl, 32+7 ; Convert from lowercase a-f\n"); + fprintf(fp, "noAdd:\n"); + fprintf(fp, " mov [edi], cl ; New value storage\n"); + fprintf(fp, " inc edi ; Next byte, please\n"); + fprintf(fp, " shl eax, 4 ; Move the mask over\n"); + fprintf(fp, " shl edx, 4 ; Move the mask over\n"); + fprintf(fp, " jnz convertLoop ; Keep convertin'\n\n"); + + + fprintf(fp, "badIndex3:\n"); + fprintf(fp, " mov [edi], byte 0 ; Null terminate the sucker!\n"); + fprintf(fp, " pop edx\n"); + fprintf(fp, " pop ecx\n"); + fprintf(fp, " ret\n\n"); + + fprintf(fp, " global _%sSetRegisterValue\n", cpubasename); + fprintf(fp, " global %sSetRegisterValue_\n", cpubasename); + + if (bPlain) + fprintf(fp, " global %sSetRegisterValue\n", cpubasename); + + sprintf(procname, "%sSetRegisterValue_", cpubasename); + ProcBegin(0xffffffff); + + fprintf(fp, "_%sSetRegisterValue:\n", cpubasename); + if (bPlain) + fprintf(fp, "%sSetRegisterValue:\n", cpubasename); + + fprintf(fp, " push esi\n"); + fprintf(fp, " push edi\n"); + fprintf(fp, " push edx\n"); + fprintf(fp, " push ecx\n"); + + if (bUseStack) + { + fprintf(fp, " mov eax, [esp+20] ; Get our register #\n"); + fprintf(fp, " mov esi, [esp+24] ; Get our context address\n"); + fprintf(fp, " mov edi, [esp+28] ; Value to assign\n"); + } + else + { + fprintf(fp, " mov esi, eax ; Get context\n"); + fprintf(fp, " mov eax, edx ; Get register # in EAX\n"); + fprintf(fp, " mov edi, ebx ; Get value to assign\n"); + } + + fprintf(fp, " or esi, esi ; Are we NULL?\n"); + fprintf(fp, " jnz userDefined\n"); + + fprintf(fp, " mov esi, _%scontextBegin\n", cpubasename); + fprintf(fp, "userDefined:\n\n"); + fprintf(fp, " shl eax, 4 ; Times 16 for reg entry size\n"); + fprintf(fp, " add eax, RegTable\n"); + fprintf(fp, " mov edx, [eax+12] ; Our mask\n"); + fprintf(fp, " not edx ; Invert EDX!\n"); + fprintf(fp, " test edi, edx ; Did we set any invalid bits?\n"); + fprintf(fp, " jnz rangeViolation\n\n"); + + fprintf(fp, " not edx ; Toggle it back to normal\n"); + fprintf(fp, " mov ecx, [eax+8] ; Get our shift value\n"); + fprintf(fp, " shl edx, cl ; Shift our mask\n"); + fprintf(fp, " shl eax, cl ; And our value to OR in\n"); + + fprintf(fp, " not edx ; Make it the inverse of what we want\n"); + fprintf(fp, " mov eax, [eax+4] ; Get our offset into the context\n"); + fprintf(fp, " and [esi+eax], edx ; Mask off the bits we're changin\n"); + fprintf(fp, " or [esi+eax], edi ; Or in our new value\n\n"); + fprintf(fp, " xor eax, eax\n"); + fprintf(fp, " jmp short setExit\n\n"); + + fprintf(fp, "rangeViolation:\n"); + fprintf(fp, " mov eax, 0ffffffffh\n\n"); + + fprintf(fp, "setExit:\n"); + fprintf(fp, " pop ecx\n"); + fprintf(fp, " pop edx\n"); + fprintf(fp, " pop edi\n"); + fprintf(fp, " pop esi\n\n"); + + fprintf(fp, " ret\n\n"); + + Alignment(); + + fprintf(fp, " global _%sGetRegisterValue\n", cpubasename); + fprintf(fp, " global %sGetRegisterValue_\n", cpubasename); + + if (bPlain) + fprintf(fp, " global %sGetRegisterValue\n", cpubasename); + + sprintf(procname, "%sGetRegisterValue_", cpubasename); + ProcBegin(0xffffffff); + + fprintf(fp, "_%sGetRegisterValue:\n", cpubasename); + if (bPlain) + fprintf(fp, "%sGetRegisterValue:\n", cpubasename); + + fprintf(fp, " push esi\n"); + + if (bUseStack) + { + fprintf(fp, " mov eax, [esp+8] ; Get our register #\n"); + fprintf(fp, " mov esi, [esp+12] ; Get our context address\n"); + } + else + { + fprintf(fp, " mov esi, eax ; Get context\n"); + fprintf(fp, " mov eax, edx ; Get register # in EAX\n"); + } + + fprintf(fp, " or esi, esi ; Is context NULL?\n"); + fprintf(fp, " jnz getVal ; Nope - use it!\n"); + fprintf(fp, " mov esi, _%scontextBegin\n\n", cpubasename); + + fprintf(fp, "getVal:\n"); + fprintf(fp, " call getRegValueInternal\n\n"); + + fprintf(fp, " pop esi\n"); + + fprintf(fp, " ret\n\n"); + + Alignment(); + + fprintf(fp, " global _%sGetRegisterName\n", cpubasename); + fprintf(fp, " global %sGetRegisterName_\n", cpubasename); + + if (bPlain) + fprintf(fp, " global %sGetRegisterName\n", cpubasename); + + sprintf(procname, "%sGetRegisterName_", cpubasename); + ProcBegin(0xffffffff); + + fprintf(fp, "_%sGetRegisterName:\n", cpubasename); + if (bPlain) + fprintf(fp, "%sGetRegisterName:\n", cpubasename); + + if (bUseStack) + { + fprintf(fp, " mov eax, [esp+4] ; Get our register #\n"); + } + + fprintf(fp, " cmp eax, CPUREG_MAXINDEX\n"); + fprintf(fp, " jae badIndex\n"); + + fprintf(fp, " shl eax, 4 ; Times 16 bytes for each entry\n"); + fprintf(fp, " mov eax, [eax+RegTable]\n"); + fprintf(fp, " jmp nameExit\n\n"); + + fprintf(fp, "badIndex:\n"); + fprintf(fp, " xor eax, eax\n\n"); + + fprintf(fp, "nameExit:\n"); + fprintf(fp, " ret\n\n"); + + Alignment(); + + fprintf(fp, " global _%sGetRegisterTextValue\n", cpubasename); + fprintf(fp, " global %sGetRegisterTextValue_\n", cpubasename); + + if (bPlain) + fprintf(fp, " global %sGetRegisterTextValue\n", cpubasename); + + sprintf(procname, "%sGetRegisterTextValue_", cpubasename); + ProcBegin(0xffffffff); + + fprintf(fp, "_%sGetRegisterTextValue:\n", cpubasename); + if (bPlain) + fprintf(fp, "%sGetRegisterTextValue:\n", cpubasename); + + fprintf(fp, " push esi\n"); + fprintf(fp, " push edi\n"); + fprintf(fp, " push edx\n"); + + if (bUseStack) + { + fprintf(fp, " mov eax, [esp+16] ; Get our register #\n"); + fprintf(fp, " mov esi, [esp+20] ; Get our context address\n"); + fprintf(fp, " mov edi, [esp+24] ; Address to place text\n"); + } + else + { + fprintf(fp, " mov esi, eax ; Get context\n"); + fprintf(fp, " mov eax, edx ; Get register # in EAX\n"); + fprintf(fp, " mov edi, ebx ; Address to place text\n"); + } + + fprintf(fp, " or esi, esi ; Is context NULL?\n"); + fprintf(fp, " jnz getVal2 ; Nope - use it!\n"); + fprintf(fp, " mov esi, _%scontextBegin\n\n", cpubasename); + + fprintf(fp, "getVal2:\n"); + fprintf(fp, " mov edx, eax ; Save off our index for later\n"); + fprintf(fp, " call getRegValueInternal\n\n"); + + fprintf(fp, "; EAX Holds the value, EDX=Register #, and EDI=Destination!\n\n"); + + fprintf(fp, " call convertValueToText\n\n"); + + fprintf(fp, " pop edx\n"); + fprintf(fp, " pop esi\n"); + fprintf(fp, " pop edi\n"); + + fprintf(fp, " ret\n\n"); + + Alignment(); + + fprintf(fp, " global _%sWriteValue\n", cpubasename); + fprintf(fp, " global %sWriteValue_\n", cpubasename); + + if (bPlain) + fprintf(fp, " global %sWriteValue\n", cpubasename); + + sprintf(procname, "%sWriteValue_", cpubasename); + ProcBegin(0xffffffff); + + fprintf(fp, "_%sWriteValue:\n", cpubasename); + if (bPlain) + fprintf(fp, "%sWriteValue:\n", cpubasename); + + fprintf(fp, " push esi\n"); + fprintf(fp, " push edi\n"); + fprintf(fp, " push edx\n"); + fprintf(fp, " push ebx\n"); + fprintf(fp, " push ecx\n"); + fprintf(fp, " push ebp\n"); + + if (bUseStack) + { + fprintf(fp, " mov eax, [esp+28] ; What kind of write is this?\n"); + fprintf(fp, " mov ebx, [esp+32] ; Address\n"); + fprintf(fp, " mov edx, [esp+36] ; Value\n"); + } + else + { + fprintf(fp, " xchg edx, ebx ; Addr=EBX, value=EDX\n"); + } + + fprintf(fp, " cmp eax, 1 ; Is it a word write?\n"); + fprintf(fp, " je near invalidWrite ; Yep - it's not valid\n"); + fprintf(fp, " cmp eax, 2 ; Is it a dword write?\n"); + fprintf(fp, " je near invalidWrite ; Yep - it's not valid\n\n"); + fprintf(fp, " or eax, eax ; Is it a byte write?\n"); + fprintf(fp, " jnz itsIoDummy ; Nope... it's an I/O write\n\n"); + + // Here we do a write memory byte + + fprintf(fp, " mov ebp, [_z80Base] ; Base pointer comes back\n"); + fprintf(fp, " mov edi, [_z80MemWrite] ; Point to the write array\n"); + + fprintf(fp, "checkLoop:\n"); + fprintf(fp, " cmp [edi], word 0ffffh ; End of our list?\n"); + fprintf(fp, " je memoryWrite ; Yes - go write it!\n"); + fprintf(fp, " cmp bx, [edi] ; Are we smaller?\n"); + fprintf(fp, " jb nextAddr ; Yes... go to the next addr\n"); + fprintf(fp, " cmp bx, [edi+4] ; Are we smaller?\n"); + fprintf(fp, " jbe callRoutine ; If not, go call it!\n"); + + fprintf(fp, "nextAddr:\n"); + fprintf(fp, " add edi, 10h ; Next structure, please\n"); + fprintf(fp, " jmp short checkLoop\n"); + + fprintf(fp, "callRoutine:\n"); + + fprintf(fp, "\n;\n; EBX=Address to target, DL=Byte to write \n;\n\n"); + + fprintf(fp, " cmp [edi+8], dword 0 ; Null handler?\n"); + fprintf(fp, " je directWriteHandler2\n\n"); + + if (FALSE == bUseStack) + { + fprintf(fp, " mov eax, ebx ; Address\n"); + fprintf(fp, " mov ebx, edi ; Pointer to struct (EDX Already has the byte to write)\n"); + } + else + { + fprintf(fp, " push edi ; Handler\n"); + fprintf(fp, " push edx ; Byte\n"); + fprintf(fp, " push ebx ; Address\n"); + } + + fprintf(fp, " call dword [edi + 8] ; Go call our handler\n"); + + if (bUseStack) + { + fprintf(fp, " add esp, 12\n"); + } + + fprintf(fp, " jmp short itsGood\n"); + + fprintf(fp, "directWriteHandler2:\n"); + fprintf(fp, " sub ebx, [edi] ; Subtract our offset\n"); + fprintf(fp, " add ebx, [edi+12] ; Add in the base address\n"); + fprintf(fp, " mov [ebx], dl ; Store our byte\n"); + fprintf(fp, " jmp short itsGood\n"); + fprintf(fp, "memoryWrite:\n"); + fprintf(fp, " mov [ebp + ebx], dl\n\n"); + fprintf(fp, " jmp short itsGood\n"); + + // Here we do an "out" + + fprintf(fp, "itsIoDummy:\n"); + + fprintf(fp, " mov edi, [_z80IoWrite] ; Point to the I/O write array\n"); + + fprintf(fp, "IOCheck:\n"); + fprintf(fp, " cmp [edi], word 0ffffh ; End of our list?\n"); + fprintf(fp, " je itsGood ; Yes - ignore it!\n"); + fprintf(fp, " cmp bx, [edi] ; Are we smaller?\n"); + fprintf(fp, " jb nextIOAddr ; Yes... go to the next addr\n"); + fprintf(fp, " cmp bx, [edi+2] ; Are we bigger?\n"); + fprintf(fp, " jbe callIOHandler ; If not, go call it!\n"); + + fprintf(fp, "nextIOAddr:\n"); + fprintf(fp, " add edi, 0ch ; Next structure, please\n"); + fprintf(fp, " jmp short IOCheck\n"); + + fprintf(fp, "callIOHandler:\n"); + + if (FALSE == bUseStack) + { + fprintf(fp, " mov eax, ebx ; Address\n"); + fprintf(fp, " mov ebx, edi ; Pointer to struct (EDX Already has the byte to write)\n"); + } + else + { + fprintf(fp, " push edi ; Handler\n"); + fprintf(fp, " push edx ; Byte\n"); + fprintf(fp, " push ebx ; Address\n"); + } + + fprintf(fp, " call dword [edi+4] ; Call the handler!\n"); + + if (bUseStack) + fprintf(fp, " add esp, 12\n"); + + fprintf(fp, " jmp short itsGood\n\n"); + + // Errors and whatnot + + fprintf(fp, "invalidWrite:\n"); + fprintf(fp, " mov eax, 0ffffffffh\n"); + fprintf(fp, " jmp short writeValueExit\n\n"); + + fprintf(fp, "itsGood:\n"); + fprintf(fp, " xor eax, eax\n\n"); + + fprintf(fp, "writeValueExit:\n"); + + fprintf(fp, " pop ebp\n"); + fprintf(fp, " pop ecx\n"); + fprintf(fp, " pop ebx\n"); + fprintf(fp, " pop edx\n"); + fprintf(fp, " pop esi\n"); + fprintf(fp, " pop edi\n"); + + fprintf(fp, " ret\n\n"); + + Alignment(); + + fprintf(fp, " global _%sReadValue\n", cpubasename); + fprintf(fp, " global %sReadValue_\n", cpubasename); + + if (bPlain) + fprintf(fp, " global %sReadValue\n", cpubasename); + + sprintf(procname, "%sReadValue_", cpubasename); + ProcBegin(0xffffffff); + + fprintf(fp, "_%sReadValue:\n", cpubasename); + if (bPlain) + fprintf(fp, "%sReadValue:\n", cpubasename); + + fprintf(fp, " push esi\n"); + fprintf(fp, " push edi\n"); + fprintf(fp, " push edx\n"); + fprintf(fp, " push ebx\n"); + fprintf(fp, " push ecx\n"); + fprintf(fp, " push ebp\n"); + + if (bUseStack) + { + fprintf(fp, " mov eax, [esp+28] ; What kind of read is this?\n"); + fprintf(fp, " mov ebx, [esp+32] ; Address\n"); + } + else + { + fprintf(fp, " xchg edx, ebx ; Addr=EBX\n"); + } + + fprintf(fp, " cmp eax, 1 ; Is it a word read?\n"); + fprintf(fp, " je near invalidRead ; Yep - it's not valid\n"); + fprintf(fp, " cmp eax, 2 ; Is it a dword read?\n"); + fprintf(fp, " je near invalidRead ; Yep - it's not valid\n\n"); + fprintf(fp, " or eax, eax ; Is it a byte read?\n"); + fprintf(fp, " jnz itsIoDummyRead ; Nope... it's an I/O read\n\n"); + + // Here we do a read memory byte + + fprintf(fp, " mov ebp, [_z80Base] ; Base pointer comes back\n"); + fprintf(fp, " mov edi, [_z80MemRead] ; Point to the read array\n"); + + fprintf(fp, "checkLoopRead:\n"); + fprintf(fp, " cmp [edi], word 0ffffh ; End of our list?\n"); + fprintf(fp, " je memoryRead ; Yes - go read it!\n"); + fprintf(fp, " cmp bx, [edi] ; Are we smaller?\n"); + fprintf(fp, " jb nextAddrRead ; Yes... go to the next addr\n"); + fprintf(fp, " cmp bx, [edi+4] ; Are we smaller?\n"); + fprintf(fp, " jbe callRoutineRead ; If not, go call it!\n"); + + fprintf(fp, "nextAddrRead:\n"); + fprintf(fp, " add edi, 10h ; Next structure, please\n"); + fprintf(fp, " jmp short checkLoopRead\n"); + + fprintf(fp, "callRoutineRead:\n"); + + fprintf(fp, "\n;\n; EBX=Address to target\n;\n\n"); + + fprintf(fp, " cmp [edi+8], dword 0 ; NULL HAndler?\n"); + fprintf(fp, " je handleSharedRead\n\n"); + + if (FALSE == bUseStack) + { + fprintf(fp, " mov eax, ebx ; Address\n"); + fprintf(fp, " mov edx, edi ; Pointer to struct\n"); + } + else + { + fprintf(fp, " push edi ; Handler\n"); + fprintf(fp, " push ebx ; Address\n"); + } + + fprintf(fp, " call dword [edi + 8] ; Go call our handler\n"); + fprintf(fp, " mov dl, al ; Get our byte read\n"); + + if (bUseStack) + { + fprintf(fp, " add esp, 8\n"); + } + + fprintf(fp, " jmp short itsGoodRead\n\n"); + + fprintf(fp, "memoryRead:\n"); + fprintf(fp, " mov dl, [ebp+ebx]\n\n"); + fprintf(fp, " jmp short itsGoodRead\n\n"); + + fprintf(fp, "handleSharedRead:\n"); + fprintf(fp, " sub ebx, [edi]\n"); + fprintf(fp, " add ebx, [edi+12]\n"); + fprintf(fp, " mov dl, [ebx]\n"); + fprintf(fp, " jmp short itsGoodRead\n\n"); + + // Here we do an "out" + + fprintf(fp, "itsIoDummyRead:\n"); + + fprintf(fp, " mov edi, [_z80IoRead] ; Point to the I/O read array\n"); + fprintf(fp, " mov dl, 0ffh ; Assume no handler\n"); + + fprintf(fp, "IOCheckRead:\n"); + fprintf(fp, " cmp [edi], word 0ffffh ; End of our list?\n"); + fprintf(fp, " je itsGoodRead ; Yes - ignore it!\n"); + fprintf(fp, " cmp bx, [edi] ; Are we smaller?\n"); + fprintf(fp, " jb nextIOAddrRead ; Yes... go to the next addr\n"); + fprintf(fp, " cmp bx, [edi+2] ; Are we bigger?\n"); + fprintf(fp, " jbe callIOHandlerRead ; If not, go call it!\n"); + + fprintf(fp, "nextIOAddrRead:\n"); + fprintf(fp, " add edi, 0ch ; Next structure, please\n"); + fprintf(fp, " jmp short IOCheckRead\n"); + + fprintf(fp, "callIOHandlerRead:\n"); + + if (FALSE == bUseStack) + { + fprintf(fp, " mov eax, ebx ; Address\n"); + fprintf(fp, " mov edx, edi ; Pointer to struct (EDX Already has the byte to write)\n"); + } + else + { + fprintf(fp, " push edi ; Handler\n"); + fprintf(fp, " push ebx ; Address\n"); + } + + fprintf(fp, " call dword [edi+4] ; Call the handler!\n"); + fprintf(fp, " mov dl, al ; Get our byte read\n"); + + if (bUseStack) + fprintf(fp, " add esp, 8\n"); + + fprintf(fp, " jmp short itsGoodRead\n\n"); + + // Errors and whatnot + + fprintf(fp, "invalidRead:\n"); + fprintf(fp, " mov eax, 0ffffffffh\n"); + fprintf(fp, " jmp short ReadValueExit\n\n"); + + fprintf(fp, "itsGoodRead:\n"); + fprintf(fp, " xor eax, eax\n"); + fprintf(fp, " mov al, dl\n\n"); + + fprintf(fp, "ReadValueExit:\n"); + + fprintf(fp, " pop ebp\n"); + fprintf(fp, " pop ecx\n"); + fprintf(fp, " pop ebx\n"); + fprintf(fp, " pop edx\n"); + fprintf(fp, " pop esi\n"); + fprintf(fp, " pop edi\n"); + + fprintf(fp, " ret\n\n"); + + + + } + else + if (MZ80_C == bWhat) + { + } +} + + +EmitCode() +{ + CodeSegmentBegin(); + EmitCBInstructions(); + EmitEDInstructions(); + + if (MZ80_ASSEMBLY_X86 == bWhat) + strcpy(mz80Index, "ix"); + + else + { + strcpy(mz80Index, "cpu.z80IX"); + strcpy(mz80IndexHalfHigh, "cpu.z80XH"); + strcpy(mz80IndexHalfLow, "cpu.z80XL"); + } + + strcpy(majorOp, "DD"); + EmitDDInstructions(); + + if (MZ80_ASSEMBLY_X86 == bWhat) + strcpy(mz80Index, "iy"); + else + { + strcpy(mz80Index, "cpu.z80IY"); + strcpy(mz80IndexHalfHigh, "cpu.z80YH"); + strcpy(mz80IndexHalfLow, "cpu.z80YL"); + } + + strcpy(majorOp, "FD"); + EmitFDInstructions(); + majorOp[0] = '\0'; + EmitRegularInstructions(); + ReadMemoryByteHandler(); + WriteMemoryByteHandler(); + + if (bThroughCallHandler) + { + PushWordHandler(); + PopWordHandler(); + } + + ReadIoHandler(); + WriteIoHandler(); + GetContextCode(); + SetContextCode(); + GetContextSizeCode(); + GetTicksCode(); + ReleaseTimesliceCode(); + ResetCode(); + IntCode(); + NmiCode(); + ExecCode(); + InitCode(); + ShutdownCode(); + DebuggerCode(); + CodeSegmentEnd(); +} + +main(int argc, char **argv) +{ + UINT32 dwLoop = 0; + + printf("MakeZ80 - V%s - Copyright 1996-2000 Neil Bradley (neil@synthcom.com)\n", VERSION); + + if (argc < 2) + { + printf("Usage: %s outfile [option1] [option2] ....\n", argv[0]); + printf("\n -s - Stack calling conventions (DJGPP, MSVC, Borland)\n"); + printf(" -x86 - Emit an assembly version of mz80\n"); + printf(" -c - Emit a C version of mz80\n"); + printf(" -cs - All stack operations go through handlers\n"); + printf(" -16 - Treat all I/O input and output as 16 bit (BC) instead of (C)\n"); + printf(" -l - Create 'plain' labels - ones without leading or trailing _'s\n"); + printf(" -nt - No timing additions occur\n"); + printf(" -os2 - Emit OS/2 compatible segmentation pragmas\n"); + exit(1); + } + + dwLoop = 1; + + while (dwLoop < argc) + { + if (strcmp("-x86", argv[dwLoop]) == 0 || strcmp("-X86", argv[dwLoop]) == 0) + bWhat = MZ80_ASSEMBLY_X86; + if (strcmp("-c", argv[dwLoop]) == 0 || strcmp("-C", argv[dwLoop]) == 0) + bWhat = MZ80_C; + if (strcmp("-cs", argv[dwLoop]) == 0 || strcmp("-cs", argv[dwLoop]) == 0) + bThroughCallHandler = TRUE; + if (strcmp("-s", argv[dwLoop]) == 0 || strcmp("-S", argv[dwLoop]) == 0) + bUseStack = 1; + if (strcmp("-l", argv[dwLoop]) == 0 || strcmp("-L", argv[dwLoop]) == 0) + bPlain = TRUE; + if (strcmp("-16", argv[dwLoop]) == 0) + b16BitIo = TRUE; + if (strcmp("-os2", argv[dwLoop]) == 0 || strcmp("-OS2", argv[dwLoop]) == 0) + bOS2 = TRUE; + if (strcmp("-nt", argv[dwLoop]) == 0) + { + bNoTiming = TRUE; + } + + dwLoop++; + } + + if (bWhat == MZ80_UNKNOWN) + { + fprintf(stderr, "Need emitted type qualifier\n"); + exit(1); + } + + for (dwLoop = 1; dwLoop < argc; dwLoop++) + if (argv[dwLoop][0] != '-') + { + fp = fopen(argv[dwLoop], "w"); + break; + } + + if (NULL == fp) + { + fprintf(stderr, "Can't open %s for writing\n", argv[1]); + exit(1); + } + + strcpy(cpubasename, "mz80"); + + StandardHeader(); + DataSegment(); + EmitCode(); + ProgramEnd(); + + fclose(fp); +} diff --git a/cpu/mz80/mz80.c b/cpu/mz80/mz80.c new file mode 100644 index 00000000..b7733fd3 --- /dev/null +++ b/cpu/mz80/mz80.c @@ -0,0 +1,17053 @@ +#include "driver.h" + +/* Multi-Z80 32 Bit emulator */ + +/* Copyright 1996-2000 Neil Bradley, All rights reserved + * + * License agreement: + * + * (MZ80 Refers to both the assembly code emitted by makeZ80.c and makeZ80.c + * itself) + * + * MZ80 May be distributed in unmodified form to any medium. + * + * MZ80 May not be sold, or sold as a part of a commercial package without + * the express written permission of Neil Bradley (neil@synthcom.com). This + * includes shareware. + * + * Modified versions of MZ80 may not be publicly redistributed without author + * approval (neil@synthcom.com). This includes distributing via a publicly + * accessible LAN. You may make your own source modifications and distribute + * MZ80 in source or object form, but if you make modifications to MZ80 + * then it should be noted in the top as a comment in makeZ80.c. + * + * MZ80 Licensing for commercial applications is available. Please email + * neil@synthcom.com for details. + * + * Synthcom Systems, Inc, and Neil Bradley will not be held responsible for + * any damage done by the use of MZ80. It is purely "as-is". + * + * If you use MZ80 in a freeware application, credit in the following text: + * + * "Multi-Z80 CPU emulator by Neil Bradley (neil@synthcom.com)" + * + * must accompany the freeware application within the application itself or + * in the documentation. + * + * Legal stuff aside: + * + * If you find problems with MZ80, please email the author so they can get + * resolved. If you find a bug and fix it, please also email the author so + * that those bug fixes can be propogated to the installed base of MZ80 + * users. If you find performance improvements or problems with MZ80, please + * email the author with your changes/suggestions and they will be rolled in + * with subsequent releases of MZ80. + * + * The whole idea of this emulator is to have the fastest available 32 bit + * Multi-Z80 emulator for the PC, giving maximum performance. + */ + +#include +#include +#include +#include "mz80.h" +UINT32 z80intAddr; +UINT32 z80pc; + + +/* Modular global variables go here*/ + +static CONTEXTMZ80 cpu; /* CPU Context */ +static UINT8 *pbPC; /* Program counter normalized */ +static UINT8 *pbSP; /* Stack pointer normalized */ +static struct MemoryReadByte *psMemRead; /* Read memory structure */ +static struct MemoryWriteByte *psMemWrite; /* Write memory structure */ +static struct z80PortRead *psIoRead; /* Read I/O structure */ +static struct z80PortWrite *psIoWrite; /* Write memory structure */ +static INT32 sdwCyclesRemaining; /* Used as a countdown */ +static UINT32 dwReturnCode; /* Return code from exec() */ +static UINT32 dwOriginalCycles; /* How many cycles did we start with? */ +static UINT32 dwElapsedTicks; /* How many ticks did we elapse? */ +static INT32 sdwAddr; /* Temporary address storage */ +static UINT32 dwAddr; /* Temporary stack address */ +static UINT8 *pbAddAdcTable; /* Pointer to add/adc flag table */ +static UINT8 *pbSubSbcTable; /* Pointer to sub/sbc flag table */ +static UINT32 dwTemp; /* Temporary value */ + +static UINT8 bTemp; /* Temporary value */ + +static UINT8 bTemp2; /* Temporary value */ + +/* Precomputed flag tables */ + +static UINT8 bPostIncFlags[0x100] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x90, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x90, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x90, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x90, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x90, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x90, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x90, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x50 +}; + +static UINT8 bPostDecFlags[0x100] = +{ + 0x92,0x42,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x12,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x12,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x12,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x12,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x12,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x12,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x12,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x16,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82, + 0x92,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82, + 0x92,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82, + 0x92,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82, + 0x92,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82, + 0x92,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82, + 0x92,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82, + 0x92,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82 +}; + +static UINT8 bPostORFlags[0x100] = +{ + 0x44,0x00,0x00,0x04,0x00,0x04,0x04,0x00,0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04, + 0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04,0x04,0x00,0x00,0x04,0x00,0x04,0x04,0x00, + 0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04,0x04,0x00,0x00,0x04,0x00,0x04,0x04,0x00, + 0x04,0x00,0x00,0x04,0x00,0x04,0x04,0x00,0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04, + 0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04,0x04,0x00,0x00,0x04,0x00,0x04,0x04,0x00, + 0x04,0x00,0x00,0x04,0x00,0x04,0x04,0x00,0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04, + 0x04,0x00,0x00,0x04,0x00,0x04,0x04,0x00,0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04, + 0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04,0x04,0x00,0x00,0x04,0x00,0x04,0x04,0x00, + 0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84,0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80, + 0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80,0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84, + 0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80,0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84, + 0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84,0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80, + 0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80,0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84, + 0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84,0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80, + 0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84,0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80, + 0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80,0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84 +}; + +static UINT8 bPostANDFlags[0x100] = +{ + 0x54,0x10,0x10,0x14,0x10,0x14,0x14,0x10,0x10,0x14,0x14,0x10,0x14,0x10,0x10,0x14, + 0x10,0x14,0x14,0x10,0x14,0x10,0x10,0x14,0x14,0x10,0x10,0x14,0x10,0x14,0x14,0x10, + 0x10,0x14,0x14,0x10,0x14,0x10,0x10,0x14,0x14,0x10,0x10,0x14,0x10,0x14,0x14,0x10, + 0x14,0x10,0x10,0x14,0x10,0x14,0x14,0x10,0x10,0x14,0x14,0x10,0x14,0x10,0x10,0x14, + 0x10,0x14,0x14,0x10,0x14,0x10,0x10,0x14,0x14,0x10,0x10,0x14,0x10,0x14,0x14,0x10, + 0x14,0x10,0x10,0x14,0x10,0x14,0x14,0x10,0x10,0x14,0x14,0x10,0x14,0x10,0x10,0x14, + 0x14,0x10,0x10,0x14,0x10,0x14,0x14,0x10,0x10,0x14,0x14,0x10,0x14,0x10,0x10,0x14, + 0x10,0x14,0x14,0x10,0x14,0x10,0x10,0x14,0x14,0x10,0x10,0x14,0x10,0x14,0x14,0x10, + 0x90,0x94,0x94,0x90,0x94,0x90,0x90,0x94,0x94,0x90,0x90,0x94,0x90,0x94,0x94,0x90, + 0x94,0x90,0x90,0x94,0x90,0x94,0x94,0x90,0x90,0x94,0x94,0x90,0x94,0x90,0x90,0x94, + 0x94,0x90,0x90,0x94,0x90,0x94,0x94,0x90,0x90,0x94,0x94,0x90,0x94,0x90,0x90,0x94, + 0x90,0x94,0x94,0x90,0x94,0x90,0x90,0x94,0x94,0x90,0x90,0x94,0x90,0x94,0x94,0x90, + 0x94,0x90,0x90,0x94,0x90,0x94,0x94,0x90,0x90,0x94,0x94,0x90,0x94,0x90,0x90,0x94, + 0x90,0x94,0x94,0x90,0x94,0x90,0x90,0x94,0x94,0x90,0x90,0x94,0x90,0x94,0x94,0x90, + 0x90,0x94,0x94,0x90,0x94,0x90,0x90,0x94,0x94,0x90,0x90,0x94,0x90,0x94,0x94,0x90, + 0x94,0x90,0x90,0x94,0x90,0x94,0x94,0x90,0x90,0x94,0x94,0x90,0x94,0x90,0x90,0x94 +}; + +static UINT16 wDAATable[0x800] = +{ + 0x5400,0x1001,0x1002,0x1403,0x1004,0x1405,0x1406,0x1007, + 0x1008,0x1409,0x1010,0x1411,0x1412,0x1013,0x1414,0x1015, + 0x1010,0x1411,0x1412,0x1013,0x1414,0x1015,0x1016,0x1417, + 0x1418,0x1019,0x1020,0x1421,0x1422,0x1023,0x1424,0x1025, + 0x1020,0x1421,0x1422,0x1023,0x1424,0x1025,0x1026,0x1427, + 0x1428,0x1029,0x1430,0x1031,0x1032,0x1433,0x1034,0x1435, + 0x1430,0x1031,0x1032,0x1433,0x1034,0x1435,0x1436,0x1037, + 0x1038,0x1439,0x1040,0x1441,0x1442,0x1043,0x1444,0x1045, + 0x1040,0x1441,0x1442,0x1043,0x1444,0x1045,0x1046,0x1447, + 0x1448,0x1049,0x1450,0x1051,0x1052,0x1453,0x1054,0x1455, + 0x1450,0x1051,0x1052,0x1453,0x1054,0x1455,0x1456,0x1057, + 0x1058,0x1459,0x1460,0x1061,0x1062,0x1463,0x1064,0x1465, + 0x1460,0x1061,0x1062,0x1463,0x1064,0x1465,0x1466,0x1067, + 0x1068,0x1469,0x1070,0x1471,0x1472,0x1073,0x1474,0x1075, + 0x1070,0x1471,0x1472,0x1073,0x1474,0x1075,0x1076,0x1477, + 0x1478,0x1079,0x9080,0x9481,0x9482,0x9083,0x9484,0x9085, + 0x9080,0x9481,0x9482,0x9083,0x9484,0x9085,0x9086,0x9487, + 0x9488,0x9089,0x9490,0x9091,0x9092,0x9493,0x9094,0x9495, + 0x9490,0x9091,0x9092,0x9493,0x9094,0x9495,0x9496,0x9097, + 0x9098,0x9499,0x5500,0x1101,0x1102,0x1503,0x1104,0x1505, + 0x5500,0x1101,0x1102,0x1503,0x1104,0x1505,0x1506,0x1107, + 0x1108,0x1509,0x1110,0x1511,0x1512,0x1113,0x1514,0x1115, + 0x1110,0x1511,0x1512,0x1113,0x1514,0x1115,0x1116,0x1517, + 0x1518,0x1119,0x1120,0x1521,0x1522,0x1123,0x1524,0x1125, + 0x1120,0x1521,0x1522,0x1123,0x1524,0x1125,0x1126,0x1527, + 0x1528,0x1129,0x1530,0x1131,0x1132,0x1533,0x1134,0x1535, + 0x1530,0x1131,0x1132,0x1533,0x1134,0x1535,0x1536,0x1137, + 0x1138,0x1539,0x1140,0x1541,0x1542,0x1143,0x1544,0x1145, + 0x1140,0x1541,0x1542,0x1143,0x1544,0x1145,0x1146,0x1547, + 0x1548,0x1149,0x1550,0x1151,0x1152,0x1553,0x1154,0x1555, + 0x1550,0x1151,0x1152,0x1553,0x1154,0x1555,0x1556,0x1157, + 0x1158,0x1559,0x1560,0x1161,0x1162,0x1563,0x1164,0x1565, + 0x1560,0x1161,0x1162,0x1563,0x1164,0x1565,0x1566,0x1167, + 0x1168,0x1569,0x1170,0x1571,0x1572,0x1173,0x1574,0x1175, + 0x1170,0x1571,0x1572,0x1173,0x1574,0x1175,0x1176,0x1577, + 0x1578,0x1179,0x9180,0x9581,0x9582,0x9183,0x9584,0x9185, + 0x9180,0x9581,0x9582,0x9183,0x9584,0x9185,0x9186,0x9587, + 0x9588,0x9189,0x9590,0x9191,0x9192,0x9593,0x9194,0x9595, + 0x9590,0x9191,0x9192,0x9593,0x9194,0x9595,0x9596,0x9197, + 0x9198,0x9599,0x95a0,0x91a1,0x91a2,0x95a3,0x91a4,0x95a5, + 0x95a0,0x91a1,0x91a2,0x95a3,0x91a4,0x95a5,0x95a6,0x91a7, + 0x91a8,0x95a9,0x91b0,0x95b1,0x95b2,0x91b3,0x95b4,0x91b5, + 0x91b0,0x95b1,0x95b2,0x91b3,0x95b4,0x91b5,0x91b6,0x95b7, + 0x95b8,0x91b9,0x95c0,0x91c1,0x91c2,0x95c3,0x91c4,0x95c5, + 0x95c0,0x91c1,0x91c2,0x95c3,0x91c4,0x95c5,0x95c6,0x91c7, + 0x91c8,0x95c9,0x91d0,0x95d1,0x95d2,0x91d3,0x95d4,0x91d5, + 0x91d0,0x95d1,0x95d2,0x91d3,0x95d4,0x91d5,0x91d6,0x95d7, + 0x95d8,0x91d9,0x91e0,0x95e1,0x95e2,0x91e3,0x95e4,0x91e5, + 0x91e0,0x95e1,0x95e2,0x91e3,0x95e4,0x91e5,0x91e6,0x95e7, + 0x95e8,0x91e9,0x95f0,0x91f1,0x91f2,0x95f3,0x91f4,0x95f5, + 0x95f0,0x91f1,0x91f2,0x95f3,0x91f4,0x95f5,0x95f6,0x91f7, + 0x91f8,0x95f9,0x5500,0x1101,0x1102,0x1503,0x1104,0x1505, + 0x5500,0x1101,0x1102,0x1503,0x1104,0x1505,0x1506,0x1107, + 0x1108,0x1509,0x1110,0x1511,0x1512,0x1113,0x1514,0x1115, + 0x1110,0x1511,0x1512,0x1113,0x1514,0x1115,0x1116,0x1517, + 0x1518,0x1119,0x1120,0x1521,0x1522,0x1123,0x1524,0x1125, + 0x1120,0x1521,0x1522,0x1123,0x1524,0x1125,0x1126,0x1527, + 0x1528,0x1129,0x1530,0x1131,0x1132,0x1533,0x1134,0x1535, + 0x1530,0x1131,0x1132,0x1533,0x1134,0x1535,0x1536,0x1137, + 0x1138,0x1539,0x1140,0x1541,0x1542,0x1143,0x1544,0x1145, + 0x1140,0x1541,0x1542,0x1143,0x1544,0x1145,0x1146,0x1547, + 0x1548,0x1149,0x1550,0x1151,0x1152,0x1553,0x1154,0x1555, + 0x1550,0x1151,0x1152,0x1553,0x1154,0x1555,0x1556,0x1157, + 0x1158,0x1559,0x1560,0x1161,0x1162,0x1563,0x1164,0x1565, + 0x1406,0x1007,0x1008,0x1409,0x140a,0x100b,0x140c,0x100d, + 0x100e,0x140f,0x1010,0x1411,0x1412,0x1013,0x1414,0x1015, + 0x1016,0x1417,0x1418,0x1019,0x101a,0x141b,0x101c,0x141d, + 0x141e,0x101f,0x1020,0x1421,0x1422,0x1023,0x1424,0x1025, + 0x1026,0x1427,0x1428,0x1029,0x102a,0x142b,0x102c,0x142d, + 0x142e,0x102f,0x1430,0x1031,0x1032,0x1433,0x1034,0x1435, + 0x1436,0x1037,0x1038,0x1439,0x143a,0x103b,0x143c,0x103d, + 0x103e,0x143f,0x1040,0x1441,0x1442,0x1043,0x1444,0x1045, + 0x1046,0x1447,0x1448,0x1049,0x104a,0x144b,0x104c,0x144d, + 0x144e,0x104f,0x1450,0x1051,0x1052,0x1453,0x1054,0x1455, + 0x1456,0x1057,0x1058,0x1459,0x145a,0x105b,0x145c,0x105d, + 0x105e,0x145f,0x1460,0x1061,0x1062,0x1463,0x1064,0x1465, + 0x1466,0x1067,0x1068,0x1469,0x146a,0x106b,0x146c,0x106d, + 0x106e,0x146f,0x1070,0x1471,0x1472,0x1073,0x1474,0x1075, + 0x1076,0x1477,0x1478,0x1079,0x107a,0x147b,0x107c,0x147d, + 0x147e,0x107f,0x9080,0x9481,0x9482,0x9083,0x9484,0x9085, + 0x9086,0x9487,0x9488,0x9089,0x908a,0x948b,0x908c,0x948d, + 0x948e,0x908f,0x9490,0x9091,0x9092,0x9493,0x9094,0x9495, + 0x9496,0x9097,0x9098,0x9499,0x949a,0x909b,0x949c,0x909d, + 0x909e,0x949f,0x5500,0x1101,0x1102,0x1503,0x1104,0x1505, + 0x1506,0x1107,0x1108,0x1509,0x150a,0x110b,0x150c,0x110d, + 0x110e,0x150f,0x1110,0x1511,0x1512,0x1113,0x1514,0x1115, + 0x1116,0x1517,0x1518,0x1119,0x111a,0x151b,0x111c,0x151d, + 0x151e,0x111f,0x1120,0x1521,0x1522,0x1123,0x1524,0x1125, + 0x1126,0x1527,0x1528,0x1129,0x112a,0x152b,0x112c,0x152d, + 0x152e,0x112f,0x1530,0x1131,0x1132,0x1533,0x1134,0x1535, + 0x1536,0x1137,0x1138,0x1539,0x153a,0x113b,0x153c,0x113d, + 0x113e,0x153f,0x1140,0x1541,0x1542,0x1143,0x1544,0x1145, + 0x1146,0x1547,0x1548,0x1149,0x114a,0x154b,0x114c,0x154d, + 0x154e,0x114f,0x1550,0x1151,0x1152,0x1553,0x1154,0x1555, + 0x1556,0x1157,0x1158,0x1559,0x155a,0x115b,0x155c,0x115d, + 0x115e,0x155f,0x1560,0x1161,0x1162,0x1563,0x1164,0x1565, + 0x1566,0x1167,0x1168,0x1569,0x156a,0x116b,0x156c,0x116d, + 0x116e,0x156f,0x1170,0x1571,0x1572,0x1173,0x1574,0x1175, + 0x1176,0x1577,0x1578,0x1179,0x117a,0x157b,0x117c,0x157d, + 0x157e,0x117f,0x9180,0x9581,0x9582,0x9183,0x9584,0x9185, + 0x9186,0x9587,0x9588,0x9189,0x918a,0x958b,0x918c,0x958d, + 0x958e,0x918f,0x9590,0x9191,0x9192,0x9593,0x9194,0x9595, + 0x9596,0x9197,0x9198,0x9599,0x959a,0x919b,0x959c,0x919d, + 0x919e,0x959f,0x95a0,0x91a1,0x91a2,0x95a3,0x91a4,0x95a5, + 0x95a6,0x91a7,0x91a8,0x95a9,0x95aa,0x91ab,0x95ac,0x91ad, + 0x91ae,0x95af,0x91b0,0x95b1,0x95b2,0x91b3,0x95b4,0x91b5, + 0x91b6,0x95b7,0x95b8,0x91b9,0x91ba,0x95bb,0x91bc,0x95bd, + 0x95be,0x91bf,0x95c0,0x91c1,0x91c2,0x95c3,0x91c4,0x95c5, + 0x95c6,0x91c7,0x91c8,0x95c9,0x95ca,0x91cb,0x95cc,0x91cd, + 0x91ce,0x95cf,0x91d0,0x95d1,0x95d2,0x91d3,0x95d4,0x91d5, + 0x91d6,0x95d7,0x95d8,0x91d9,0x91da,0x95db,0x91dc,0x95dd, + 0x95de,0x91df,0x91e0,0x95e1,0x95e2,0x91e3,0x95e4,0x91e5, + 0x91e6,0x95e7,0x95e8,0x91e9,0x91ea,0x95eb,0x91ec,0x95ed, + 0x95ee,0x91ef,0x95f0,0x91f1,0x91f2,0x95f3,0x91f4,0x95f5, + 0x95f6,0x91f7,0x91f8,0x95f9,0x95fa,0x91fb,0x95fc,0x91fd, + 0x91fe,0x95ff,0x5500,0x1101,0x1102,0x1503,0x1104,0x1505, + 0x1506,0x1107,0x1108,0x1509,0x150a,0x110b,0x150c,0x110d, + 0x110e,0x150f,0x1110,0x1511,0x1512,0x1113,0x1514,0x1115, + 0x1116,0x1517,0x1518,0x1119,0x111a,0x151b,0x111c,0x151d, + 0x151e,0x111f,0x1120,0x1521,0x1522,0x1123,0x1524,0x1125, + 0x1126,0x1527,0x1528,0x1129,0x112a,0x152b,0x112c,0x152d, + 0x152e,0x112f,0x1530,0x1131,0x1132,0x1533,0x1134,0x1535, + 0x1536,0x1137,0x1138,0x1539,0x153a,0x113b,0x153c,0x113d, + 0x113e,0x153f,0x1140,0x1541,0x1542,0x1143,0x1544,0x1145, + 0x1146,0x1547,0x1548,0x1149,0x114a,0x154b,0x114c,0x154d, + 0x154e,0x114f,0x1550,0x1151,0x1152,0x1553,0x1154,0x1555, + 0x1556,0x1157,0x1158,0x1559,0x155a,0x115b,0x155c,0x115d, + 0x115e,0x155f,0x1560,0x1161,0x1162,0x1563,0x1164,0x1565, + 0x5600,0x1201,0x1202,0x1603,0x1204,0x1605,0x1606,0x1207, + 0x1208,0x1609,0x1204,0x1605,0x1606,0x1207,0x1208,0x1609, + 0x1210,0x1611,0x1612,0x1213,0x1614,0x1215,0x1216,0x1617, + 0x1618,0x1219,0x1614,0x1215,0x1216,0x1617,0x1618,0x1219, + 0x1220,0x1621,0x1622,0x1223,0x1624,0x1225,0x1226,0x1627, + 0x1628,0x1229,0x1624,0x1225,0x1226,0x1627,0x1628,0x1229, + 0x1630,0x1231,0x1232,0x1633,0x1234,0x1635,0x1636,0x1237, + 0x1238,0x1639,0x1234,0x1635,0x1636,0x1237,0x1238,0x1639, + 0x1240,0x1641,0x1642,0x1243,0x1644,0x1245,0x1246,0x1647, + 0x1648,0x1249,0x1644,0x1245,0x1246,0x1647,0x1648,0x1249, + 0x1650,0x1251,0x1252,0x1653,0x1254,0x1655,0x1656,0x1257, + 0x1258,0x1659,0x1254,0x1655,0x1656,0x1257,0x1258,0x1659, + 0x1660,0x1261,0x1262,0x1663,0x1264,0x1665,0x1666,0x1267, + 0x1268,0x1669,0x1264,0x1665,0x1666,0x1267,0x1268,0x1669, + 0x1270,0x1671,0x1672,0x1273,0x1674,0x1275,0x1276,0x1677, + 0x1678,0x1279,0x1674,0x1275,0x1276,0x1677,0x1678,0x1279, + 0x9280,0x9681,0x9682,0x9283,0x9684,0x9285,0x9286,0x9687, + 0x9688,0x9289,0x9684,0x9285,0x9286,0x9687,0x9688,0x9289, + 0x9690,0x9291,0x9292,0x9693,0x9294,0x9695,0x9696,0x9297, + 0x9298,0x9699,0x1334,0x1735,0x1736,0x1337,0x1338,0x1739, + 0x1340,0x1741,0x1742,0x1343,0x1744,0x1345,0x1346,0x1747, + 0x1748,0x1349,0x1744,0x1345,0x1346,0x1747,0x1748,0x1349, + 0x1750,0x1351,0x1352,0x1753,0x1354,0x1755,0x1756,0x1357, + 0x1358,0x1759,0x1354,0x1755,0x1756,0x1357,0x1358,0x1759, + 0x1760,0x1361,0x1362,0x1763,0x1364,0x1765,0x1766,0x1367, + 0x1368,0x1769,0x1364,0x1765,0x1766,0x1367,0x1368,0x1769, + 0x1370,0x1771,0x1772,0x1373,0x1774,0x1375,0x1376,0x1777, + 0x1778,0x1379,0x1774,0x1375,0x1376,0x1777,0x1778,0x1379, + 0x9380,0x9781,0x9782,0x9383,0x9784,0x9385,0x9386,0x9787, + 0x9788,0x9389,0x9784,0x9385,0x9386,0x9787,0x9788,0x9389, + 0x9790,0x9391,0x9392,0x9793,0x9394,0x9795,0x9796,0x9397, + 0x9398,0x9799,0x9394,0x9795,0x9796,0x9397,0x9398,0x9799, + 0x97a0,0x93a1,0x93a2,0x97a3,0x93a4,0x97a5,0x97a6,0x93a7, + 0x93a8,0x97a9,0x93a4,0x97a5,0x97a6,0x93a7,0x93a8,0x97a9, + 0x93b0,0x97b1,0x97b2,0x93b3,0x97b4,0x93b5,0x93b6,0x97b7, + 0x97b8,0x93b9,0x97b4,0x93b5,0x93b6,0x97b7,0x97b8,0x93b9, + 0x97c0,0x93c1,0x93c2,0x97c3,0x93c4,0x97c5,0x97c6,0x93c7, + 0x93c8,0x97c9,0x93c4,0x97c5,0x97c6,0x93c7,0x93c8,0x97c9, + 0x93d0,0x97d1,0x97d2,0x93d3,0x97d4,0x93d5,0x93d6,0x97d7, + 0x97d8,0x93d9,0x97d4,0x93d5,0x93d6,0x97d7,0x97d8,0x93d9, + 0x93e0,0x97e1,0x97e2,0x93e3,0x97e4,0x93e5,0x93e6,0x97e7, + 0x97e8,0x93e9,0x97e4,0x93e5,0x93e6,0x97e7,0x97e8,0x93e9, + 0x97f0,0x93f1,0x93f2,0x97f3,0x93f4,0x97f5,0x97f6,0x93f7, + 0x93f8,0x97f9,0x93f4,0x97f5,0x97f6,0x93f7,0x93f8,0x97f9, + 0x5700,0x1301,0x1302,0x1703,0x1304,0x1705,0x1706,0x1307, + 0x1308,0x1709,0x1304,0x1705,0x1706,0x1307,0x1308,0x1709, + 0x1310,0x1711,0x1712,0x1313,0x1714,0x1315,0x1316,0x1717, + 0x1718,0x1319,0x1714,0x1315,0x1316,0x1717,0x1718,0x1319, + 0x1320,0x1721,0x1722,0x1323,0x1724,0x1325,0x1326,0x1727, + 0x1728,0x1329,0x1724,0x1325,0x1326,0x1727,0x1728,0x1329, + 0x1730,0x1331,0x1332,0x1733,0x1334,0x1735,0x1736,0x1337, + 0x1338,0x1739,0x1334,0x1735,0x1736,0x1337,0x1338,0x1739, + 0x1340,0x1741,0x1742,0x1343,0x1744,0x1345,0x1346,0x1747, + 0x1748,0x1349,0x1744,0x1345,0x1346,0x1747,0x1748,0x1349, + 0x1750,0x1351,0x1352,0x1753,0x1354,0x1755,0x1756,0x1357, + 0x1358,0x1759,0x1354,0x1755,0x1756,0x1357,0x1358,0x1759, + 0x1760,0x1361,0x1362,0x1763,0x1364,0x1765,0x1766,0x1367, + 0x1368,0x1769,0x1364,0x1765,0x1766,0x1367,0x1368,0x1769, + 0x1370,0x1771,0x1772,0x1373,0x1774,0x1375,0x1376,0x1777, + 0x1778,0x1379,0x1774,0x1375,0x1376,0x1777,0x1778,0x1379, + 0x9380,0x9781,0x9782,0x9383,0x9784,0x9385,0x9386,0x9787, + 0x9788,0x9389,0x9784,0x9385,0x9386,0x9787,0x9788,0x9389, + 0x9790,0x9391,0x9392,0x9793,0x9394,0x9795,0x9796,0x9397, + 0x9398,0x9799,0x9394,0x9795,0x9796,0x9397,0x9398,0x9799, + 0x97fa,0x93fb,0x97fc,0x93fd,0x93fe,0x97ff,0x5600,0x1201, + 0x1202,0x1603,0x1204,0x1605,0x1606,0x1207,0x1208,0x1609, + 0x160a,0x120b,0x160c,0x120d,0x120e,0x160f,0x1210,0x1611, + 0x1612,0x1213,0x1614,0x1215,0x1216,0x1617,0x1618,0x1219, + 0x121a,0x161b,0x121c,0x161d,0x161e,0x121f,0x1220,0x1621, + 0x1622,0x1223,0x1624,0x1225,0x1226,0x1627,0x1628,0x1229, + 0x122a,0x162b,0x122c,0x162d,0x162e,0x122f,0x1630,0x1231, + 0x1232,0x1633,0x1234,0x1635,0x1636,0x1237,0x1238,0x1639, + 0x163a,0x123b,0x163c,0x123d,0x123e,0x163f,0x1240,0x1641, + 0x1642,0x1243,0x1644,0x1245,0x1246,0x1647,0x1648,0x1249, + 0x124a,0x164b,0x124c,0x164d,0x164e,0x124f,0x1650,0x1251, + 0x1252,0x1653,0x1254,0x1655,0x1656,0x1257,0x1258,0x1659, + 0x165a,0x125b,0x165c,0x125d,0x125e,0x165f,0x1660,0x1261, + 0x1262,0x1663,0x1264,0x1665,0x1666,0x1267,0x1268,0x1669, + 0x166a,0x126b,0x166c,0x126d,0x126e,0x166f,0x1270,0x1671, + 0x1672,0x1273,0x1674,0x1275,0x1276,0x1677,0x1678,0x1279, + 0x127a,0x167b,0x127c,0x167d,0x167e,0x127f,0x9280,0x9681, + 0x9682,0x9283,0x9684,0x9285,0x9286,0x9687,0x9688,0x9289, + 0x928a,0x968b,0x928c,0x968d,0x968e,0x928f,0x9690,0x9291, + 0x9292,0x9693,0x1334,0x1735,0x1736,0x1337,0x1338,0x1739, + 0x173a,0x133b,0x173c,0x133d,0x133e,0x173f,0x1340,0x1741, + 0x1742,0x1343,0x1744,0x1345,0x1346,0x1747,0x1748,0x1349, + 0x134a,0x174b,0x134c,0x174d,0x174e,0x134f,0x1750,0x1351, + 0x1352,0x1753,0x1354,0x1755,0x1756,0x1357,0x1358,0x1759, + 0x175a,0x135b,0x175c,0x135d,0x135e,0x175f,0x1760,0x1361, + 0x1362,0x1763,0x1364,0x1765,0x1766,0x1367,0x1368,0x1769, + 0x176a,0x136b,0x176c,0x136d,0x136e,0x176f,0x1370,0x1771, + 0x1772,0x1373,0x1774,0x1375,0x1376,0x1777,0x1778,0x1379, + 0x137a,0x177b,0x137c,0x177d,0x177e,0x137f,0x9380,0x9781, + 0x9782,0x9383,0x9784,0x9385,0x9386,0x9787,0x9788,0x9389, + 0x938a,0x978b,0x938c,0x978d,0x978e,0x938f,0x9790,0x9391, + 0x9392,0x9793,0x9394,0x9795,0x9796,0x9397,0x9398,0x9799, + 0x979a,0x939b,0x979c,0x939d,0x939e,0x979f,0x97a0,0x93a1, + 0x93a2,0x97a3,0x93a4,0x97a5,0x97a6,0x93a7,0x93a8,0x97a9, + 0x97aa,0x93ab,0x97ac,0x93ad,0x93ae,0x97af,0x93b0,0x97b1, + 0x97b2,0x93b3,0x97b4,0x93b5,0x93b6,0x97b7,0x97b8,0x93b9, + 0x93ba,0x97bb,0x93bc,0x97bd,0x97be,0x93bf,0x97c0,0x93c1, + 0x93c2,0x97c3,0x93c4,0x97c5,0x97c6,0x93c7,0x93c8,0x97c9, + 0x97ca,0x93cb,0x97cc,0x93cd,0x93ce,0x97cf,0x93d0,0x97d1, + 0x97d2,0x93d3,0x97d4,0x93d5,0x93d6,0x97d7,0x97d8,0x93d9, + 0x93da,0x97db,0x93dc,0x97dd,0x97de,0x93df,0x93e0,0x97e1, + 0x97e2,0x93e3,0x97e4,0x93e5,0x93e6,0x97e7,0x97e8,0x93e9, + 0x93ea,0x97eb,0x93ec,0x97ed,0x97ee,0x93ef,0x97f0,0x93f1, + 0x93f2,0x97f3,0x93f4,0x97f5,0x97f6,0x93f7,0x93f8,0x97f9, + 0x97fa,0x93fb,0x97fc,0x93fd,0x93fe,0x97ff,0x5700,0x1301, + 0x1302,0x1703,0x1304,0x1705,0x1706,0x1307,0x1308,0x1709, + 0x170a,0x130b,0x170c,0x130d,0x130e,0x170f,0x1310,0x1711, + 0x1712,0x1313,0x1714,0x1315,0x1316,0x1717,0x1718,0x1319, + 0x131a,0x171b,0x131c,0x171d,0x171e,0x131f,0x1320,0x1721, + 0x1722,0x1323,0x1724,0x1325,0x1326,0x1727,0x1728,0x1329, + 0x132a,0x172b,0x132c,0x172d,0x172e,0x132f,0x1730,0x1331, + 0x1332,0x1733,0x1334,0x1735,0x1736,0x1337,0x1338,0x1739, + 0x173a,0x133b,0x173c,0x133d,0x133e,0x173f,0x1340,0x1741, + 0x1742,0x1343,0x1744,0x1345,0x1346,0x1747,0x1748,0x1349, + 0x134a,0x174b,0x134c,0x174d,0x174e,0x134f,0x1750,0x1351, + 0x1352,0x1753,0x1354,0x1755,0x1756,0x1357,0x1358,0x1759, + 0x175a,0x135b,0x175c,0x135d,0x135e,0x175f,0x1760,0x1361, + 0x1362,0x1763,0x1364,0x1765,0x1766,0x1367,0x1368,0x1769, + 0x176a,0x136b,0x176c,0x136d,0x136e,0x176f,0x1370,0x1771, + 0x1772,0x1373,0x1774,0x1375,0x1376,0x1777,0x1778,0x1379, + 0x137a,0x177b,0x137c,0x177d,0x177e,0x137f,0x9380,0x9781, + 0x9782,0x9383,0x9784,0x9385,0x9386,0x9787,0x9788,0x9389, + 0x938a,0x978b,0x938c,0x978d,0x978e,0x938f,0x9790,0x9391, + 0x9392,0x9793,0x9394,0x9795,0x9796,0x9397,0x9398,0x9799 +}; + +void DDFDCBHandler(UINT32 dwWhich); + + +static void InvalidInstruction(UINT32 dwCount) +{ + pbPC -= dwCount; /* Invalid instruction - back up */ + dwReturnCode = (UINT32) pbPC - (UINT32) cpu.z80Base; + dwOriginalCycles -= sdwCyclesRemaining; + sdwCyclesRemaining = 0; +} + +void CBHandler(void) +{ + switch (*pbPC++) + { + case 0x00: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + bTemp2 = (cpu.z80B >> 7); + cpu.z80B = (cpu.z80B << 1) | bTemp2; + cpu.z80F |= bTemp2 | bPostORFlags[cpu.z80B]; + break; + } + case 0x01: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + bTemp2 = (cpu.z80C >> 7); + cpu.z80C = (cpu.z80C << 1) | bTemp2; + cpu.z80F |= bTemp2 | bPostORFlags[cpu.z80C]; + break; + } + case 0x02: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + bTemp2 = (cpu.z80D >> 7); + cpu.z80D = (cpu.z80D << 1) | bTemp2; + cpu.z80F |= bTemp2 | bPostORFlags[cpu.z80D]; + break; + } + case 0x03: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + bTemp2 = (cpu.z80E >> 7); + cpu.z80E = (cpu.z80E << 1) | bTemp2; + cpu.z80F |= bTemp2 | bPostORFlags[cpu.z80E]; + break; + } + case 0x04: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + bTemp2 = (cpu.z80H >> 7); + cpu.z80H = (cpu.z80H << 1) | bTemp2; + cpu.z80F |= bTemp2 | bPostORFlags[cpu.z80H]; + break; + } + case 0x05: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + bTemp2 = (cpu.z80L >> 7); + cpu.z80L = (cpu.z80L << 1) | bTemp2; + cpu.z80F |= bTemp2 | bPostORFlags[cpu.z80L]; + break; + } + case 0x06: + { + sdwCyclesRemaining -= 15; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + bTemp2 = (bTemp >> 7); + bTemp = (bTemp << 1) | bTemp2; + cpu.z80F |= bTemp2 | bPostORFlags[bTemp]; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0x07: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + bTemp2 = (cpu.z80A >> 7); + cpu.z80A = (cpu.z80A << 1) | bTemp2; + cpu.z80F |= bTemp2 | bPostORFlags[cpu.z80A]; + break; + } + case 0x08: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80B & Z80_FLAG_CARRY); + cpu.z80B = (cpu.z80B >> 1) | (cpu.z80B << 7); + cpu.z80F |= bPostORFlags[cpu.z80B]; + break; + } + case 0x09: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80C & Z80_FLAG_CARRY); + cpu.z80C = (cpu.z80C >> 1) | (cpu.z80C << 7); + cpu.z80F |= bPostORFlags[cpu.z80C]; + break; + } + case 0x0a: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80D & Z80_FLAG_CARRY); + cpu.z80D = (cpu.z80D >> 1) | (cpu.z80D << 7); + cpu.z80F |= bPostORFlags[cpu.z80D]; + break; + } + case 0x0b: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80E & Z80_FLAG_CARRY); + cpu.z80E = (cpu.z80E >> 1) | (cpu.z80E << 7); + cpu.z80F |= bPostORFlags[cpu.z80E]; + break; + } + case 0x0c: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80H & Z80_FLAG_CARRY); + cpu.z80H = (cpu.z80H >> 1) | (cpu.z80H << 7); + cpu.z80F |= bPostORFlags[cpu.z80H]; + break; + } + case 0x0d: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80L & Z80_FLAG_CARRY); + cpu.z80L = (cpu.z80L >> 1) | (cpu.z80L << 7); + cpu.z80F |= bPostORFlags[cpu.z80L]; + break; + } + case 0x0e: + { + sdwCyclesRemaining -= 15; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (bTemp & Z80_FLAG_CARRY); + bTemp = (bTemp >> 1) | (bTemp << 7); + cpu.z80F |= bPostORFlags[bTemp]; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0x0f: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80A & Z80_FLAG_CARRY); + cpu.z80A = (cpu.z80A >> 1) | (cpu.z80A << 7); + cpu.z80F |= bPostORFlags[cpu.z80A]; + break; + } + case 0x10: + { + sdwCyclesRemaining -= 8; + bTemp2 = cpu.z80F & Z80_FLAG_CARRY; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80B >> 7); + cpu.z80B = (cpu.z80B << 1) | bTemp2; + cpu.z80F |= bPostORFlags[cpu.z80B]; + break; + } + case 0x11: + { + sdwCyclesRemaining -= 8; + bTemp2 = cpu.z80F & Z80_FLAG_CARRY; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80C >> 7); + cpu.z80C = (cpu.z80C << 1) | bTemp2; + cpu.z80F |= bPostORFlags[cpu.z80C]; + break; + } + case 0x12: + { + sdwCyclesRemaining -= 8; + bTemp2 = cpu.z80F & Z80_FLAG_CARRY; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80D >> 7); + cpu.z80D = (cpu.z80D << 1) | bTemp2; + cpu.z80F |= bPostORFlags[cpu.z80D]; + break; + } + case 0x13: + { + sdwCyclesRemaining -= 8; + bTemp2 = cpu.z80F & Z80_FLAG_CARRY; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80E >> 7); + cpu.z80E = (cpu.z80E << 1) | bTemp2; + cpu.z80F |= bPostORFlags[cpu.z80E]; + break; + } + case 0x14: + { + sdwCyclesRemaining -= 8; + bTemp2 = cpu.z80F & Z80_FLAG_CARRY; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80H >> 7); + cpu.z80H = (cpu.z80H << 1) | bTemp2; + cpu.z80F |= bPostORFlags[cpu.z80H]; + break; + } + case 0x15: + { + sdwCyclesRemaining -= 8; + bTemp2 = cpu.z80F & Z80_FLAG_CARRY; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80L >> 7); + cpu.z80L = (cpu.z80L << 1) | bTemp2; + cpu.z80F |= bPostORFlags[cpu.z80L]; + break; + } + case 0x16: + { + sdwCyclesRemaining -= 15; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + bTemp2 = cpu.z80F & Z80_FLAG_CARRY; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (bTemp >> 7); + bTemp = (bTemp << 1) | bTemp2; + cpu.z80F |= bPostORFlags[bTemp]; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0x17: + { + sdwCyclesRemaining -= 8; + bTemp2 = cpu.z80F & Z80_FLAG_CARRY; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80A >> 7); + cpu.z80A = (cpu.z80A << 1) | bTemp2; + cpu.z80F |= bPostORFlags[cpu.z80A]; + break; + } + case 0x18: + { + sdwCyclesRemaining -= 8; + bTemp2 = (cpu.z80F & Z80_FLAG_CARRY) << 7; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80B & Z80_FLAG_CARRY); + cpu.z80B = (cpu.z80B >> 1) | bTemp2; + cpu.z80F |= bPostORFlags[cpu.z80B]; + break; + } + case 0x19: + { + sdwCyclesRemaining -= 8; + bTemp2 = (cpu.z80F & Z80_FLAG_CARRY) << 7; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80C & Z80_FLAG_CARRY); + cpu.z80C = (cpu.z80C >> 1) | bTemp2; + cpu.z80F |= bPostORFlags[cpu.z80C]; + break; + } + case 0x1a: + { + sdwCyclesRemaining -= 8; + bTemp2 = (cpu.z80F & Z80_FLAG_CARRY) << 7; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80D & Z80_FLAG_CARRY); + cpu.z80D = (cpu.z80D >> 1) | bTemp2; + cpu.z80F |= bPostORFlags[cpu.z80D]; + break; + } + case 0x1b: + { + sdwCyclesRemaining -= 8; + bTemp2 = (cpu.z80F & Z80_FLAG_CARRY) << 7; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80E & Z80_FLAG_CARRY); + cpu.z80E = (cpu.z80E >> 1) | bTemp2; + cpu.z80F |= bPostORFlags[cpu.z80E]; + break; + } + case 0x1c: + { + sdwCyclesRemaining -= 8; + bTemp2 = (cpu.z80F & Z80_FLAG_CARRY) << 7; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80H & Z80_FLAG_CARRY); + cpu.z80H = (cpu.z80H >> 1) | bTemp2; + cpu.z80F |= bPostORFlags[cpu.z80H]; + break; + } + case 0x1d: + { + sdwCyclesRemaining -= 8; + bTemp2 = (cpu.z80F & Z80_FLAG_CARRY) << 7; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80L & Z80_FLAG_CARRY); + cpu.z80L = (cpu.z80L >> 1) | bTemp2; + cpu.z80F |= bPostORFlags[cpu.z80L]; + break; + } + case 0x1e: + { + sdwCyclesRemaining -= 15; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + bTemp2 = (cpu.z80F & Z80_FLAG_CARRY) << 7; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (bTemp & Z80_FLAG_CARRY); + bTemp = (bTemp >> 1) | bTemp2; + cpu.z80F |= bPostORFlags[bTemp]; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0x1f: + { + sdwCyclesRemaining -= 8; + bTemp2 = (cpu.z80F & Z80_FLAG_CARRY) << 7; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80A & Z80_FLAG_CARRY); + cpu.z80A = (cpu.z80A >> 1) | bTemp2; + cpu.z80F |= bPostORFlags[cpu.z80A]; + break; + } + case 0x20: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80B >> 7); + cpu.z80B = (cpu.z80B << 1); + cpu.z80F |= bPostORFlags[cpu.z80B]; + break; + } + case 0x21: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80C >> 7); + cpu.z80C = (cpu.z80C << 1); + cpu.z80F |= bPostORFlags[cpu.z80C]; + break; + } + case 0x22: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80D >> 7); + cpu.z80D = (cpu.z80D << 1); + cpu.z80F |= bPostORFlags[cpu.z80D]; + break; + } + case 0x23: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80E >> 7); + cpu.z80E = (cpu.z80E << 1); + cpu.z80F |= bPostORFlags[cpu.z80E]; + break; + } + case 0x24: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80H >> 7); + cpu.z80H = (cpu.z80H << 1); + cpu.z80F |= bPostORFlags[cpu.z80H]; + break; + } + case 0x25: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80L >> 7); + cpu.z80L = (cpu.z80L << 1); + cpu.z80F |= bPostORFlags[cpu.z80L]; + break; + } + case 0x26: + { + sdwCyclesRemaining -= 15; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (bTemp >> 7); + bTemp = (bTemp << 1); + cpu.z80F |= bPostORFlags[bTemp]; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0x27: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80A >> 7); + cpu.z80A = (cpu.z80A << 1); + cpu.z80F |= bPostORFlags[cpu.z80A]; + break; + } + case 0x28: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80B & Z80_FLAG_CARRY); + cpu.z80B = (cpu.z80B >> 1) | (cpu.z80B & 0x80); + cpu.z80F |= bPostORFlags[cpu.z80B]; + break; + } + case 0x29: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80C & Z80_FLAG_CARRY); + cpu.z80C = (cpu.z80C >> 1) | (cpu.z80C & 0x80); + cpu.z80F |= bPostORFlags[cpu.z80C]; + break; + } + case 0x2a: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80D & Z80_FLAG_CARRY); + cpu.z80D = (cpu.z80D >> 1) | (cpu.z80D & 0x80); + cpu.z80F |= bPostORFlags[cpu.z80D]; + break; + } + case 0x2b: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80E & Z80_FLAG_CARRY); + cpu.z80E = (cpu.z80E >> 1) | (cpu.z80E & 0x80); + cpu.z80F |= bPostORFlags[cpu.z80E]; + break; + } + case 0x2c: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80H & Z80_FLAG_CARRY); + cpu.z80H = (cpu.z80H >> 1) | (cpu.z80H & 0x80); + cpu.z80F |= bPostORFlags[cpu.z80H]; + break; + } + case 0x2d: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80L & Z80_FLAG_CARRY); + cpu.z80L = (cpu.z80L >> 1) | (cpu.z80L & 0x80); + cpu.z80F |= bPostORFlags[cpu.z80L]; + break; + } + case 0x2e: + { + sdwCyclesRemaining -= 15; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (bTemp & Z80_FLAG_CARRY); + bTemp = (bTemp >> 1) | (bTemp & 0x80); + cpu.z80F |= bPostORFlags[bTemp]; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0x2f: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80A & Z80_FLAG_CARRY); + cpu.z80A = (cpu.z80A >> 1) | (cpu.z80A & 0x80); + cpu.z80F |= bPostORFlags[cpu.z80A]; + break; + } + case 0x30: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80B >> 7); + cpu.z80B = (cpu.z80B << 1); + cpu.z80F |= bPostORFlags[cpu.z80B]; + break; + } + case 0x31: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80C >> 7); + cpu.z80C = (cpu.z80C << 1); + cpu.z80F |= bPostORFlags[cpu.z80C]; + break; + } + case 0x32: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80D >> 7); + cpu.z80D = (cpu.z80D << 1); + cpu.z80F |= bPostORFlags[cpu.z80D]; + break; + } + case 0x33: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80E >> 7); + cpu.z80E = (cpu.z80E << 1); + cpu.z80F |= bPostORFlags[cpu.z80E]; + break; + } + case 0x34: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80H >> 7); + cpu.z80H = (cpu.z80H << 1); + cpu.z80F |= bPostORFlags[cpu.z80H]; + break; + } + case 0x35: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80L >> 7); + cpu.z80L = (cpu.z80L << 1); + cpu.z80F |= bPostORFlags[cpu.z80L]; + break; + } + case 0x36: + { + sdwCyclesRemaining -= 15; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (bTemp >> 7); + bTemp = (bTemp << 1); + cpu.z80F |= bPostORFlags[bTemp]; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0x37: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80A >> 7); + cpu.z80A = (cpu.z80A << 1); + cpu.z80F |= bPostORFlags[cpu.z80A]; + break; + } + case 0x38: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80B & Z80_FLAG_CARRY); + cpu.z80B = (cpu.z80B >> 1); + cpu.z80F |= bPostORFlags[cpu.z80B]; + break; + } + case 0x39: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80C & Z80_FLAG_CARRY); + cpu.z80C = (cpu.z80C >> 1); + cpu.z80F |= bPostORFlags[cpu.z80C]; + break; + } + case 0x3a: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80D & Z80_FLAG_CARRY); + cpu.z80D = (cpu.z80D >> 1); + cpu.z80F |= bPostORFlags[cpu.z80D]; + break; + } + case 0x3b: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80E & Z80_FLAG_CARRY); + cpu.z80E = (cpu.z80E >> 1); + cpu.z80F |= bPostORFlags[cpu.z80E]; + break; + } + case 0x3c: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80H & Z80_FLAG_CARRY); + cpu.z80H = (cpu.z80H >> 1); + cpu.z80F |= bPostORFlags[cpu.z80H]; + break; + } + case 0x3d: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80L & Z80_FLAG_CARRY); + cpu.z80L = (cpu.z80L >> 1); + cpu.z80F |= bPostORFlags[cpu.z80L]; + break; + } + case 0x3e: + { + sdwCyclesRemaining -= 15; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (bTemp & Z80_FLAG_CARRY); + bTemp = (bTemp >> 1); + cpu.z80F |= bPostORFlags[bTemp]; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0x3f: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (cpu.z80A & Z80_FLAG_CARRY); + cpu.z80A = (cpu.z80A >> 1); + cpu.z80F |= bPostORFlags[cpu.z80A]; + break; + } + case 0x40: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80B & 0x01)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x41: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80C & 0x01)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x42: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80D & 0x01)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x43: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80E & 0x01)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x44: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80H & 0x01)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x45: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80L & 0x01)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x46: + { + sdwCyclesRemaining -= 12; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(bTemp & 0x01)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x47: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80A & 0x01)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x48: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80B & 0x02)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x49: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80C & 0x02)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x4a: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80D & 0x02)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x4b: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80E & 0x02)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x4c: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80H & 0x02)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x4d: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80L & 0x02)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x4e: + { + sdwCyclesRemaining -= 12; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(bTemp & 0x02)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x4f: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80A & 0x02)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x50: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80B & 0x04)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x51: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80C & 0x04)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x52: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80D & 0x04)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x53: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80E & 0x04)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x54: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80H & 0x04)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x55: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80L & 0x04)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x56: + { + sdwCyclesRemaining -= 12; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(bTemp & 0x04)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x57: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80A & 0x04)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x58: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80B & 0x08)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x59: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80C & 0x08)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x5a: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80D & 0x08)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x5b: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80E & 0x08)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x5c: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80H & 0x08)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x5d: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80L & 0x08)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x5e: + { + sdwCyclesRemaining -= 12; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(bTemp & 0x08)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x5f: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80A & 0x08)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x60: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80B & 0x10)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x61: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80C & 0x10)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x62: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80D & 0x10)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x63: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80E & 0x10)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x64: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80H & 0x10)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x65: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80L & 0x10)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x66: + { + sdwCyclesRemaining -= 12; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(bTemp & 0x10)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x67: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80A & 0x10)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x68: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80B & 0x20)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x69: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80C & 0x20)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x6a: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80D & 0x20)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x6b: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80E & 0x20)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x6c: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80H & 0x20)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x6d: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80L & 0x20)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x6e: + { + sdwCyclesRemaining -= 12; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(bTemp & 0x20)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x6f: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80A & 0x20)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x70: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80B & 0x40)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x71: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80C & 0x40)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x72: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80D & 0x40)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x73: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80E & 0x40)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x74: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80H & 0x40)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x75: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80L & 0x40)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x76: + { + sdwCyclesRemaining -= 12; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(bTemp & 0x40)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x77: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80A & 0x40)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x78: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80B & 0x80)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x79: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80C & 0x80)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x7a: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80D & 0x80)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x7b: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80E & 0x80)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x7c: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80H & 0x80)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x7d: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80L & 0x80)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x7e: + { + sdwCyclesRemaining -= 12; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(bTemp & 0x80)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x7f: + { + sdwCyclesRemaining -= 8; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO); + cpu.z80F |= (Z80_FLAG_HALF_CARRY); + if (!(cpu.z80A & 0x80)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x80: + { + sdwCyclesRemaining -= 8; + cpu.z80B &= 0xfe; + break; + } + case 0x81: + { + sdwCyclesRemaining -= 8; + cpu.z80C &= 0xfe; + break; + } + case 0x82: + { + sdwCyclesRemaining -= 8; + cpu.z80D &= 0xfe; + break; + } + case 0x83: + { + sdwCyclesRemaining -= 8; + cpu.z80E &= 0xfe; + break; + } + case 0x84: + { + sdwCyclesRemaining -= 8; + cpu.z80H &= 0xfe; + break; + } + case 0x85: + { + sdwCyclesRemaining -= 8; + cpu.z80L &= 0xfe; + break; + } + case 0x86: + { + sdwCyclesRemaining -= 15; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + bTemp &= 0xfe; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0x87: + { + sdwCyclesRemaining -= 8; + cpu.z80A &= 0xfe; + break; + } + case 0x88: + { + sdwCyclesRemaining -= 8; + cpu.z80B &= 0xfd; + break; + } + case 0x89: + { + sdwCyclesRemaining -= 8; + cpu.z80C &= 0xfd; + break; + } + case 0x8a: + { + sdwCyclesRemaining -= 8; + cpu.z80D &= 0xfd; + break; + } + case 0x8b: + { + sdwCyclesRemaining -= 8; + cpu.z80E &= 0xfd; + break; + } + case 0x8c: + { + sdwCyclesRemaining -= 8; + cpu.z80H &= 0xfd; + break; + } + case 0x8d: + { + sdwCyclesRemaining -= 8; + cpu.z80L &= 0xfd; + break; + } + case 0x8e: + { + sdwCyclesRemaining -= 15; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + bTemp &= 0xfd; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0x8f: + { + sdwCyclesRemaining -= 8; + cpu.z80A &= 0xfd; + break; + } + case 0x90: + { + sdwCyclesRemaining -= 8; + cpu.z80B &= 0xfb; + break; + } + case 0x91: + { + sdwCyclesRemaining -= 8; + cpu.z80C &= 0xfb; + break; + } + case 0x92: + { + sdwCyclesRemaining -= 8; + cpu.z80D &= 0xfb; + break; + } + case 0x93: + { + sdwCyclesRemaining -= 8; + cpu.z80E &= 0xfb; + break; + } + case 0x94: + { + sdwCyclesRemaining -= 8; + cpu.z80H &= 0xfb; + break; + } + case 0x95: + { + sdwCyclesRemaining -= 8; + cpu.z80L &= 0xfb; + break; + } + case 0x96: + { + sdwCyclesRemaining -= 15; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + bTemp &= 0xfb; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0x97: + { + sdwCyclesRemaining -= 8; + cpu.z80A &= 0xfb; + break; + } + case 0x98: + { + sdwCyclesRemaining -= 8; + cpu.z80B &= 0xf7; + break; + } + case 0x99: + { + sdwCyclesRemaining -= 8; + cpu.z80C &= 0xf7; + break; + } + case 0x9a: + { + sdwCyclesRemaining -= 8; + cpu.z80D &= 0xf7; + break; + } + case 0x9b: + { + sdwCyclesRemaining -= 8; + cpu.z80E &= 0xf7; + break; + } + case 0x9c: + { + sdwCyclesRemaining -= 8; + cpu.z80H &= 0xf7; + break; + } + case 0x9d: + { + sdwCyclesRemaining -= 8; + cpu.z80L &= 0xf7; + break; + } + case 0x9e: + { + sdwCyclesRemaining -= 15; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + bTemp &= 0xf7; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0x9f: + { + sdwCyclesRemaining -= 8; + cpu.z80A &= 0xf7; + break; + } + case 0xa0: + { + sdwCyclesRemaining -= 8; + cpu.z80B &= 0xef; + break; + } + case 0xa1: + { + sdwCyclesRemaining -= 8; + cpu.z80C &= 0xef; + break; + } + case 0xa2: + { + sdwCyclesRemaining -= 8; + cpu.z80D &= 0xef; + break; + } + case 0xa3: + { + sdwCyclesRemaining -= 8; + cpu.z80E &= 0xef; + break; + } + case 0xa4: + { + sdwCyclesRemaining -= 8; + cpu.z80H &= 0xef; + break; + } + case 0xa5: + { + sdwCyclesRemaining -= 8; + cpu.z80L &= 0xef; + break; + } + case 0xa6: + { + sdwCyclesRemaining -= 15; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + bTemp &= 0xef; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0xa7: + { + sdwCyclesRemaining -= 8; + cpu.z80A &= 0xef; + break; + } + case 0xa8: + { + sdwCyclesRemaining -= 8; + cpu.z80B &= 0xdf; + break; + } + case 0xa9: + { + sdwCyclesRemaining -= 8; + cpu.z80C &= 0xdf; + break; + } + case 0xaa: + { + sdwCyclesRemaining -= 8; + cpu.z80D &= 0xdf; + break; + } + case 0xab: + { + sdwCyclesRemaining -= 8; + cpu.z80E &= 0xdf; + break; + } + case 0xac: + { + sdwCyclesRemaining -= 8; + cpu.z80H &= 0xdf; + break; + } + case 0xad: + { + sdwCyclesRemaining -= 8; + cpu.z80L &= 0xdf; + break; + } + case 0xae: + { + sdwCyclesRemaining -= 15; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + bTemp &= 0xdf; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0xaf: + { + sdwCyclesRemaining -= 8; + cpu.z80A &= 0xdf; + break; + } + case 0xb0: + { + sdwCyclesRemaining -= 8; + cpu.z80B &= 0xbf; + break; + } + case 0xb1: + { + sdwCyclesRemaining -= 8; + cpu.z80C &= 0xbf; + break; + } + case 0xb2: + { + sdwCyclesRemaining -= 8; + cpu.z80D &= 0xbf; + break; + } + case 0xb3: + { + sdwCyclesRemaining -= 8; + cpu.z80E &= 0xbf; + break; + } + case 0xb4: + { + sdwCyclesRemaining -= 8; + cpu.z80H &= 0xbf; + break; + } + case 0xb5: + { + sdwCyclesRemaining -= 8; + cpu.z80L &= 0xbf; + break; + } + case 0xb6: + { + sdwCyclesRemaining -= 15; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + bTemp &= 0xbf; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0xb7: + { + sdwCyclesRemaining -= 8; + cpu.z80A &= 0xbf; + break; + } + case 0xb8: + { + sdwCyclesRemaining -= 8; + cpu.z80B &= 0x7f; + break; + } + case 0xb9: + { + sdwCyclesRemaining -= 8; + cpu.z80C &= 0x7f; + break; + } + case 0xba: + { + sdwCyclesRemaining -= 8; + cpu.z80D &= 0x7f; + break; + } + case 0xbb: + { + sdwCyclesRemaining -= 8; + cpu.z80E &= 0x7f; + break; + } + case 0xbc: + { + sdwCyclesRemaining -= 8; + cpu.z80H &= 0x7f; + break; + } + case 0xbd: + { + sdwCyclesRemaining -= 8; + cpu.z80L &= 0x7f; + break; + } + case 0xbe: + { + sdwCyclesRemaining -= 15; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + bTemp &= 0x7f; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0xbf: + { + sdwCyclesRemaining -= 8; + cpu.z80A &= 0x7f; + break; + } + case 0xc0: + { + sdwCyclesRemaining -= 8; + cpu.z80B |= 0x01; + break; + } + case 0xc1: + { + sdwCyclesRemaining -= 8; + cpu.z80C |= 0x01; + break; + } + case 0xc2: + { + sdwCyclesRemaining -= 8; + cpu.z80D |= 0x01; + break; + } + case 0xc3: + { + sdwCyclesRemaining -= 8; + cpu.z80E |= 0x01; + break; + } + case 0xc4: + { + sdwCyclesRemaining -= 8; + cpu.z80H |= 0x01; + break; + } + case 0xc5: + { + sdwCyclesRemaining -= 8; + cpu.z80L |= 0x01; + break; + } + case 0xc6: + { + sdwCyclesRemaining -= 15; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + bTemp |= 0x01; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0xc7: + { + sdwCyclesRemaining -= 8; + cpu.z80A |= 0x01; + break; + } + case 0xc8: + { + sdwCyclesRemaining -= 8; + cpu.z80B |= 0x02; + break; + } + case 0xc9: + { + sdwCyclesRemaining -= 8; + cpu.z80C |= 0x02; + break; + } + case 0xca: + { + sdwCyclesRemaining -= 8; + cpu.z80D |= 0x02; + break; + } + case 0xcb: + { + sdwCyclesRemaining -= 8; + cpu.z80E |= 0x02; + break; + } + case 0xcc: + { + sdwCyclesRemaining -= 8; + cpu.z80H |= 0x02; + break; + } + case 0xcd: + { + sdwCyclesRemaining -= 8; + cpu.z80L |= 0x02; + break; + } + case 0xce: + { + sdwCyclesRemaining -= 15; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + bTemp |= 0x02; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0xcf: + { + sdwCyclesRemaining -= 8; + cpu.z80A |= 0x02; + break; + } + case 0xd0: + { + sdwCyclesRemaining -= 8; + cpu.z80B |= 0x04; + break; + } + case 0xd1: + { + sdwCyclesRemaining -= 8; + cpu.z80C |= 0x04; + break; + } + case 0xd2: + { + sdwCyclesRemaining -= 8; + cpu.z80D |= 0x04; + break; + } + case 0xd3: + { + sdwCyclesRemaining -= 8; + cpu.z80E |= 0x04; + break; + } + case 0xd4: + { + sdwCyclesRemaining -= 8; + cpu.z80H |= 0x04; + break; + } + case 0xd5: + { + sdwCyclesRemaining -= 8; + cpu.z80L |= 0x04; + break; + } + case 0xd6: + { + sdwCyclesRemaining -= 15; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + bTemp |= 0x04; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0xd7: + { + sdwCyclesRemaining -= 8; + cpu.z80A |= 0x04; + break; + } + case 0xd8: + { + sdwCyclesRemaining -= 8; + cpu.z80B |= 0x08; + break; + } + case 0xd9: + { + sdwCyclesRemaining -= 8; + cpu.z80C |= 0x08; + break; + } + case 0xda: + { + sdwCyclesRemaining -= 8; + cpu.z80D |= 0x08; + break; + } + case 0xdb: + { + sdwCyclesRemaining -= 8; + cpu.z80E |= 0x08; + break; + } + case 0xdc: + { + sdwCyclesRemaining -= 8; + cpu.z80H |= 0x08; + break; + } + case 0xdd: + { + sdwCyclesRemaining -= 8; + cpu.z80L |= 0x08; + break; + } + case 0xde: + { + sdwCyclesRemaining -= 15; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + bTemp |= 0x08; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0xdf: + { + sdwCyclesRemaining -= 8; + cpu.z80A |= 0x08; + break; + } + case 0xe0: + { + sdwCyclesRemaining -= 8; + cpu.z80B |= 0x10; + break; + } + case 0xe1: + { + sdwCyclesRemaining -= 8; + cpu.z80C |= 0x10; + break; + } + case 0xe2: + { + sdwCyclesRemaining -= 8; + cpu.z80D |= 0x10; + break; + } + case 0xe3: + { + sdwCyclesRemaining -= 8; + cpu.z80E |= 0x10; + break; + } + case 0xe4: + { + sdwCyclesRemaining -= 8; + cpu.z80H |= 0x10; + break; + } + case 0xe5: + { + sdwCyclesRemaining -= 8; + cpu.z80L |= 0x10; + break; + } + case 0xe6: + { + sdwCyclesRemaining -= 15; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + bTemp |= 0x10; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0xe7: + { + sdwCyclesRemaining -= 8; + cpu.z80A |= 0x10; + break; + } + case 0xe8: + { + sdwCyclesRemaining -= 8; + cpu.z80B |= 0x20; + break; + } + case 0xe9: + { + sdwCyclesRemaining -= 8; + cpu.z80C |= 0x20; + break; + } + case 0xea: + { + sdwCyclesRemaining -= 8; + cpu.z80D |= 0x20; + break; + } + case 0xeb: + { + sdwCyclesRemaining -= 8; + cpu.z80E |= 0x20; + break; + } + case 0xec: + { + sdwCyclesRemaining -= 8; + cpu.z80H |= 0x20; + break; + } + case 0xed: + { + sdwCyclesRemaining -= 8; + cpu.z80L |= 0x20; + break; + } + case 0xee: + { + sdwCyclesRemaining -= 15; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + bTemp |= 0x20; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0xef: + { + sdwCyclesRemaining -= 8; + cpu.z80A |= 0x20; + break; + } + case 0xf0: + { + sdwCyclesRemaining -= 8; + cpu.z80B |= 0x40; + break; + } + case 0xf1: + { + sdwCyclesRemaining -= 8; + cpu.z80C |= 0x40; + break; + } + case 0xf2: + { + sdwCyclesRemaining -= 8; + cpu.z80D |= 0x40; + break; + } + case 0xf3: + { + sdwCyclesRemaining -= 8; + cpu.z80E |= 0x40; + break; + } + case 0xf4: + { + sdwCyclesRemaining -= 8; + cpu.z80H |= 0x40; + break; + } + case 0xf5: + { + sdwCyclesRemaining -= 8; + cpu.z80L |= 0x40; + break; + } + case 0xf6: + { + sdwCyclesRemaining -= 15; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + bTemp |= 0x40; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0xf7: + { + sdwCyclesRemaining -= 8; + cpu.z80A |= 0x40; + break; + } + case 0xf8: + { + sdwCyclesRemaining -= 8; + cpu.z80B |= 0x80; + break; + } + case 0xf9: + { + sdwCyclesRemaining -= 8; + cpu.z80C |= 0x80; + break; + } + case 0xfa: + { + sdwCyclesRemaining -= 8; + cpu.z80D |= 0x80; + break; + } + case 0xfb: + { + sdwCyclesRemaining -= 8; + cpu.z80E |= 0x80; + break; + } + case 0xfc: + { + sdwCyclesRemaining -= 8; + cpu.z80H |= 0x80; + break; + } + case 0xfd: + { + sdwCyclesRemaining -= 8; + cpu.z80L |= 0x80; + break; + } + case 0xfe: + { + sdwCyclesRemaining -= 15; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + bTemp |= 0x80; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0xff: + { + sdwCyclesRemaining -= 8; + cpu.z80A |= 0x80; + break; + } + } +} +void EDHandler(void) +{ + switch (*pbPC++) + { + case 0x00: + { + InvalidInstruction(2); + break; + } + case 0x01: + { + InvalidInstruction(2); + break; + } + case 0x02: + { + InvalidInstruction(2); + break; + } + case 0x03: + { + InvalidInstruction(2); + break; + } + case 0x04: + { + InvalidInstruction(2); + break; + } + case 0x05: + { + InvalidInstruction(2); + break; + } + case 0x06: + { + InvalidInstruction(2); + break; + } + case 0x07: + { + InvalidInstruction(2); + break; + } + case 0x08: + { + InvalidInstruction(2); + break; + } + case 0x09: + { + InvalidInstruction(2); + break; + } + case 0x0a: + { + InvalidInstruction(2); + break; + } + case 0x0b: + { + InvalidInstruction(2); + break; + } + case 0x0c: + { + InvalidInstruction(2); + break; + } + case 0x0d: + { + InvalidInstruction(2); + break; + } + case 0x0e: + { + InvalidInstruction(2); + break; + } + case 0x0f: + { + InvalidInstruction(2); + break; + } + case 0x10: + { + InvalidInstruction(2); + break; + } + case 0x11: + { + InvalidInstruction(2); + break; + } + case 0x12: + { + InvalidInstruction(2); + break; + } + case 0x13: + { + InvalidInstruction(2); + break; + } + case 0x14: + { + InvalidInstruction(2); + break; + } + case 0x15: + { + InvalidInstruction(2); + break; + } + case 0x16: + { + InvalidInstruction(2); + break; + } + case 0x17: + { + InvalidInstruction(2); + break; + } + case 0x18: + { + InvalidInstruction(2); + break; + } + case 0x19: + { + InvalidInstruction(2); + break; + } + case 0x1a: + { + InvalidInstruction(2); + break; + } + case 0x1b: + { + InvalidInstruction(2); + break; + } + case 0x1c: + { + InvalidInstruction(2); + break; + } + case 0x1d: + { + InvalidInstruction(2); + break; + } + case 0x1e: + { + InvalidInstruction(2); + break; + } + case 0x1f: + { + InvalidInstruction(2); + break; + } + case 0x20: + { + InvalidInstruction(2); + break; + } + case 0x21: + { + InvalidInstruction(2); + break; + } + case 0x22: + { + InvalidInstruction(2); + break; + } + case 0x23: + { + InvalidInstruction(2); + break; + } + case 0x24: + { + InvalidInstruction(2); + break; + } + case 0x25: + { + InvalidInstruction(2); + break; + } + case 0x26: + { + InvalidInstruction(2); + break; + } + case 0x27: + { + InvalidInstruction(2); + break; + } + case 0x28: + { + InvalidInstruction(2); + break; + } + case 0x29: + { + InvalidInstruction(2); + break; + } + case 0x2a: + { + InvalidInstruction(2); + break; + } + case 0x2b: + { + InvalidInstruction(2); + break; + } + case 0x2c: + { + InvalidInstruction(2); + break; + } + case 0x2d: + { + InvalidInstruction(2); + break; + } + case 0x2e: + { + InvalidInstruction(2); + break; + } + case 0x2f: + { + InvalidInstruction(2); + break; + } + case 0x30: + { + InvalidInstruction(2); + break; + } + case 0x31: + { + InvalidInstruction(2); + break; + } + case 0x32: + { + InvalidInstruction(2); + break; + } + case 0x33: + { + InvalidInstruction(2); + break; + } + case 0x34: + { + InvalidInstruction(2); + break; + } + case 0x35: + { + InvalidInstruction(2); + break; + } + case 0x36: + { + InvalidInstruction(2); + break; + } + case 0x37: + { + InvalidInstruction(2); + break; + } + case 0x38: + { + InvalidInstruction(2); + break; + } + case 0x39: + { + InvalidInstruction(2); + break; + } + case 0x3a: + { + InvalidInstruction(2); + break; + } + case 0x3b: + { + InvalidInstruction(2); + break; + } + case 0x3c: + { + InvalidInstruction(2); + break; + } + case 0x3d: + { + InvalidInstruction(2); + break; + } + case 0x3e: + { + InvalidInstruction(2); + break; + } + case 0x3f: + { + InvalidInstruction(2); + break; + } + case 0x40: + { + sdwCyclesRemaining -= 12; + dwAddr = cpu.z80C; + psIoRead = cpu.z80IoRead; /* Beginning of our handler */ + while (psIoRead->lowIoAddr != 0xffff) + { + if ((dwAddr >= psIoRead->lowIoAddr) && (dwAddr <= psIoRead->highIoAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + cpu.z80B = psIoRead->IOCall(dwAddr, psIoRead); + psIoRead = NULL; + break; + } + ++psIoRead; + } + + if (psIoRead) + { + cpu.z80B = 0xff; /* Unclaimed I/O read */ + } + + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostORFlags[cpu.z80B]; + break; + } + case 0x41: + { + sdwCyclesRemaining -= 12; + dwAddr = cpu.z80C; + psIoWrite = cpu.z80IoWrite; /* Beginning of our handler */ + while (psIoWrite->lowIoAddr != 0xffff) + { + if ((dwAddr >= psIoWrite->lowIoAddr) && (dwAddr <= psIoWrite->highIoAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + psIoWrite->IOCall(dwAddr, cpu.z80B, psIoWrite); + psIoWrite = NULL; + break; + } + ++psIoWrite; + } + + break; + } + case 0x42: + { + sdwCyclesRemaining -= 15; + dwTemp = cpu.z80HL - cpu.z80BC - (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= ((dwTemp >> 8) & Z80_FLAG_SIGN); + if (0 == (dwTemp & 0xffff)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + cpu.z80F |= (((cpu.z80HL ^ dwTemp ^ cpu.z80BC) >> 8) & Z80_FLAG_HALF_CARRY); + cpu.z80F |= ((((cpu.z80BC ^ cpu.z80HL) & (cpu.z80BC ^ dwTemp)) >> 13) & Z80_FLAG_OVERFLOW_PARITY); + cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY); + cpu.z80HL = dwTemp & 0xffff; + break; + } + case 0x43: + { + sdwCyclesRemaining -= 20; + dwTemp = *pbPC++; + dwTemp |= ((UINT32) *pbPC++ << 8); + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwTemp >= psMemWrite->lowAddr) && (dwTemp <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwTemp, (cpu.z80BC & 0xff), psMemWrite); + psMemWrite->memoryCall(dwTemp + 1, (cpu.z80BC >> 8), psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwTemp - psMemWrite->lowAddr)) = cpu.z80BC; + *((UINT8 *) psMemWrite->pUserArea + (dwTemp - psMemWrite->lowAddr) + 1) = cpu.z80BC >> 8; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwTemp] = (UINT8) cpu.z80BC; + cpu.z80Base[dwTemp + 1] = (UINT8) ((UINT32) cpu.z80BC >> 8); + } + + break; + } + case 0x44: + { + sdwCyclesRemaining -= 8; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) 0 << 8) | cpu.z80A]; + cpu.z80A = 0 - cpu.z80A; + break; + } + case 0x45: + { + sdwCyclesRemaining -= 14; + pbSP = cpu.z80Base + cpu.z80sp; /* Normalize our stack PTR */ + dwAddr = *pbSP++; /* Pop LSB */ + dwAddr |= ((UINT32) *pbSP << 8); /* Pop MSB */ + cpu.z80sp += 2; /* Pop the word off */ + pbPC = (cpu.z80Base + dwAddr); /* Point PC to our return address */ + cpu.z80iff &= ~(IFF1); /* Keep IFF2 around */ + cpu.z80iff |= ((cpu.z80iff >> 1) & IFF1); /* IFF2->IFF1 */ + break; + } + case 0x46: + { + sdwCyclesRemaining -= 8; + cpu.z80interruptMode = 0; + break; + } + case 0x47: + { + sdwCyclesRemaining -= 9; + cpu.z80i = cpu.z80A; + break; + } + case 0x48: + { + sdwCyclesRemaining -= 12; + dwAddr = cpu.z80C; + psIoRead = cpu.z80IoRead; /* Beginning of our handler */ + while (psIoRead->lowIoAddr != 0xffff) + { + if ((dwAddr >= psIoRead->lowIoAddr) && (dwAddr <= psIoRead->highIoAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + cpu.z80C = psIoRead->IOCall(dwAddr, psIoRead); + psIoRead = NULL; + break; + } + ++psIoRead; + } + + if (psIoRead) + { + cpu.z80C = 0xff; /* Unclaimed I/O read */ + } + + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostORFlags[cpu.z80C]; + break; + } + case 0x49: + { + sdwCyclesRemaining -= 12; + dwAddr = cpu.z80C; + psIoWrite = cpu.z80IoWrite; /* Beginning of our handler */ + while (psIoWrite->lowIoAddr != 0xffff) + { + if ((dwAddr >= psIoWrite->lowIoAddr) && (dwAddr <= psIoWrite->highIoAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + psIoWrite->IOCall(dwAddr, cpu.z80C, psIoWrite); + psIoWrite = NULL; + break; + } + ++psIoWrite; + } + + break; + } + case 0x4a: + { + sdwCyclesRemaining -= 15; + dwTemp = cpu.z80HL + cpu.z80BC + (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= ((dwTemp >> 8) & Z80_FLAG_SIGN); + if (0 == (dwTemp & 0xffff)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + cpu.z80F |= (((cpu.z80HL ^ dwTemp ^ cpu.z80BC) >> 8) & Z80_FLAG_HALF_CARRY); + cpu.z80F |= ((((cpu.z80BC ^ cpu.z80HL ^ 0x8000) & (cpu.z80BC ^ dwTemp)) >> 13) & Z80_FLAG_OVERFLOW_PARITY); + cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY); + cpu.z80HL = dwTemp & 0xffff; + break; + } + case 0x4b: + { + sdwCyclesRemaining -= 20; + dwTemp = *pbPC++; + dwTemp |= ((UINT32) *pbPC++ << 8); + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwTemp >= psMemRead->lowAddr) && (dwTemp <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80BC = psMemRead->memoryCall(dwTemp, psMemRead); + cpu.z80BC |= (UINT32) ((UINT32) psMemRead->memoryCall(dwTemp + 1, psMemRead) << 8); + } + else + { + cpu.z80BC = *((UINT8 *) psMemRead->pUserArea + (dwTemp - psMemRead->lowAddr)); + cpu.z80BC |= (UINT32) ((UINT32) *((UINT8 *) psMemRead->pUserArea + (dwTemp - psMemRead->lowAddr + 1)) << 8); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80BC = cpu.z80Base[dwTemp]; + cpu.z80BC |= (UINT32) ((UINT32) cpu.z80Base[dwTemp + 1] << 8); + } + + break; + } + case 0x4c: + { + sdwCyclesRemaining -= 8; + InvalidInstruction(2); + break; + } + case 0x4d: + { + sdwCyclesRemaining -= 14; + pbSP = cpu.z80Base + cpu.z80sp; /* Normalize our stack PTR */ + dwAddr = *pbSP++; /* Pop LSB */ + dwAddr |= ((UINT32) *pbSP << 8); /* Pop MSB */ + cpu.z80sp += 2; /* Pop the word off */ + pbPC = (cpu.z80Base + dwAddr); /* Point PC to our return address */ + break; + } + case 0x4e: + { + sdwCyclesRemaining -= 8; + InvalidInstruction(2); + break; + } + case 0x4f: + { + sdwCyclesRemaining -= 9; + cpu.z80r = cpu.z80A; + break; + } + case 0x50: + { + sdwCyclesRemaining -= 12; + dwAddr = cpu.z80C; + psIoRead = cpu.z80IoRead; /* Beginning of our handler */ + while (psIoRead->lowIoAddr != 0xffff) + { + if ((dwAddr >= psIoRead->lowIoAddr) && (dwAddr <= psIoRead->highIoAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + cpu.z80D = psIoRead->IOCall(dwAddr, psIoRead); + psIoRead = NULL; + break; + } + ++psIoRead; + } + + if (psIoRead) + { + cpu.z80D = 0xff; /* Unclaimed I/O read */ + } + + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostORFlags[cpu.z80D]; + break; + } + case 0x51: + { + sdwCyclesRemaining -= 12; + dwAddr = cpu.z80C; + psIoWrite = cpu.z80IoWrite; /* Beginning of our handler */ + while (psIoWrite->lowIoAddr != 0xffff) + { + if ((dwAddr >= psIoWrite->lowIoAddr) && (dwAddr <= psIoWrite->highIoAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + psIoWrite->IOCall(dwAddr, cpu.z80D, psIoWrite); + psIoWrite = NULL; + break; + } + ++psIoWrite; + } + + break; + } + case 0x52: + { + sdwCyclesRemaining -= 15; + dwTemp = cpu.z80HL - cpu.z80DE - (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= ((dwTemp >> 8) & Z80_FLAG_SIGN); + if (0 == (dwTemp & 0xffff)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + cpu.z80F |= (((cpu.z80HL ^ dwTemp ^ cpu.z80DE) >> 8) & Z80_FLAG_HALF_CARRY); + cpu.z80F |= ((((cpu.z80DE ^ cpu.z80HL) & (cpu.z80DE ^ dwTemp)) >> 13) & Z80_FLAG_OVERFLOW_PARITY); + cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY); + cpu.z80HL = dwTemp & 0xffff; + break; + } + case 0x53: + { + sdwCyclesRemaining -= 20; + dwTemp = *pbPC++; + dwTemp |= ((UINT32) *pbPC++ << 8); + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwTemp >= psMemWrite->lowAddr) && (dwTemp <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwTemp, (cpu.z80DE & 0xff), psMemWrite); + psMemWrite->memoryCall(dwTemp + 1, (cpu.z80DE >> 8), psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwTemp - psMemWrite->lowAddr)) = cpu.z80DE; + *((UINT8 *) psMemWrite->pUserArea + (dwTemp - psMemWrite->lowAddr) + 1) = cpu.z80DE >> 8; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwTemp] = (UINT8) cpu.z80DE; + cpu.z80Base[dwTemp + 1] = (UINT8) ((UINT32) cpu.z80DE >> 8); + } + + break; + } + case 0x54: + { + sdwCyclesRemaining -= 8; + InvalidInstruction(2); + break; + } + case 0x55: + { + sdwCyclesRemaining -= 8; + InvalidInstruction(2); + break; + } + case 0x56: + { + sdwCyclesRemaining -= 8; + cpu.z80interruptMode = 1; + cpu.z80intAddr = 0x38; + break; + } + case 0x57: + { + sdwCyclesRemaining -= 9; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= ((cpu.z80iff & IFF2) << 1); + cpu.z80A = cpu.z80i; + cpu.z80F |= bPostORFlags[cpu.z80A]; + break; + } + case 0x58: + { + sdwCyclesRemaining -= 12; + dwAddr = cpu.z80C; + psIoRead = cpu.z80IoRead; /* Beginning of our handler */ + while (psIoRead->lowIoAddr != 0xffff) + { + if ((dwAddr >= psIoRead->lowIoAddr) && (dwAddr <= psIoRead->highIoAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + cpu.z80E = psIoRead->IOCall(dwAddr, psIoRead); + psIoRead = NULL; + break; + } + ++psIoRead; + } + + if (psIoRead) + { + cpu.z80E = 0xff; /* Unclaimed I/O read */ + } + + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostORFlags[cpu.z80E]; + break; + } + case 0x59: + { + sdwCyclesRemaining -= 12; + dwAddr = cpu.z80C; + psIoWrite = cpu.z80IoWrite; /* Beginning of our handler */ + while (psIoWrite->lowIoAddr != 0xffff) + { + if ((dwAddr >= psIoWrite->lowIoAddr) && (dwAddr <= psIoWrite->highIoAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + psIoWrite->IOCall(dwAddr, cpu.z80E, psIoWrite); + psIoWrite = NULL; + break; + } + ++psIoWrite; + } + + break; + } + case 0x5a: + { + sdwCyclesRemaining -= 15; + dwTemp = cpu.z80HL + cpu.z80DE + (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= ((dwTemp >> 8) & Z80_FLAG_SIGN); + if (0 == (dwTemp & 0xffff)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + cpu.z80F |= (((cpu.z80HL ^ dwTemp ^ cpu.z80DE) >> 8) & Z80_FLAG_HALF_CARRY); + cpu.z80F |= ((((cpu.z80DE ^ cpu.z80HL ^ 0x8000) & (cpu.z80DE ^ dwTemp)) >> 13) & Z80_FLAG_OVERFLOW_PARITY); + cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY); + cpu.z80HL = dwTemp & 0xffff; + break; + } + case 0x5b: + { + sdwCyclesRemaining -= 20; + dwTemp = *pbPC++; + dwTemp |= ((UINT32) *pbPC++ << 8); + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwTemp >= psMemRead->lowAddr) && (dwTemp <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80DE = psMemRead->memoryCall(dwTemp, psMemRead); + cpu.z80DE |= (UINT32) ((UINT32) psMemRead->memoryCall(dwTemp + 1, psMemRead) << 8); + } + else + { + cpu.z80DE = *((UINT8 *) psMemRead->pUserArea + (dwTemp - psMemRead->lowAddr)); + cpu.z80DE |= (UINT32) ((UINT32) *((UINT8 *) psMemRead->pUserArea + (dwTemp - psMemRead->lowAddr + 1)) << 8); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80DE = cpu.z80Base[dwTemp]; + cpu.z80DE |= (UINT32) ((UINT32) cpu.z80Base[dwTemp + 1] << 8); + } + + break; + } + case 0x5c: + { + sdwCyclesRemaining -= 8; + InvalidInstruction(2); + break; + } + case 0x5d: + { + sdwCyclesRemaining -= 8; + InvalidInstruction(2); + break; + } + case 0x5e: + { + sdwCyclesRemaining -= 8; + cpu.z80interruptMode = 2; + break; + } + case 0x5f: + { + sdwCyclesRemaining -= 9; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostORFlags[cpu.z80r]; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_OVERFLOW_PARITY)) | ((cpu.z80iff & IFF2) << 1); + cpu.z80A = cpu.z80r; + bTemp = (cpu.z80r + (cpu.z80B + sdwCyclesRemaining + 1 + cpu.z80H)) ^ cpu.z80A; + cpu.z80r = (cpu.z80r & 0x80) | (bTemp & 0x7f); + break; + } + case 0x60: + { + sdwCyclesRemaining -= 12; + dwAddr = cpu.z80C; + psIoRead = cpu.z80IoRead; /* Beginning of our handler */ + while (psIoRead->lowIoAddr != 0xffff) + { + if ((dwAddr >= psIoRead->lowIoAddr) && (dwAddr <= psIoRead->highIoAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + cpu.z80H = psIoRead->IOCall(dwAddr, psIoRead); + psIoRead = NULL; + break; + } + ++psIoRead; + } + + if (psIoRead) + { + cpu.z80H = 0xff; /* Unclaimed I/O read */ + } + + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostORFlags[cpu.z80H]; + break; + } + case 0x61: + { + sdwCyclesRemaining -= 12; + dwAddr = cpu.z80C; + psIoWrite = cpu.z80IoWrite; /* Beginning of our handler */ + while (psIoWrite->lowIoAddr != 0xffff) + { + if ((dwAddr >= psIoWrite->lowIoAddr) && (dwAddr <= psIoWrite->highIoAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + psIoWrite->IOCall(dwAddr, cpu.z80H, psIoWrite); + psIoWrite = NULL; + break; + } + ++psIoWrite; + } + + break; + } + case 0x62: + { + sdwCyclesRemaining -= 15; + dwTemp = cpu.z80HL - cpu.z80HL - (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= ((dwTemp >> 8) & Z80_FLAG_SIGN); + if (0 == (dwTemp & 0xffff)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + cpu.z80F |= (((cpu.z80HL ^ dwTemp ^ cpu.z80HL) >> 8) & Z80_FLAG_HALF_CARRY); + cpu.z80F |= ((((cpu.z80HL ^ cpu.z80HL) & (cpu.z80HL ^ dwTemp)) >> 13) & Z80_FLAG_OVERFLOW_PARITY); + cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY); + cpu.z80HL = dwTemp & 0xffff; + break; + } + case 0x63: + { + sdwCyclesRemaining -= 20; + dwTemp = *pbPC++; + dwTemp |= ((UINT32) *pbPC++ << 8); + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwTemp >= psMemWrite->lowAddr) && (dwTemp <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwTemp, (cpu.z80HL & 0xff), psMemWrite); + psMemWrite->memoryCall(dwTemp + 1, (cpu.z80HL >> 8), psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwTemp - psMemWrite->lowAddr)) = cpu.z80HL; + *((UINT8 *) psMemWrite->pUserArea + (dwTemp - psMemWrite->lowAddr) + 1) = cpu.z80HL >> 8; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwTemp] = (UINT8) cpu.z80HL; + cpu.z80Base[dwTemp + 1] = (UINT8) ((UINT32) cpu.z80HL >> 8); + } + + break; + } + case 0x64: + { + sdwCyclesRemaining -= 8; + InvalidInstruction(2); + break; + } + case 0x65: + { + sdwCyclesRemaining -= 8; + InvalidInstruction(2); + break; + } + case 0x66: + { + sdwCyclesRemaining -= 8; + InvalidInstruction(2); + break; + } + case 0x67: + { + sdwCyclesRemaining -= 18; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + bTemp2 = (cpu.z80A & 0x0f) << 4; + cpu.z80A = (cpu.z80A & 0xf0) | (bTemp & 0x0f); + bTemp = (bTemp >> 4) | bTemp2; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostORFlags[cpu.z80A]; + break; + } + case 0x68: + { + sdwCyclesRemaining -= 12; + dwAddr = cpu.z80C; + psIoRead = cpu.z80IoRead; /* Beginning of our handler */ + while (psIoRead->lowIoAddr != 0xffff) + { + if ((dwAddr >= psIoRead->lowIoAddr) && (dwAddr <= psIoRead->highIoAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + cpu.z80L = psIoRead->IOCall(dwAddr, psIoRead); + psIoRead = NULL; + break; + } + ++psIoRead; + } + + if (psIoRead) + { + cpu.z80L = 0xff; /* Unclaimed I/O read */ + } + + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostORFlags[cpu.z80L]; + break; + } + case 0x69: + { + sdwCyclesRemaining -= 12; + dwAddr = cpu.z80C; + psIoWrite = cpu.z80IoWrite; /* Beginning of our handler */ + while (psIoWrite->lowIoAddr != 0xffff) + { + if ((dwAddr >= psIoWrite->lowIoAddr) && (dwAddr <= psIoWrite->highIoAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + psIoWrite->IOCall(dwAddr, cpu.z80L, psIoWrite); + psIoWrite = NULL; + break; + } + ++psIoWrite; + } + + break; + } + case 0x6a: + { + sdwCyclesRemaining -= 15; + dwTemp = cpu.z80HL + cpu.z80HL + (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= ((dwTemp >> 8) & Z80_FLAG_SIGN); + if (0 == (dwTemp & 0xffff)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + cpu.z80F |= (((cpu.z80HL ^ dwTemp ^ cpu.z80HL) >> 8) & Z80_FLAG_HALF_CARRY); + cpu.z80F |= ((((cpu.z80HL ^ cpu.z80HL ^ 0x8000) & (cpu.z80HL ^ dwTemp)) >> 13) & Z80_FLAG_OVERFLOW_PARITY); + cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY); + cpu.z80HL = dwTemp & 0xffff; + break; + } + case 0x6b: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(2); + break; + } + case 0x6c: + { + sdwCyclesRemaining -= 8; + InvalidInstruction(2); + break; + } + case 0x6d: + { + sdwCyclesRemaining -= 8; + InvalidInstruction(2); + break; + } + case 0x6e: + { + sdwCyclesRemaining -= 8; + InvalidInstruction(2); + break; + } + case 0x6f: + { + sdwCyclesRemaining -= 18; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + bTemp2 = (cpu.z80A & 0x0f); + cpu.z80A = (cpu.z80A & 0xf0) | (bTemp >> 4); + bTemp = (bTemp << 4) | bTemp2; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostORFlags[cpu.z80A]; + break; + } + case 0x70: + { + sdwCyclesRemaining -= 12; + InvalidInstruction(2); + break; + } + case 0x71: + { + sdwCyclesRemaining -= 12; + InvalidInstruction(2); + break; + } + case 0x72: + { + sdwCyclesRemaining -= 15; + dwTemp = cpu.z80HL - cpu.z80sp - (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= ((dwTemp >> 8) & Z80_FLAG_SIGN); + if (0 == (dwTemp & 0xffff)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + cpu.z80F |= (((cpu.z80HL ^ dwTemp ^ cpu.z80sp) >> 8) & Z80_FLAG_HALF_CARRY); + cpu.z80F |= ((((cpu.z80sp ^ cpu.z80HL) & (cpu.z80sp ^ dwTemp)) >> 13) & Z80_FLAG_OVERFLOW_PARITY); + cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY); + cpu.z80HL = dwTemp & 0xffff; + break; + } + case 0x73: + { + sdwCyclesRemaining -= 20; + dwTemp = *pbPC++; + dwTemp |= ((UINT32) *pbPC++ << 8); + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwTemp >= psMemWrite->lowAddr) && (dwTemp <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwTemp, (cpu.z80sp & 0xff), psMemWrite); + psMemWrite->memoryCall(dwTemp + 1, (cpu.z80sp >> 8), psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwTemp - psMemWrite->lowAddr)) = cpu.z80sp; + *((UINT8 *) psMemWrite->pUserArea + (dwTemp - psMemWrite->lowAddr) + 1) = cpu.z80sp >> 8; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwTemp] = (UINT8) cpu.z80sp; + cpu.z80Base[dwTemp + 1] = (UINT8) ((UINT32) cpu.z80sp >> 8); + } + + break; + } + case 0x74: + { + sdwCyclesRemaining -= 8; + InvalidInstruction(2); + break; + } + case 0x75: + { + sdwCyclesRemaining -= 8; + InvalidInstruction(2); + break; + } + case 0x76: + { + sdwCyclesRemaining -= 8; + InvalidInstruction(2); + break; + } + case 0x77: + { + InvalidInstruction(2); + break; + } + case 0x78: + { + sdwCyclesRemaining -= 12; + dwAddr = cpu.z80C; + psIoRead = cpu.z80IoRead; /* Beginning of our handler */ + while (psIoRead->lowIoAddr != 0xffff) + { + if ((dwAddr >= psIoRead->lowIoAddr) && (dwAddr <= psIoRead->highIoAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + cpu.z80A = psIoRead->IOCall(dwAddr, psIoRead); + psIoRead = NULL; + break; + } + ++psIoRead; + } + + if (psIoRead) + { + cpu.z80A = 0xff; /* Unclaimed I/O read */ + } + + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostORFlags[cpu.z80A]; + break; + } + case 0x79: + { + sdwCyclesRemaining -= 12; + dwAddr = cpu.z80C; + psIoWrite = cpu.z80IoWrite; /* Beginning of our handler */ + while (psIoWrite->lowIoAddr != 0xffff) + { + if ((dwAddr >= psIoWrite->lowIoAddr) && (dwAddr <= psIoWrite->highIoAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + psIoWrite->IOCall(dwAddr, cpu.z80A, psIoWrite); + psIoWrite = NULL; + break; + } + ++psIoWrite; + } + + break; + } + case 0x7a: + { + sdwCyclesRemaining -= 15; + dwTemp = cpu.z80HL + cpu.z80sp + (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= ((dwTemp >> 8) & Z80_FLAG_SIGN); + if (0 == (dwTemp & 0xffff)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + cpu.z80F |= (((cpu.z80HL ^ dwTemp ^ cpu.z80sp) >> 8) & Z80_FLAG_HALF_CARRY); + cpu.z80F |= ((((cpu.z80sp ^ cpu.z80HL ^ 0x8000) & (cpu.z80sp ^ dwTemp)) >> 13) & Z80_FLAG_OVERFLOW_PARITY); + cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY); + cpu.z80HL = dwTemp & 0xffff; + break; + } + case 0x7b: + { + sdwCyclesRemaining -= 20; + dwTemp = *pbPC++; + dwTemp |= ((UINT32) *pbPC++ << 8); + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwTemp >= psMemRead->lowAddr) && (dwTemp <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80sp = psMemRead->memoryCall(dwTemp, psMemRead); + cpu.z80sp |= (UINT32) ((UINT32) psMemRead->memoryCall(dwTemp + 1, psMemRead) << 8); + } + else + { + cpu.z80sp = *((UINT8 *) psMemRead->pUserArea + (dwTemp - psMemRead->lowAddr)); + cpu.z80sp |= (UINT32) ((UINT32) *((UINT8 *) psMemRead->pUserArea + (dwTemp - psMemRead->lowAddr + 1)) << 8); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80sp = cpu.z80Base[dwTemp]; + cpu.z80sp |= (UINT32) ((UINT32) cpu.z80Base[dwTemp + 1] << 8); + } + + break; + } + case 0x7c: + { + sdwCyclesRemaining -= 8; + InvalidInstruction(2); + break; + } + case 0x7d: + { + sdwCyclesRemaining -= 8; + InvalidInstruction(2); + break; + } + case 0x7e: + { + sdwCyclesRemaining -= 8; + InvalidInstruction(2); + break; + } + case 0x7f: + { + InvalidInstruction(2); + break; + } + case 0x80: + { + InvalidInstruction(2); + break; + } + case 0x81: + { + InvalidInstruction(2); + break; + } + case 0x82: + { + InvalidInstruction(2); + break; + } + case 0x83: + { + InvalidInstruction(2); + break; + } + case 0x84: + { + InvalidInstruction(2); + break; + } + case 0x85: + { + InvalidInstruction(2); + break; + } + case 0x86: + { + InvalidInstruction(2); + break; + } + case 0x87: + { + InvalidInstruction(2); + break; + } + case 0x88: + { + InvalidInstruction(2); + break; + } + case 0x89: + { + InvalidInstruction(2); + break; + } + case 0x8a: + { + InvalidInstruction(2); + break; + } + case 0x8b: + { + InvalidInstruction(2); + break; + } + case 0x8c: + { + InvalidInstruction(2); + break; + } + case 0x8d: + { + InvalidInstruction(2); + break; + } + case 0x8e: + { + InvalidInstruction(2); + break; + } + case 0x8f: + { + InvalidInstruction(2); + break; + } + case 0x90: + { + InvalidInstruction(2); + break; + } + case 0x91: + { + InvalidInstruction(2); + break; + } + case 0x92: + { + InvalidInstruction(2); + break; + } + case 0x93: + { + InvalidInstruction(2); + break; + } + case 0x94: + { + InvalidInstruction(2); + break; + } + case 0x95: + { + InvalidInstruction(2); + break; + } + case 0x96: + { + InvalidInstruction(2); + break; + } + case 0x97: + { + InvalidInstruction(2); + break; + } + case 0x98: + { + InvalidInstruction(2); + break; + } + case 0x99: + { + InvalidInstruction(2); + break; + } + case 0x9a: + { + InvalidInstruction(2); + break; + } + case 0x9b: + { + InvalidInstruction(2); + break; + } + case 0x9c: + { + InvalidInstruction(2); + break; + } + case 0x9d: + { + InvalidInstruction(2); + break; + } + case 0x9e: + { + InvalidInstruction(2); + break; + } + case 0x9f: + { + InvalidInstruction(2); + break; + } + case 0xa0: + { + sdwCyclesRemaining -= 16; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80DE >= psMemWrite->lowAddr) && (cpu.z80DE <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80DE, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80DE - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80DE] = (UINT8) bTemp; + } + + ++cpu.z80HL; + ++cpu.z80DE; + --cpu.z80BC; + cpu.z80HL &= 0xffff; + cpu.z80DE &= 0xffff; + cpu.z80BC &= 0xffff; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY); + if (cpu.z80BC) + { + cpu.z80F |= Z80_FLAG_OVERFLOW_PARITY; + } + break; + } + case 0xa1: + { + sdwCyclesRemaining -= 16; + { + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + cpu.z80HL++; + cpu.z80HL &= 0xffff; + cpu.z80BC--; + cpu.z80BC &= 0xffff; + } + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= (pbSubSbcTable[((UINT32) cpu.z80A << 8) | bTemp] & (Z80_FLAG_SIGN | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO)); + if (cpu.z80BC) + { + cpu.z80F |= Z80_FLAG_OVERFLOW_PARITY; + } + break; + } + case 0xa2: + { + sdwCyclesRemaining -= 16; + { + psIoRead = cpu.z80IoRead; /* Beginning of our handler */ + while (psIoRead->lowIoAddr != 0xffff) + { + if ((cpu.z80B >= psIoRead->lowIoAddr) && (cpu.z80B <= psIoRead->highIoAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + bTemp = psIoRead->IOCall(cpu.z80B, psIoRead); + psIoRead = NULL; + break; + } + ++psIoRead; + } + + if (psIoRead) + { + bTemp = 0xff; /* Unclaimed I/O read */ + } + + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + cpu.z80HL++; + cpu.z80HL &= 0xffff; + sdwCyclesRemaining -= 16; + cpu.z80B--; + } + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= (bPostORFlags[bTemp] & (Z80_FLAG_SIGN | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY)); + if (cpu.z80B) + { + cpu.z80F |= Z80_FLAG_OVERFLOW_PARITY; + pbPC -= 2; + } + break; + } + case 0xa3: + { + sdwCyclesRemaining -= 16; + { + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + psIoWrite = cpu.z80IoWrite; /* Beginning of our handler */ + while (psIoWrite->lowIoAddr != 0xffff) + { + if ((cpu.z80BC >= psIoWrite->lowIoAddr) && (cpu.z80BC <= psIoWrite->highIoAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + psIoWrite->IOCall(cpu.z80BC, bTemp, psIoWrite); + psIoWrite = NULL; + break; + } + ++psIoWrite; + } + + cpu.z80HL++; + cpu.z80HL &= 0xffff; + sdwCyclesRemaining -= 16; + cpu.z80B--; + } + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= (bPostORFlags[bTemp] & (Z80_FLAG_SIGN | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY)); + if (cpu.z80B) + { + cpu.z80F |= Z80_FLAG_OVERFLOW_PARITY; + } + break; + } + case 0xa4: + { + InvalidInstruction(2); + break; + } + case 0xa5: + { + InvalidInstruction(2); + break; + } + case 0xa6: + { + InvalidInstruction(2); + break; + } + case 0xa7: + { + InvalidInstruction(2); + break; + } + case 0xa8: + { + sdwCyclesRemaining -= 16; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80DE >= psMemWrite->lowAddr) && (cpu.z80DE <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80DE, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80DE - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80DE] = (UINT8) bTemp; + } + + --cpu.z80HL; + --cpu.z80DE; + --cpu.z80BC; + cpu.z80HL &= 0xffff; + cpu.z80DE &= 0xffff; + cpu.z80BC &= 0xffff; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY); + if (cpu.z80BC) + { + cpu.z80F |= Z80_FLAG_OVERFLOW_PARITY; + } + break; + } + case 0xa9: + { + sdwCyclesRemaining -= 16; + { + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + cpu.z80HL--; + cpu.z80HL &= 0xffff; + cpu.z80BC--; + cpu.z80BC &= 0xffff; + } + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= (pbSubSbcTable[((UINT32) cpu.z80A << 8) | bTemp] & (Z80_FLAG_SIGN | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO)); + if (cpu.z80BC) + { + cpu.z80F |= Z80_FLAG_OVERFLOW_PARITY; + } + break; + } + case 0xaa: + { + sdwCyclesRemaining -= 16; + { + psIoRead = cpu.z80IoRead; /* Beginning of our handler */ + while (psIoRead->lowIoAddr != 0xffff) + { + if ((cpu.z80B >= psIoRead->lowIoAddr) && (cpu.z80B <= psIoRead->highIoAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + bTemp = psIoRead->IOCall(cpu.z80B, psIoRead); + psIoRead = NULL; + break; + } + ++psIoRead; + } + + if (psIoRead) + { + bTemp = 0xff; /* Unclaimed I/O read */ + } + + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + cpu.z80HL--; + cpu.z80HL &= 0xffff; + sdwCyclesRemaining -= 16; + cpu.z80B--; + } + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= (bPostORFlags[bTemp] & (Z80_FLAG_SIGN | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY)); + if (cpu.z80B) + { + cpu.z80F |= Z80_FLAG_OVERFLOW_PARITY; + pbPC -= 2; + } + break; + } + case 0xab: + { + sdwCyclesRemaining -= 16; + { + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + psIoWrite = cpu.z80IoWrite; /* Beginning of our handler */ + while (psIoWrite->lowIoAddr != 0xffff) + { + if ((cpu.z80BC >= psIoWrite->lowIoAddr) && (cpu.z80BC <= psIoWrite->highIoAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + psIoWrite->IOCall(cpu.z80BC, bTemp, psIoWrite); + psIoWrite = NULL; + break; + } + ++psIoWrite; + } + + cpu.z80HL--; + cpu.z80HL &= 0xffff; + sdwCyclesRemaining -= 16; + cpu.z80B--; + } + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= (bPostORFlags[bTemp] & (Z80_FLAG_SIGN | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY)); + if (cpu.z80B) + { + cpu.z80F |= Z80_FLAG_OVERFLOW_PARITY; + } + break; + } + case 0xac: + { + InvalidInstruction(2); + break; + } + case 0xad: + { + InvalidInstruction(2); + break; + } + case 0xae: + { + InvalidInstruction(2); + break; + } + case 0xaf: + { + InvalidInstruction(2); + break; + } + case 0xb0: + { + sdwCyclesRemaining -= 16; + while ((sdwCyclesRemaining > 0) && (cpu.z80BC)) + { + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80DE >= psMemWrite->lowAddr) && (cpu.z80DE <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80DE, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80DE - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80DE] = (UINT8) bTemp; + } + + ++cpu.z80HL; + ++cpu.z80DE; + --cpu.z80BC; + cpu.z80HL &= 0xffff; + cpu.z80DE &= 0xffff; + cpu.z80BC &= 0xffff; + sdwCyclesRemaining -= 21; + } + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY); + if (cpu.z80BC) + { + pbPC -= 2; /* Back up so we hit this instruction again */ + cpu.z80F |= Z80_FLAG_OVERFLOW_PARITY; + } + sdwCyclesRemaining -= 16; + break; + } + case 0xb1: + { + sdwCyclesRemaining -= 16; + while ((sdwCyclesRemaining >= 0) && (cpu.z80BC)) + { + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + cpu.z80HL++; + cpu.z80HL &= 0xffff; + cpu.z80BC--; + cpu.z80BC &= 0xffff; + sdwCyclesRemaining -= 16; + if (cpu.z80A == bTemp) + { + break; + } + } + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= (pbSubSbcTable[((UINT32) cpu.z80A << 8) | bTemp] & (Z80_FLAG_SIGN | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO)); + if (cpu.z80BC) + { + cpu.z80F |= Z80_FLAG_OVERFLOW_PARITY; + } + break; + } + case 0xb2: + { + sdwCyclesRemaining -= 16; + while ((sdwCyclesRemaining > 0) && (cpu.z80B)) + { + psIoRead = cpu.z80IoRead; /* Beginning of our handler */ + while (psIoRead->lowIoAddr != 0xffff) + { + if ((cpu.z80B >= psIoRead->lowIoAddr) && (cpu.z80B <= psIoRead->highIoAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + bTemp = psIoRead->IOCall(cpu.z80B, psIoRead); + psIoRead = NULL; + break; + } + ++psIoRead; + } + + if (psIoRead) + { + bTemp = 0xff; /* Unclaimed I/O read */ + } + + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + cpu.z80HL++; + cpu.z80HL &= 0xffff; + sdwCyclesRemaining -= 16; + cpu.z80B--; + } + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= (bPostORFlags[bTemp] & (Z80_FLAG_SIGN | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY)); + if (cpu.z80B) + { + cpu.z80F |= Z80_FLAG_OVERFLOW_PARITY; + pbPC -= 2; + } + break; + } + case 0xb3: + { + sdwCyclesRemaining -= 16; + while ((sdwCyclesRemaining > 0) && (cpu.z80B)) + { + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + psIoWrite = cpu.z80IoWrite; /* Beginning of our handler */ + while (psIoWrite->lowIoAddr != 0xffff) + { + if ((cpu.z80BC >= psIoWrite->lowIoAddr) && (cpu.z80BC <= psIoWrite->highIoAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + psIoWrite->IOCall(cpu.z80BC, bTemp, psIoWrite); + psIoWrite = NULL; + break; + } + ++psIoWrite; + } + + cpu.z80HL++; + cpu.z80HL &= 0xffff; + sdwCyclesRemaining -= 16; + cpu.z80B--; + } + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= (bPostORFlags[bTemp] & (Z80_FLAG_SIGN | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY)); + if (cpu.z80B) + { + cpu.z80F |= Z80_FLAG_OVERFLOW_PARITY; + } + break; + } + case 0xb4: + { + InvalidInstruction(2); + break; + } + case 0xb5: + { + InvalidInstruction(2); + break; + } + case 0xb6: + { + InvalidInstruction(2); + break; + } + case 0xb7: + { + InvalidInstruction(2); + break; + } + case 0xb8: + { + sdwCyclesRemaining -= 16; + while ((sdwCyclesRemaining > 0) && (cpu.z80BC)) + { + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80DE >= psMemWrite->lowAddr) && (cpu.z80DE <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80DE, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80DE - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80DE] = (UINT8) bTemp; + } + + --cpu.z80HL; + --cpu.z80DE; + --cpu.z80BC; + cpu.z80HL &= 0xffff; + cpu.z80DE &= 0xffff; + cpu.z80BC &= 0xffff; + sdwCyclesRemaining -= 21; + } + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY); + if (cpu.z80BC) + { + pbPC -= 2; /* Back up so we hit this instruction again */ + cpu.z80F |= Z80_FLAG_OVERFLOW_PARITY; + } + sdwCyclesRemaining -= 16; + break; + } + case 0xb9: + { + sdwCyclesRemaining -= 16; + while ((sdwCyclesRemaining >= 0) && (cpu.z80BC)) + { + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + cpu.z80HL--; + cpu.z80HL &= 0xffff; + cpu.z80BC--; + cpu.z80BC &= 0xffff; + sdwCyclesRemaining -= 16; + if (cpu.z80A == bTemp) + { + break; + } + } + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= (pbSubSbcTable[((UINT32) cpu.z80A << 8) | bTemp] & (Z80_FLAG_SIGN | Z80_FLAG_NEGATIVE | Z80_FLAG_ZERO)); + if (cpu.z80BC) + { + cpu.z80F |= Z80_FLAG_OVERFLOW_PARITY; + } + break; + } + case 0xba: + { + sdwCyclesRemaining -= 16; + while ((sdwCyclesRemaining > 0) && (cpu.z80B)) + { + psIoRead = cpu.z80IoRead; /* Beginning of our handler */ + while (psIoRead->lowIoAddr != 0xffff) + { + if ((cpu.z80B >= psIoRead->lowIoAddr) && (cpu.z80B <= psIoRead->highIoAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + bTemp = psIoRead->IOCall(cpu.z80B, psIoRead); + psIoRead = NULL; + break; + } + ++psIoRead; + } + + if (psIoRead) + { + bTemp = 0xff; /* Unclaimed I/O read */ + } + + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + cpu.z80HL--; + cpu.z80HL &= 0xffff; + sdwCyclesRemaining -= 16; + cpu.z80B--; + } + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= (bPostORFlags[bTemp] & (Z80_FLAG_SIGN | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY)); + if (cpu.z80B) + { + cpu.z80F |= Z80_FLAG_OVERFLOW_PARITY; + pbPC -= 2; + } + break; + } + case 0xbb: + { + sdwCyclesRemaining -= 16; + while ((sdwCyclesRemaining > 0) && (cpu.z80B)) + { + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + psIoWrite = cpu.z80IoWrite; /* Beginning of our handler */ + while (psIoWrite->lowIoAddr != 0xffff) + { + if ((cpu.z80BC >= psIoWrite->lowIoAddr) && (cpu.z80BC <= psIoWrite->highIoAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + psIoWrite->IOCall(cpu.z80BC, bTemp, psIoWrite); + psIoWrite = NULL; + break; + } + ++psIoWrite; + } + + cpu.z80HL--; + cpu.z80HL &= 0xffff; + sdwCyclesRemaining -= 16; + cpu.z80B--; + } + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= (bPostORFlags[bTemp] & (Z80_FLAG_SIGN | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY)); + if (cpu.z80B) + { + cpu.z80F |= Z80_FLAG_OVERFLOW_PARITY; + } + break; + } + case 0xbc: + { + InvalidInstruction(2); + break; + } + case 0xbd: + { + InvalidInstruction(2); + break; + } + case 0xbe: + { + InvalidInstruction(2); + break; + } + case 0xbf: + { + InvalidInstruction(2); + break; + } + case 0xc0: + { + InvalidInstruction(2); + break; + } + case 0xc1: + { + InvalidInstruction(2); + break; + } + case 0xc2: + { + InvalidInstruction(2); + break; + } + case 0xc3: + { + InvalidInstruction(2); + break; + } + case 0xc4: + { + InvalidInstruction(2); + break; + } + case 0xc5: + { + InvalidInstruction(2); + break; + } + case 0xc6: + { + InvalidInstruction(2); + break; + } + case 0xc7: + { + InvalidInstruction(2); + break; + } + case 0xc8: + { + InvalidInstruction(2); + break; + } + case 0xc9: + { + InvalidInstruction(2); + break; + } + case 0xca: + { + InvalidInstruction(2); + break; + } + case 0xcb: + { + InvalidInstruction(2); + break; + } + case 0xcc: + { + InvalidInstruction(2); + break; + } + case 0xcd: + { + InvalidInstruction(2); + break; + } + case 0xce: + { + InvalidInstruction(2); + break; + } + case 0xcf: + { + InvalidInstruction(2); + break; + } + case 0xd0: + { + InvalidInstruction(2); + break; + } + case 0xd1: + { + InvalidInstruction(2); + break; + } + case 0xd2: + { + InvalidInstruction(2); + break; + } + case 0xd3: + { + InvalidInstruction(2); + break; + } + case 0xd4: + { + InvalidInstruction(2); + break; + } + case 0xd5: + { + InvalidInstruction(2); + break; + } + case 0xd6: + { + InvalidInstruction(2); + break; + } + case 0xd7: + { + InvalidInstruction(2); + break; + } + case 0xd8: + { + InvalidInstruction(2); + break; + } + case 0xd9: + { + InvalidInstruction(2); + break; + } + case 0xda: + { + InvalidInstruction(2); + break; + } + case 0xdb: + { + InvalidInstruction(2); + break; + } + case 0xdc: + { + InvalidInstruction(2); + break; + } + case 0xdd: + { + InvalidInstruction(2); + break; + } + case 0xde: + { + InvalidInstruction(2); + break; + } + case 0xdf: + { + InvalidInstruction(2); + break; + } + case 0xe0: + { + InvalidInstruction(2); + break; + } + case 0xe1: + { + InvalidInstruction(2); + break; + } + case 0xe2: + { + InvalidInstruction(2); + break; + } + case 0xe3: + { + InvalidInstruction(2); + break; + } + case 0xe4: + { + InvalidInstruction(2); + break; + } + case 0xe5: + { + InvalidInstruction(2); + break; + } + case 0xe6: + { + InvalidInstruction(2); + break; + } + case 0xe7: + { + InvalidInstruction(2); + break; + } + case 0xe8: + { + InvalidInstruction(2); + break; + } + case 0xe9: + { + InvalidInstruction(2); + break; + } + case 0xea: + { + InvalidInstruction(2); + break; + } + case 0xeb: + { + InvalidInstruction(2); + break; + } + case 0xec: + { + InvalidInstruction(2); + break; + } + case 0xed: + { + InvalidInstruction(2); + break; + } + case 0xee: + { + InvalidInstruction(2); + break; + } + case 0xef: + { + InvalidInstruction(2); + break; + } + case 0xf0: + { + InvalidInstruction(2); + break; + } + case 0xf1: + { + InvalidInstruction(2); + break; + } + case 0xf2: + { + InvalidInstruction(2); + break; + } + case 0xf3: + { + InvalidInstruction(2); + break; + } + case 0xf4: + { + InvalidInstruction(2); + break; + } + case 0xf5: + { + InvalidInstruction(2); + break; + } + case 0xf6: + { + InvalidInstruction(2); + break; + } + case 0xf7: + { + InvalidInstruction(2); + break; + } + case 0xf8: + { + InvalidInstruction(2); + break; + } + case 0xf9: + { + InvalidInstruction(2); + break; + } + case 0xfa: + { + InvalidInstruction(2); + break; + } + case 0xfb: + { + InvalidInstruction(2); + break; + } + case 0xfc: + { + InvalidInstruction(2); + break; + } + case 0xfd: + { + InvalidInstruction(2); + break; + } + case 0xfe: + { + InvalidInstruction(2); + break; + } + case 0xff: + { + InvalidInstruction(2); + break; + } + } +} + +void DDHandler(void) +{ + switch (*pbPC++) + { + case 0x00: + { + InvalidInstruction(2); + break; + } + case 0x01: + { + InvalidInstruction(2); + break; + } + case 0x02: + { + InvalidInstruction(2); + break; + } + case 0x03: + { + InvalidInstruction(2); + break; + } + case 0x04: + { + InvalidInstruction(2); + break; + } + case 0x05: + { + InvalidInstruction(2); + break; + } + case 0x06: + { + InvalidInstruction(2); + break; + } + case 0x07: + { + InvalidInstruction(2); + break; + } + case 0x08: + { + InvalidInstruction(2); + break; + } + case 0x09: + { + sdwCyclesRemaining -= 15; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY); + dwTemp = cpu.z80IX + cpu.z80BC; + cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY) | (((cpu.z80IX ^ dwTemp ^ cpu.z80BC) >> 8) & Z80_FLAG_HALF_CARRY); + cpu.z80IX = dwTemp & 0xffff; + break; + } + case 0x0a: + { + InvalidInstruction(2); + break; + } + case 0x0b: + { + InvalidInstruction(2); + break; + } + case 0x0c: + { + InvalidInstruction(2); + break; + } + case 0x0d: + { + InvalidInstruction(2); + break; + } + case 0x0e: + { + InvalidInstruction(2); + break; + } + case 0x0f: + { + InvalidInstruction(2); + break; + } + case 0x10: + { + InvalidInstruction(2); + break; + } + case 0x11: + { + InvalidInstruction(2); + break; + } + case 0x12: + { + InvalidInstruction(2); + break; + } + case 0x13: + { + InvalidInstruction(2); + break; + } + case 0x14: + { + InvalidInstruction(2); + break; + } + case 0x15: + { + InvalidInstruction(2); + break; + } + case 0x16: + { + InvalidInstruction(2); + break; + } + case 0x17: + { + InvalidInstruction(2); + break; + } + case 0x18: + { + InvalidInstruction(2); + break; + } + case 0x19: + { + sdwCyclesRemaining -= 15; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY); + dwTemp = cpu.z80IX + cpu.z80DE; + cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY) | (((cpu.z80IX ^ dwTemp ^ cpu.z80DE) >> 8) & Z80_FLAG_HALF_CARRY); + cpu.z80IX = dwTemp & 0xffff; + break; + } + case 0x1a: + { + InvalidInstruction(2); + break; + } + case 0x1b: + { + InvalidInstruction(2); + break; + } + case 0x1c: + { + InvalidInstruction(2); + break; + } + case 0x1d: + { + InvalidInstruction(2); + break; + } + case 0x1e: + { + InvalidInstruction(2); + break; + } + case 0x1f: + { + InvalidInstruction(2); + break; + } + case 0x20: + { + InvalidInstruction(2); + break; + } + case 0x21: + { + sdwCyclesRemaining -= 14; + cpu.z80IX = *pbPC++; + cpu.z80IX |= ((UINT32) *pbPC++ << 8); + break; + } + case 0x22: + { + sdwCyclesRemaining -= 20; + dwAddr = *pbPC++; + dwAddr |= ((UINT32) *pbPC++ << 8); + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, (cpu.z80IX & 0xff), psMemWrite); + psMemWrite->memoryCall(dwAddr + 1, (cpu.z80IX >> 8), psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = cpu.z80IX; + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr) + 1) = cpu.z80IX >> 8; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) cpu.z80IX; + cpu.z80Base[dwAddr + 1] = (UINT8) ((UINT32) cpu.z80IX >> 8); + } + + break; + } + case 0x23: + { + sdwCyclesRemaining -= 10; + cpu.z80IX++; + cpu.z80IX &= 0xffff; + break; + } + case 0x24: + { + sdwCyclesRemaining -= 9; + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostIncFlags[cpu.z80XH++]; + break; + } + case 0x25: + { + sdwCyclesRemaining -= 9; + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostDecFlags[cpu.z80XH--]; + break; + } + case 0x26: + { + sdwCyclesRemaining -= 9; + cpu.z80XH = *pbPC++; + break; + } + case 0x27: + { + InvalidInstruction(2); + break; + } + case 0x28: + { + InvalidInstruction(2); + break; + } + case 0x29: + { + sdwCyclesRemaining -= 15; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY); + dwTemp = cpu.z80IX + cpu.z80IX; + cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY) | (((cpu.z80IX ^ dwTemp ^ cpu.z80HL) >> 8) & Z80_FLAG_HALF_CARRY); + cpu.z80IX = dwTemp & 0xffff; + break; + } + case 0x2a: + { + sdwCyclesRemaining -= 20; + dwAddr = *pbPC++; + dwAddr |= ((UINT32) *pbPC++ << 8); + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemRead->lowAddr) && (dwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80IX = psMemRead->memoryCall(dwAddr, psMemRead); + cpu.z80IX |= (UINT32) ((UINT32) psMemRead->memoryCall(dwAddr + 1, psMemRead) << 8); + } + else + { + cpu.z80IX = *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr)); + cpu.z80IX |= (UINT32) ((UINT32) *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr + 1)) << 8); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80IX = cpu.z80Base[dwAddr]; + cpu.z80IX |= (UINT32) ((UINT32) cpu.z80Base[dwAddr + 1] << 8); + } + + break; + } + case 0x2b: + { + sdwCyclesRemaining -= 10; + cpu.z80IX--; + cpu.z80IX &= 0xffff; + break; + } + case 0x2c: + { + sdwCyclesRemaining -= 9; + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostIncFlags[cpu.z80XL++]; + break; + } + case 0x2d: + { + sdwCyclesRemaining -= 9; + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostDecFlags[cpu.z80XL--]; + break; + } + case 0x2e: + { + sdwCyclesRemaining -= 9; + cpu.z80XL = *pbPC++; + break; + } + case 0x2f: + { + InvalidInstruction(2); + break; + } + case 0x30: + { + InvalidInstruction(2); + break; + } + case 0x31: + { + InvalidInstruction(2); + break; + } + case 0x32: + { + InvalidInstruction(2); + break; + } + case 0x33: + { + InvalidInstruction(2); + break; + } + case 0x34: + { + sdwCyclesRemaining -= 23; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + dwAddr = (sdwAddr + (INT32) cpu.z80IX) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemRead->lowAddr) && (dwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(dwAddr, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[dwAddr]; + } + + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostIncFlags[bTemp++]; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0x35: + { + sdwCyclesRemaining -= 23; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + dwAddr = (sdwAddr + (INT32) cpu.z80IX) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemRead->lowAddr) && (dwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(dwAddr, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[dwAddr]; + } + + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostDecFlags[bTemp--]; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0x36: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IX + sdwAddr) & 0xffff; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemWrite->lowAddr) && (sdwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(sdwAddr, *pbPC++, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (sdwAddr - psMemWrite->lowAddr)) = *pbPC++; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[sdwAddr] = (UINT8) *pbPC++; + } + + break; + } + case 0x37: + { + InvalidInstruction(2); + break; + } + case 0x38: + { + InvalidInstruction(2); + break; + } + case 0x39: + { + sdwCyclesRemaining -= 15; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY); + dwTemp = cpu.z80IX + cpu.z80sp; + cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY) | (((cpu.z80IX ^ dwTemp ^ cpu.z80sp) >> 8) & Z80_FLAG_HALF_CARRY); + cpu.z80IX = dwTemp & 0xffff; + break; + } + case 0x3a: + { + InvalidInstruction(2); + break; + } + case 0x3b: + { + InvalidInstruction(2); + break; + } + case 0x3c: + { + InvalidInstruction(2); + break; + } + case 0x3d: + { + InvalidInstruction(2); + break; + } + case 0x3e: + { + InvalidInstruction(2); + break; + } + case 0x3f: + { + InvalidInstruction(2); + break; + } + case 0x40: + { + InvalidInstruction(2); + break; + } + case 0x41: + { + InvalidInstruction(2); + break; + } + case 0x42: + { + InvalidInstruction(2); + break; + } + case 0x43: + { + InvalidInstruction(2); + break; + } + case 0x44: + { + sdwCyclesRemaining -= 9; + cpu.z80B = cpu.z80XH; + break; + } + case 0x45: + { + sdwCyclesRemaining -= 9; + cpu.z80B = cpu.z80XL; + break; + } + case 0x46: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IX + sdwAddr) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemRead->lowAddr) && (sdwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80B = psMemRead->memoryCall(sdwAddr, psMemRead); + } + else + { + cpu.z80B = *((UINT8 *) psMemRead->pUserArea + (sdwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80B = cpu.z80Base[sdwAddr]; + } + + break; + } + case 0x47: + { + InvalidInstruction(2); + break; + } + case 0x48: + { + InvalidInstruction(2); + break; + } + case 0x49: + { + InvalidInstruction(2); + break; + } + case 0x4a: + { + InvalidInstruction(2); + break; + } + case 0x4b: + { + InvalidInstruction(2); + break; + } + case 0x4c: + { + sdwCyclesRemaining -= 9; + cpu.z80C = cpu.z80XH; + break; + } + case 0x4d: + { + sdwCyclesRemaining -= 9; + cpu.z80C = cpu.z80XL; + break; + } + case 0x4e: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IX + sdwAddr) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemRead->lowAddr) && (sdwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80C = psMemRead->memoryCall(sdwAddr, psMemRead); + } + else + { + cpu.z80C = *((UINT8 *) psMemRead->pUserArea + (sdwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80C = cpu.z80Base[sdwAddr]; + } + + break; + } + case 0x4f: + { + InvalidInstruction(2); + break; + } + case 0x50: + { + InvalidInstruction(2); + break; + } + case 0x51: + { + InvalidInstruction(2); + break; + } + case 0x52: + { + InvalidInstruction(2); + break; + } + case 0x53: + { + InvalidInstruction(2); + break; + } + case 0x54: + { + sdwCyclesRemaining -= 9; + cpu.z80D = cpu.z80XH; + break; + } + case 0x55: + { + sdwCyclesRemaining -= 9; + cpu.z80D = cpu.z80XL; + break; + } + case 0x56: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IX + sdwAddr) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemRead->lowAddr) && (sdwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80D = psMemRead->memoryCall(sdwAddr, psMemRead); + } + else + { + cpu.z80D = *((UINT8 *) psMemRead->pUserArea + (sdwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80D = cpu.z80Base[sdwAddr]; + } + + break; + } + case 0x57: + { + InvalidInstruction(2); + break; + } + case 0x58: + { + InvalidInstruction(2); + break; + } + case 0x59: + { + InvalidInstruction(2); + break; + } + case 0x5a: + { + InvalidInstruction(2); + break; + } + case 0x5b: + { + InvalidInstruction(2); + break; + } + case 0x5c: + { + sdwCyclesRemaining -= 9; + cpu.z80E = cpu.z80XH; + break; + } + case 0x5d: + { + sdwCyclesRemaining -= 9; + cpu.z80E = cpu.z80XL; + break; + } + case 0x5e: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IX + sdwAddr) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemRead->lowAddr) && (sdwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80E = psMemRead->memoryCall(sdwAddr, psMemRead); + } + else + { + cpu.z80E = *((UINT8 *) psMemRead->pUserArea + (sdwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80E = cpu.z80Base[sdwAddr]; + } + + break; + } + case 0x5f: + { + InvalidInstruction(2); + break; + } + case 0x60: + { + sdwCyclesRemaining -= 9; + cpu.z80XH = cpu.z80B; + break; + } + case 0x61: + { + sdwCyclesRemaining -= 9; + cpu.z80XH = cpu.z80C; + break; + } + case 0x62: + { + sdwCyclesRemaining -= 9; + cpu.z80XH = cpu.z80D; + break; + } + case 0x63: + { + sdwCyclesRemaining -= 9; + cpu.z80XH = cpu.z80E; + break; + } + case 0x64: + { + sdwCyclesRemaining -= 9; + break; + } + case 0x65: + { + sdwCyclesRemaining -= 9; + cpu.z80XH = cpu.z80XL; + break; + } + case 0x66: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IX + sdwAddr) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemRead->lowAddr) && (sdwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80H = psMemRead->memoryCall(sdwAddr, psMemRead); + } + else + { + cpu.z80H = *((UINT8 *) psMemRead->pUserArea + (sdwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80H = cpu.z80Base[sdwAddr]; + } + + break; + } + case 0x67: + { + sdwCyclesRemaining -= 9; + cpu.z80XH = cpu.z80A; + break; + } + case 0x68: + { + sdwCyclesRemaining -= 9; + cpu.z80XL = cpu.z80B; + break; + } + case 0x69: + { + sdwCyclesRemaining -= 9; + cpu.z80XL = cpu.z80C; + break; + } + case 0x6a: + { + sdwCyclesRemaining -= 9; + cpu.z80XL = cpu.z80D; + break; + } + case 0x6b: + { + sdwCyclesRemaining -= 9; + cpu.z80XL = cpu.z80E; + break; + } + case 0x6c: + { + sdwCyclesRemaining -= 9; + cpu.z80XL = cpu.z80XH; + break; + } + case 0x6d: + { + sdwCyclesRemaining -= 9; + break; + } + case 0x6e: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IX + sdwAddr) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemRead->lowAddr) && (sdwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80L = psMemRead->memoryCall(sdwAddr, psMemRead); + } + else + { + cpu.z80L = *((UINT8 *) psMemRead->pUserArea + (sdwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80L = cpu.z80Base[sdwAddr]; + } + + break; + } + case 0x6f: + { + sdwCyclesRemaining -= 9; + cpu.z80XL = cpu.z80A; + break; + } + case 0x70: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IX + sdwAddr) & 0xffff; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemWrite->lowAddr) && (sdwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(sdwAddr, cpu.z80B, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (sdwAddr - psMemWrite->lowAddr)) = cpu.z80B; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[sdwAddr] = (UINT8) cpu.z80B; + } + + break; + } + case 0x71: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IX + sdwAddr) & 0xffff; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemWrite->lowAddr) && (sdwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(sdwAddr, cpu.z80C, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (sdwAddr - psMemWrite->lowAddr)) = cpu.z80C; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[sdwAddr] = (UINT8) cpu.z80C; + } + + break; + } + case 0x72: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IX + sdwAddr) & 0xffff; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemWrite->lowAddr) && (sdwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(sdwAddr, cpu.z80D, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (sdwAddr - psMemWrite->lowAddr)) = cpu.z80D; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[sdwAddr] = (UINT8) cpu.z80D; + } + + break; + } + case 0x73: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IX + sdwAddr) & 0xffff; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemWrite->lowAddr) && (sdwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(sdwAddr, cpu.z80E, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (sdwAddr - psMemWrite->lowAddr)) = cpu.z80E; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[sdwAddr] = (UINT8) cpu.z80E; + } + + break; + } + case 0x74: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IX + sdwAddr) & 0xffff; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemWrite->lowAddr) && (sdwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(sdwAddr, cpu.z80H, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (sdwAddr - psMemWrite->lowAddr)) = cpu.z80H; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[sdwAddr] = (UINT8) cpu.z80H; + } + + break; + } + case 0x75: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IX + sdwAddr) & 0xffff; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemWrite->lowAddr) && (sdwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(sdwAddr, cpu.z80L, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (sdwAddr - psMemWrite->lowAddr)) = cpu.z80L; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[sdwAddr] = (UINT8) cpu.z80L; + } + + break; + } + case 0x76: + { + sdwCyclesRemaining -= 19; + InvalidInstruction(2); + break; + } + case 0x77: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IX + sdwAddr) & 0xffff; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemWrite->lowAddr) && (sdwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(sdwAddr, cpu.z80A, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (sdwAddr - psMemWrite->lowAddr)) = cpu.z80A; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[sdwAddr] = (UINT8) cpu.z80A; + } + + break; + } + case 0x78: + { + InvalidInstruction(2); + break; + } + case 0x79: + { + InvalidInstruction(2); + break; + } + case 0x7a: + { + InvalidInstruction(2); + break; + } + case 0x7b: + { + InvalidInstruction(2); + break; + } + case 0x7c: + { + sdwCyclesRemaining -= 9; + cpu.z80A = cpu.z80XH; + break; + } + case 0x7d: + { + sdwCyclesRemaining -= 9; + cpu.z80A = cpu.z80XL; + break; + } + case 0x7e: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IX + sdwAddr) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemRead->lowAddr) && (sdwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80A = psMemRead->memoryCall(sdwAddr, psMemRead); + } + else + { + cpu.z80A = *((UINT8 *) psMemRead->pUserArea + (sdwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80A = cpu.z80Base[sdwAddr]; + } + + break; + } + case 0x7f: + { + InvalidInstruction(2); + break; + } + case 0x80: + { + InvalidInstruction(2); + break; + } + case 0x81: + { + InvalidInstruction(2); + break; + } + case 0x82: + { + InvalidInstruction(2); + break; + } + case 0x83: + { + InvalidInstruction(2); + break; + } + case 0x84: + { + sdwCyclesRemaining -= 9; + bTemp2 = cpu.z80A + cpu.z80XH; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | cpu.z80XH]; + InvalidInstruction(2); + break; + } + case 0x85: + { + sdwCyclesRemaining -= 9; + bTemp2 = cpu.z80A + cpu.z80XL; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | cpu.z80XL]; + InvalidInstruction(2); + break; + } + case 0x86: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + dwAddr = (sdwAddr + (INT32) cpu.z80IX) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemRead->lowAddr) && (dwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(dwAddr, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[dwAddr]; + } + + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | bTemp]; + cpu.z80A += bTemp; + break; + } + case 0x87: + { + InvalidInstruction(2); + break; + } + case 0x88: + { + InvalidInstruction(2); + break; + } + case 0x89: + { + InvalidInstruction(2); + break; + } + case 0x8a: + { + InvalidInstruction(2); + break; + } + case 0x8b: + { + InvalidInstruction(2); + break; + } + case 0x8c: + { + sdwCyclesRemaining -= 9; + bTemp2 = cpu.z80A + cpu.z80XH + (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | cpu.z80XH | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + InvalidInstruction(2); + break; + } + case 0x8d: + { + sdwCyclesRemaining -= 9; + bTemp2 = cpu.z80A + cpu.z80XL + (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | cpu.z80XL | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + InvalidInstruction(2); + break; + } + case 0x8e: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + dwAddr = (sdwAddr + (INT32) cpu.z80IX) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemRead->lowAddr) && (dwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(dwAddr, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[dwAddr]; + } + + bTemp2 = (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | bTemp | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + cpu.z80A += bTemp + bTemp2; + break; + } + case 0x8f: + { + InvalidInstruction(2); + break; + } + case 0x90: + { + InvalidInstruction(2); + break; + } + case 0x91: + { + InvalidInstruction(2); + break; + } + case 0x92: + { + InvalidInstruction(2); + break; + } + case 0x93: + { + InvalidInstruction(2); + break; + } + case 0x94: + { + sdwCyclesRemaining -= 9; + bTemp2 = cpu.z80A - cpu.z80XH; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80XH]; + InvalidInstruction(2); + break; + } + case 0x95: + { + sdwCyclesRemaining -= 9; + bTemp2 = cpu.z80A - cpu.z80XL; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80XL]; + InvalidInstruction(2); + break; + } + case 0x96: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + dwAddr = (sdwAddr + (INT32) cpu.z80IX) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemRead->lowAddr) && (dwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(dwAddr, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[dwAddr]; + } + + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | bTemp]; + cpu.z80A -= bTemp; + break; + } + case 0x97: + { + InvalidInstruction(2); + break; + } + case 0x98: + { + InvalidInstruction(2); + break; + } + case 0x99: + { + InvalidInstruction(2); + break; + } + case 0x9a: + { + InvalidInstruction(2); + break; + } + case 0x9b: + { + InvalidInstruction(2); + break; + } + case 0x9c: + { + sdwCyclesRemaining -= 9; + bTemp2 = cpu.z80A - cpu.z80XH - (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80XH | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + InvalidInstruction(2); + break; + } + case 0x9d: + { + sdwCyclesRemaining -= 9; + bTemp2 = cpu.z80A - cpu.z80XL - (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80XL | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + InvalidInstruction(2); + break; + } + case 0x9e: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + dwAddr = (sdwAddr + (INT32) cpu.z80IX) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemRead->lowAddr) && (dwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(dwAddr, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[dwAddr]; + } + + bTemp2 = cpu.z80A; + cpu.z80A = cpu.z80A - bTemp - (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) bTemp2 << 8) | bTemp | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + break; + } + case 0x9f: + { + InvalidInstruction(2); + break; + } + case 0xa0: + { + InvalidInstruction(2); + break; + } + case 0xa1: + { + InvalidInstruction(2); + break; + } + case 0xa2: + { + InvalidInstruction(2); + break; + } + case 0xa3: + { + InvalidInstruction(2); + break; + } + case 0xa4: + { + sdwCyclesRemaining -= 9; + cpu.z80A &= cpu.z80XH; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostANDFlags[cpu.z80A]; + + InvalidInstruction(2); + break; + } + case 0xa5: + { + sdwCyclesRemaining -= 9; + cpu.z80A &= cpu.z80XL; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostANDFlags[cpu.z80A]; + + InvalidInstruction(2); + break; + } + case 0xa6: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + dwAddr = (sdwAddr + (INT32) cpu.z80IX) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemRead->lowAddr) && (dwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(dwAddr, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[dwAddr]; + } + + cpu.z80A &= bTemp; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostANDFlags[cpu.z80A]; + + break; + } + case 0xa7: + { + InvalidInstruction(2); + break; + } + case 0xa8: + { + InvalidInstruction(2); + break; + } + case 0xa9: + { + InvalidInstruction(2); + break; + } + case 0xaa: + { + InvalidInstruction(2); + break; + } + case 0xab: + { + InvalidInstruction(2); + break; + } + case 0xac: + { + sdwCyclesRemaining -= 9; + cpu.z80A ^= cpu.z80XH; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + InvalidInstruction(2); + break; + } + case 0xad: + { + sdwCyclesRemaining -= 9; + cpu.z80A ^= cpu.z80XL; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + InvalidInstruction(2); + break; + } + case 0xae: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + dwAddr = (sdwAddr + (INT32) cpu.z80IX) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemRead->lowAddr) && (dwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(dwAddr, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[dwAddr]; + } + + cpu.z80A ^= bTemp; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + break; + } + case 0xaf: + { + InvalidInstruction(2); + break; + } + case 0xb0: + { + InvalidInstruction(2); + break; + } + case 0xb1: + { + InvalidInstruction(2); + break; + } + case 0xb2: + { + InvalidInstruction(2); + break; + } + case 0xb3: + { + InvalidInstruction(2); + break; + } + case 0xb4: + { + sdwCyclesRemaining -= 9; + cpu.z80A |= cpu.z80XH; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + InvalidInstruction(2); + break; + } + case 0xb5: + { + sdwCyclesRemaining -= 9; + cpu.z80A |= cpu.z80XL; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + InvalidInstruction(2); + break; + } + case 0xb6: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + dwAddr = (sdwAddr + (INT32) cpu.z80IX) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemRead->lowAddr) && (dwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(dwAddr, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[dwAddr]; + } + + cpu.z80A |= bTemp; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + break; + } + case 0xb7: + { + InvalidInstruction(2); + break; + } + case 0xb8: + { + InvalidInstruction(2); + break; + } + case 0xb9: + { + InvalidInstruction(2); + break; + } + case 0xba: + { + InvalidInstruction(2); + break; + } + case 0xbb: + { + InvalidInstruction(2); + break; + } + case 0xbc: + { + sdwCyclesRemaining -= 9; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + InvalidInstruction(2); + break; + } + case 0xbd: + { + sdwCyclesRemaining -= 9; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + InvalidInstruction(2); + break; + } + case 0xbe: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + dwAddr = (sdwAddr + (INT32) cpu.z80IX) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemRead->lowAddr) && (dwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(dwAddr, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[dwAddr]; + } + + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | bTemp]; + break; + } + case 0xbf: + { + InvalidInstruction(2); + break; + } + case 0xc0: + { + InvalidInstruction(2); + break; + } + case 0xc1: + { + InvalidInstruction(2); + break; + } + case 0xc2: + { + InvalidInstruction(2); + break; + } + case 0xc3: + { + InvalidInstruction(2); + break; + } + case 0xc4: + { + InvalidInstruction(2); + break; + } + case 0xc5: + { + InvalidInstruction(2); + break; + } + case 0xc6: + { + InvalidInstruction(2); + break; + } + case 0xc7: + { + InvalidInstruction(2); + break; + } + case 0xc8: + { + InvalidInstruction(2); + break; + } + case 0xc9: + { + InvalidInstruction(2); + break; + } + case 0xca: + { + InvalidInstruction(2); + break; + } + case 0xcb: + { + DDFDCBHandler(0); + break; + } + case 0xcc: + { + InvalidInstruction(2); + break; + } + case 0xcd: + { + InvalidInstruction(2); + break; + } + case 0xce: + { + InvalidInstruction(2); + break; + } + case 0xcf: + { + InvalidInstruction(2); + break; + } + case 0xd0: + { + InvalidInstruction(2); + break; + } + case 0xd1: + { + InvalidInstruction(2); + break; + } + case 0xd2: + { + InvalidInstruction(2); + break; + } + case 0xd3: + { + InvalidInstruction(2); + break; + } + case 0xd4: + { + InvalidInstruction(2); + break; + } + case 0xd5: + { + InvalidInstruction(2); + break; + } + case 0xd6: + { + InvalidInstruction(2); + break; + } + case 0xd7: + { + InvalidInstruction(2); + break; + } + case 0xd8: + { + InvalidInstruction(2); + break; + } + case 0xd9: + { + InvalidInstruction(2); + break; + } + case 0xda: + { + InvalidInstruction(2); + break; + } + case 0xdb: + { + InvalidInstruction(2); + break; + } + case 0xdc: + { + InvalidInstruction(2); + break; + } + case 0xdd: + { + InvalidInstruction(2); + break; + } + case 0xde: + { + InvalidInstruction(2); + break; + } + case 0xdf: + { + InvalidInstruction(2); + break; + } + case 0xe0: + { + InvalidInstruction(2); + break; + } + case 0xe1: + { + sdwCyclesRemaining -= 14; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80sp >= psMemRead->lowAddr) && (cpu.z80sp <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80IX = psMemRead->memoryCall(cpu.z80sp, psMemRead); + cpu.z80IX |= (UINT32) ((UINT32) psMemRead->memoryCall(cpu.z80sp + 1, psMemRead) << 8); + } + else + { + cpu.z80IX = *((UINT8 *) psMemRead->pUserArea + (cpu.z80sp - psMemRead->lowAddr)); + cpu.z80IX |= (UINT32) ((UINT32) *((UINT8 *) psMemRead->pUserArea + (cpu.z80sp - psMemRead->lowAddr + 1)) << 8); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80IX = cpu.z80Base[cpu.z80sp]; + cpu.z80IX |= (UINT32) ((UINT32) cpu.z80Base[cpu.z80sp + 1] << 8); + } + + cpu.z80sp += 2; + pbSP = (cpu.z80Base + cpu.z80sp); /* Normalize the stack pointer */ + break; + } + case 0xe2: + { + InvalidInstruction(2); + break; + } + case 0xe3: + { + sdwCyclesRemaining -= 23; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80sp >= psMemRead->lowAddr) && (cpu.z80sp <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + dwAddr = psMemRead->memoryCall(cpu.z80sp, psMemRead); + dwAddr |= (UINT32) ((UINT32) psMemRead->memoryCall(cpu.z80sp + 1, psMemRead) << 8); + } + else + { + dwAddr = *((UINT8 *) psMemRead->pUserArea + (cpu.z80sp - psMemRead->lowAddr)); + dwAddr |= (UINT32) ((UINT32) *((UINT8 *) psMemRead->pUserArea + (cpu.z80sp - psMemRead->lowAddr + 1)) << 8); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + dwAddr = cpu.z80Base[cpu.z80sp]; + dwAddr |= (UINT32) ((UINT32) cpu.z80Base[cpu.z80sp + 1] << 8); + } + + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80sp >= psMemWrite->lowAddr) && (cpu.z80sp <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80sp, (cpu.z80IX & 0xff), psMemWrite); + psMemWrite->memoryCall(cpu.z80sp + 1, (cpu.z80IX >> 8), psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80sp - psMemWrite->lowAddr)) = cpu.z80IX; + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80sp - psMemWrite->lowAddr) + 1) = cpu.z80IX >> 8; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80sp] = (UINT8) cpu.z80IX; + cpu.z80Base[cpu.z80sp + 1] = (UINT8) ((UINT32) cpu.z80IX >> 8); + } + + cpu.z80IX = dwAddr; + break; + } + case 0xe4: + { + InvalidInstruction(2); + break; + } + case 0xe5: + { + sdwCyclesRemaining -= 15; + cpu.z80sp -= 2; + pbSP = (cpu.z80Base + cpu.z80sp); /* Normalize the stack pointer */ + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80sp >= psMemWrite->lowAddr) && (cpu.z80sp <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80sp, (cpu.z80IX & 0xff), psMemWrite); + psMemWrite->memoryCall(cpu.z80sp + 1, (cpu.z80IX >> 8), psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80sp - psMemWrite->lowAddr)) = cpu.z80IX; + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80sp - psMemWrite->lowAddr) + 1) = cpu.z80IX >> 8; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80sp] = (UINT8) cpu.z80IX; + cpu.z80Base[cpu.z80sp + 1] = (UINT8) ((UINT32) cpu.z80IX >> 8); + } + + break; + } + case 0xe6: + { + InvalidInstruction(2); + break; + } + case 0xe7: + { + InvalidInstruction(2); + break; + } + case 0xe8: + { + InvalidInstruction(2); + break; + } + case 0xe9: + { + sdwCyclesRemaining -= 8; + pbPC = cpu.z80Base + cpu.z80IX; + break; + } + case 0xea: + { + InvalidInstruction(2); + break; + } + case 0xeb: + { + InvalidInstruction(2); + break; + } + case 0xec: + { + InvalidInstruction(2); + break; + } + case 0xed: + { + InvalidInstruction(2); + break; + } + case 0xee: + { + InvalidInstruction(2); + break; + } + case 0xef: + { + InvalidInstruction(2); + break; + } + case 0xf0: + { + InvalidInstruction(2); + break; + } + case 0xf1: + { + InvalidInstruction(2); + break; + } + case 0xf2: + { + InvalidInstruction(2); + break; + } + case 0xf3: + { + InvalidInstruction(2); + break; + } + case 0xf4: + { + InvalidInstruction(2); + break; + } + case 0xf5: + { + InvalidInstruction(2); + break; + } + case 0xf6: + { + InvalidInstruction(2); + break; + } + case 0xf7: + { + InvalidInstruction(2); + break; + } + case 0xf8: + { + InvalidInstruction(2); + break; + } + case 0xf9: + { + sdwCyclesRemaining -= 10; + cpu.z80sp = cpu.z80IX; + break; + } + case 0xfa: + { + InvalidInstruction(2); + break; + } + case 0xfb: + { + InvalidInstruction(2); + break; + } + case 0xfc: + { + InvalidInstruction(2); + break; + } + case 0xfd: + { + InvalidInstruction(2); + break; + } + case 0xfe: + { + InvalidInstruction(2); + break; + } + case 0xff: + { + InvalidInstruction(2); + break; + } + } +} +void DDFDCBHandler(UINT32 dwWhich) +{ + if (dwWhich) + { + dwAddr = (UINT32) ((INT32) cpu.z80IY + ((INT32) *pbPC++)) & 0xffff; + } + else + { + dwAddr = (UINT32) ((INT32) cpu.z80IX + ((INT32) *pbPC++)) & 0xffff; + } + + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemRead->lowAddr) && (dwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(dwAddr, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[dwAddr]; + } + + switch (*pbPC++) + { + case 0x00: + { + InvalidInstruction(4); + break; + } + case 0x01: + { + InvalidInstruction(4); + break; + } + case 0x02: + { + InvalidInstruction(4); + break; + } + case 0x03: + { + InvalidInstruction(4); + break; + } + case 0x04: + { + InvalidInstruction(4); + break; + } + case 0x05: + { + InvalidInstruction(4); + break; + } + case 0x06: + { + sdwCyclesRemaining -= 23; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + bTemp2 = (bTemp >> 7); + bTemp = (bTemp << 1) | bTemp2; + cpu.z80F |= bTemp2 | bPostORFlags[bTemp]; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0x07: + { + InvalidInstruction(4); + break; + } + case 0x08: + { + InvalidInstruction(4); + break; + } + case 0x09: + { + InvalidInstruction(4); + break; + } + case 0x0a: + { + InvalidInstruction(4); + break; + } + case 0x0b: + { + InvalidInstruction(4); + break; + } + case 0x0c: + { + InvalidInstruction(4); + break; + } + case 0x0d: + { + InvalidInstruction(4); + break; + } + case 0x0e: + { + sdwCyclesRemaining -= 23; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (bTemp & Z80_FLAG_CARRY); + bTemp = (bTemp >> 1) | (bTemp << 7); + cpu.z80F |= bPostORFlags[bTemp]; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0x0f: + { + InvalidInstruction(4); + break; + } + case 0x10: + { + InvalidInstruction(4); + break; + } + case 0x11: + { + InvalidInstruction(4); + break; + } + case 0x12: + { + InvalidInstruction(4); + break; + } + case 0x13: + { + InvalidInstruction(4); + break; + } + case 0x14: + { + InvalidInstruction(4); + break; + } + case 0x15: + { + InvalidInstruction(4); + break; + } + case 0x16: + { + sdwCyclesRemaining -= 23; + bTemp2 = cpu.z80F & Z80_FLAG_CARRY; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (bTemp >> 7); + bTemp = (bTemp << 1) | bTemp2; + cpu.z80F |= bPostORFlags[bTemp]; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0x17: + { + InvalidInstruction(4); + break; + } + case 0x18: + { + InvalidInstruction(4); + break; + } + case 0x19: + { + InvalidInstruction(4); + break; + } + case 0x1a: + { + InvalidInstruction(4); + break; + } + case 0x1b: + { + InvalidInstruction(4); + break; + } + case 0x1c: + { + InvalidInstruction(4); + break; + } + case 0x1d: + { + InvalidInstruction(4); + break; + } + case 0x1e: + { + sdwCyclesRemaining -= 23; + bTemp2 = (cpu.z80F & Z80_FLAG_CARRY) << 7; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (bTemp & Z80_FLAG_CARRY); + bTemp = (bTemp >> 1) | bTemp2; + cpu.z80F |= bPostORFlags[bTemp]; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0x1f: + { + InvalidInstruction(4); + break; + } + case 0x20: + { + InvalidInstruction(4); + break; + } + case 0x21: + { + InvalidInstruction(4); + break; + } + case 0x22: + { + InvalidInstruction(4); + break; + } + case 0x23: + { + InvalidInstruction(4); + break; + } + case 0x24: + { + InvalidInstruction(4); + break; + } + case 0x25: + { + InvalidInstruction(4); + break; + } + case 0x26: + { + sdwCyclesRemaining -= 23; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (bTemp >> 7); + bTemp = (bTemp << 1); + cpu.z80F |= bPostORFlags[bTemp]; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0x27: + { + InvalidInstruction(4); + break; + } + case 0x28: + { + InvalidInstruction(4); + break; + } + case 0x29: + { + InvalidInstruction(4); + break; + } + case 0x2a: + { + InvalidInstruction(4); + break; + } + case 0x2b: + { + InvalidInstruction(4); + break; + } + case 0x2c: + { + InvalidInstruction(4); + break; + } + case 0x2d: + { + InvalidInstruction(4); + break; + } + case 0x2e: + { + sdwCyclesRemaining -= 23; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (bTemp & Z80_FLAG_CARRY); + bTemp = (bTemp >> 1) | (bTemp & 0x80); + cpu.z80F |= bPostORFlags[bTemp]; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0x2f: + { + InvalidInstruction(4); + break; + } + case 0x30: + { + InvalidInstruction(4); + break; + } + case 0x31: + { + InvalidInstruction(4); + break; + } + case 0x32: + { + InvalidInstruction(4); + break; + } + case 0x33: + { + InvalidInstruction(4); + break; + } + case 0x34: + { + InvalidInstruction(4); + break; + } + case 0x35: + { + InvalidInstruction(4); + break; + } + case 0x36: + { + sdwCyclesRemaining -= 23; + InvalidInstruction(4); + break; + } + case 0x37: + { + InvalidInstruction(4); + break; + } + case 0x38: + { + InvalidInstruction(4); + break; + } + case 0x39: + { + InvalidInstruction(4); + break; + } + case 0x3a: + { + InvalidInstruction(4); + break; + } + case 0x3b: + { + InvalidInstruction(4); + break; + } + case 0x3c: + { + InvalidInstruction(4); + break; + } + case 0x3d: + { + InvalidInstruction(4); + break; + } + case 0x3e: + { + sdwCyclesRemaining -= 23; + cpu.z80F &= ~(Z80_FLAG_ZERO | Z80_FLAG_SIGN | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE | Z80_FLAG_CARRY); + cpu.z80F |= (bTemp & Z80_FLAG_CARRY); + bTemp = (bTemp >> 1); + cpu.z80F |= bPostORFlags[bTemp]; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0x3f: + { + InvalidInstruction(4); + break; + } + case 0x40: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x41: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x42: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x43: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x44: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x45: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x46: + { + sdwCyclesRemaining -= 20; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_ZERO | Z80_FLAG_NEGATIVE)) | Z80_FLAG_HALF_CARRY; + if (!(bTemp & 0x01)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x47: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x48: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x49: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x4a: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x4b: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x4c: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x4d: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x4e: + { + sdwCyclesRemaining -= 20; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_ZERO | Z80_FLAG_NEGATIVE)) | Z80_FLAG_HALF_CARRY; + if (!(bTemp & 0x02)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x4f: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x50: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x51: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x52: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x53: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x54: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x55: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x56: + { + sdwCyclesRemaining -= 20; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_ZERO | Z80_FLAG_NEGATIVE)) | Z80_FLAG_HALF_CARRY; + if (!(bTemp & 0x04)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x57: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x58: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x59: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x5a: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x5b: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x5c: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x5d: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x5e: + { + sdwCyclesRemaining -= 20; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_ZERO | Z80_FLAG_NEGATIVE)) | Z80_FLAG_HALF_CARRY; + if (!(bTemp & 0x08)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x5f: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x60: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x61: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x62: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x63: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x64: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x65: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x66: + { + sdwCyclesRemaining -= 20; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_ZERO | Z80_FLAG_NEGATIVE)) | Z80_FLAG_HALF_CARRY; + if (!(bTemp & 0x10)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x67: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x68: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x69: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x6a: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x6b: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x6c: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x6d: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x6e: + { + sdwCyclesRemaining -= 20; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_ZERO | Z80_FLAG_NEGATIVE)) | Z80_FLAG_HALF_CARRY; + if (!(bTemp & 0x20)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x6f: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x70: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x71: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x72: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x73: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x74: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x75: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x76: + { + sdwCyclesRemaining -= 20; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_ZERO | Z80_FLAG_NEGATIVE)) | Z80_FLAG_HALF_CARRY; + if (!(bTemp & 0x40)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x77: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x78: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x79: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x7a: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x7b: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x7c: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x7d: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x7e: + { + sdwCyclesRemaining -= 20; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_ZERO | Z80_FLAG_NEGATIVE)) | Z80_FLAG_HALF_CARRY; + if (!(bTemp & 0x80)) + { + cpu.z80F |= Z80_FLAG_ZERO; + } + break; + } + case 0x7f: + { + sdwCyclesRemaining -= 20; + InvalidInstruction(4); + break; + } + case 0x80: + { + InvalidInstruction(4); + break; + } + case 0x81: + { + InvalidInstruction(4); + break; + } + case 0x82: + { + InvalidInstruction(4); + break; + } + case 0x83: + { + InvalidInstruction(4); + break; + } + case 0x84: + { + InvalidInstruction(4); + break; + } + case 0x85: + { + InvalidInstruction(4); + break; + } + case 0x86: + { + sdwCyclesRemaining -= 23; + bTemp &= 0xfe; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0x87: + { + InvalidInstruction(4); + break; + } + case 0x88: + { + InvalidInstruction(4); + break; + } + case 0x89: + { + InvalidInstruction(4); + break; + } + case 0x8a: + { + InvalidInstruction(4); + break; + } + case 0x8b: + { + InvalidInstruction(4); + break; + } + case 0x8c: + { + InvalidInstruction(4); + break; + } + case 0x8d: + { + InvalidInstruction(4); + break; + } + case 0x8e: + { + sdwCyclesRemaining -= 23; + bTemp &= 0xfd; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0x8f: + { + InvalidInstruction(4); + break; + } + case 0x90: + { + InvalidInstruction(4); + break; + } + case 0x91: + { + InvalidInstruction(4); + break; + } + case 0x92: + { + InvalidInstruction(4); + break; + } + case 0x93: + { + InvalidInstruction(4); + break; + } + case 0x94: + { + InvalidInstruction(4); + break; + } + case 0x95: + { + InvalidInstruction(4); + break; + } + case 0x96: + { + sdwCyclesRemaining -= 23; + bTemp &= 0xfb; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0x97: + { + InvalidInstruction(4); + break; + } + case 0x98: + { + InvalidInstruction(4); + break; + } + case 0x99: + { + InvalidInstruction(4); + break; + } + case 0x9a: + { + InvalidInstruction(4); + break; + } + case 0x9b: + { + InvalidInstruction(4); + break; + } + case 0x9c: + { + InvalidInstruction(4); + break; + } + case 0x9d: + { + InvalidInstruction(4); + break; + } + case 0x9e: + { + sdwCyclesRemaining -= 23; + bTemp &= 0xf7; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0x9f: + { + InvalidInstruction(4); + break; + } + case 0xa0: + { + InvalidInstruction(4); + break; + } + case 0xa1: + { + InvalidInstruction(4); + break; + } + case 0xa2: + { + InvalidInstruction(4); + break; + } + case 0xa3: + { + InvalidInstruction(4); + break; + } + case 0xa4: + { + InvalidInstruction(4); + break; + } + case 0xa5: + { + InvalidInstruction(4); + break; + } + case 0xa6: + { + sdwCyclesRemaining -= 23; + bTemp &= 0xef; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0xa7: + { + InvalidInstruction(4); + break; + } + case 0xa8: + { + InvalidInstruction(4); + break; + } + case 0xa9: + { + InvalidInstruction(4); + break; + } + case 0xaa: + { + InvalidInstruction(4); + break; + } + case 0xab: + { + InvalidInstruction(4); + break; + } + case 0xac: + { + InvalidInstruction(4); + break; + } + case 0xad: + { + InvalidInstruction(4); + break; + } + case 0xae: + { + sdwCyclesRemaining -= 23; + bTemp &= 0xdf; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0xaf: + { + InvalidInstruction(4); + break; + } + case 0xb0: + { + InvalidInstruction(4); + break; + } + case 0xb1: + { + InvalidInstruction(4); + break; + } + case 0xb2: + { + InvalidInstruction(4); + break; + } + case 0xb3: + { + InvalidInstruction(4); + break; + } + case 0xb4: + { + InvalidInstruction(4); + break; + } + case 0xb5: + { + InvalidInstruction(4); + break; + } + case 0xb6: + { + sdwCyclesRemaining -= 23; + bTemp &= 0xbf; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0xb7: + { + InvalidInstruction(4); + break; + } + case 0xb8: + { + InvalidInstruction(4); + break; + } + case 0xb9: + { + InvalidInstruction(4); + break; + } + case 0xba: + { + InvalidInstruction(4); + break; + } + case 0xbb: + { + InvalidInstruction(4); + break; + } + case 0xbc: + { + InvalidInstruction(4); + break; + } + case 0xbd: + { + InvalidInstruction(4); + break; + } + case 0xbe: + { + sdwCyclesRemaining -= 23; + bTemp &= 0x7f; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0xbf: + { + InvalidInstruction(4); + break; + } + case 0xc0: + { + InvalidInstruction(4); + break; + } + case 0xc1: + { + InvalidInstruction(4); + break; + } + case 0xc2: + { + InvalidInstruction(4); + break; + } + case 0xc3: + { + InvalidInstruction(4); + break; + } + case 0xc4: + { + InvalidInstruction(4); + break; + } + case 0xc5: + { + InvalidInstruction(4); + break; + } + case 0xc6: + { + sdwCyclesRemaining -= 23; + bTemp |= 0x01; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0xc7: + { + InvalidInstruction(4); + break; + } + case 0xc8: + { + InvalidInstruction(4); + break; + } + case 0xc9: + { + InvalidInstruction(4); + break; + } + case 0xca: + { + InvalidInstruction(4); + break; + } + case 0xcb: + { + InvalidInstruction(4); + break; + } + case 0xcc: + { + InvalidInstruction(4); + break; + } + case 0xcd: + { + InvalidInstruction(4); + break; + } + case 0xce: + { + sdwCyclesRemaining -= 23; + bTemp |= 0x02; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0xcf: + { + InvalidInstruction(4); + break; + } + case 0xd0: + { + InvalidInstruction(4); + break; + } + case 0xd1: + { + InvalidInstruction(4); + break; + } + case 0xd2: + { + InvalidInstruction(4); + break; + } + case 0xd3: + { + InvalidInstruction(4); + break; + } + case 0xd4: + { + InvalidInstruction(4); + break; + } + case 0xd5: + { + InvalidInstruction(4); + break; + } + case 0xd6: + { + sdwCyclesRemaining -= 23; + bTemp |= 0x04; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0xd7: + { + InvalidInstruction(4); + break; + } + case 0xd8: + { + InvalidInstruction(4); + break; + } + case 0xd9: + { + InvalidInstruction(4); + break; + } + case 0xda: + { + InvalidInstruction(4); + break; + } + case 0xdb: + { + InvalidInstruction(4); + break; + } + case 0xdc: + { + InvalidInstruction(4); + break; + } + case 0xdd: + { + InvalidInstruction(4); + break; + } + case 0xde: + { + sdwCyclesRemaining -= 23; + bTemp |= 0x08; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0xdf: + { + InvalidInstruction(4); + break; + } + case 0xe0: + { + InvalidInstruction(4); + break; + } + case 0xe1: + { + InvalidInstruction(4); + break; + } + case 0xe2: + { + InvalidInstruction(4); + break; + } + case 0xe3: + { + InvalidInstruction(4); + break; + } + case 0xe4: + { + InvalidInstruction(4); + break; + } + case 0xe5: + { + InvalidInstruction(4); + break; + } + case 0xe6: + { + sdwCyclesRemaining -= 23; + bTemp |= 0x10; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0xe7: + { + InvalidInstruction(4); + break; + } + case 0xe8: + { + InvalidInstruction(4); + break; + } + case 0xe9: + { + InvalidInstruction(4); + break; + } + case 0xea: + { + InvalidInstruction(4); + break; + } + case 0xeb: + { + InvalidInstruction(4); + break; + } + case 0xec: + { + InvalidInstruction(4); + break; + } + case 0xed: + { + InvalidInstruction(4); + break; + } + case 0xee: + { + sdwCyclesRemaining -= 23; + bTemp |= 0x20; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0xef: + { + InvalidInstruction(4); + break; + } + case 0xf0: + { + InvalidInstruction(4); + break; + } + case 0xf1: + { + InvalidInstruction(4); + break; + } + case 0xf2: + { + InvalidInstruction(4); + break; + } + case 0xf3: + { + InvalidInstruction(4); + break; + } + case 0xf4: + { + InvalidInstruction(4); + break; + } + case 0xf5: + { + InvalidInstruction(4); + break; + } + case 0xf6: + { + sdwCyclesRemaining -= 23; + bTemp |= 0x40; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0xf7: + { + InvalidInstruction(4); + break; + } + case 0xf8: + { + InvalidInstruction(4); + break; + } + case 0xf9: + { + InvalidInstruction(4); + break; + } + case 0xfa: + { + InvalidInstruction(4); + break; + } + case 0xfb: + { + InvalidInstruction(4); + break; + } + case 0xfc: + { + InvalidInstruction(4); + break; + } + case 0xfd: + { + InvalidInstruction(4); + break; + } + case 0xfe: + { + sdwCyclesRemaining -= 23; + bTemp |= 0x80; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0xff: + { + InvalidInstruction(4); + break; + } + } +} +void FDHandler(void) +{ + switch (*pbPC++) + { + case 0x00: + { + InvalidInstruction(2); + break; + } + case 0x01: + { + InvalidInstruction(2); + break; + } + case 0x02: + { + InvalidInstruction(2); + break; + } + case 0x03: + { + InvalidInstruction(2); + break; + } + case 0x04: + { + InvalidInstruction(2); + break; + } + case 0x05: + { + InvalidInstruction(2); + break; + } + case 0x06: + { + InvalidInstruction(2); + break; + } + case 0x07: + { + InvalidInstruction(2); + break; + } + case 0x08: + { + InvalidInstruction(2); + break; + } + case 0x09: + { + sdwCyclesRemaining -= 15; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY); + dwTemp = cpu.z80IY + cpu.z80BC; + cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY) | (((cpu.z80IY ^ dwTemp ^ cpu.z80BC) >> 8) & Z80_FLAG_HALF_CARRY); + cpu.z80IY = dwTemp & 0xffff; + break; + } + case 0x0a: + { + InvalidInstruction(2); + break; + } + case 0x0b: + { + InvalidInstruction(2); + break; + } + case 0x0c: + { + InvalidInstruction(2); + break; + } + case 0x0d: + { + InvalidInstruction(2); + break; + } + case 0x0e: + { + InvalidInstruction(2); + break; + } + case 0x0f: + { + InvalidInstruction(2); + break; + } + case 0x10: + { + InvalidInstruction(2); + break; + } + case 0x11: + { + InvalidInstruction(2); + break; + } + case 0x12: + { + InvalidInstruction(2); + break; + } + case 0x13: + { + InvalidInstruction(2); + break; + } + case 0x14: + { + InvalidInstruction(2); + break; + } + case 0x15: + { + InvalidInstruction(2); + break; + } + case 0x16: + { + InvalidInstruction(2); + break; + } + case 0x17: + { + InvalidInstruction(2); + break; + } + case 0x18: + { + InvalidInstruction(2); + break; + } + case 0x19: + { + sdwCyclesRemaining -= 15; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY); + dwTemp = cpu.z80IY + cpu.z80DE; + cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY) | (((cpu.z80IY ^ dwTemp ^ cpu.z80DE) >> 8) & Z80_FLAG_HALF_CARRY); + cpu.z80IY = dwTemp & 0xffff; + break; + } + case 0x1a: + { + InvalidInstruction(2); + break; + } + case 0x1b: + { + InvalidInstruction(2); + break; + } + case 0x1c: + { + InvalidInstruction(2); + break; + } + case 0x1d: + { + InvalidInstruction(2); + break; + } + case 0x1e: + { + InvalidInstruction(2); + break; + } + case 0x1f: + { + InvalidInstruction(2); + break; + } + case 0x20: + { + InvalidInstruction(2); + break; + } + case 0x21: + { + sdwCyclesRemaining -= 14; + cpu.z80IY = *pbPC++; + cpu.z80IY |= ((UINT32) *pbPC++ << 8); + break; + } + case 0x22: + { + sdwCyclesRemaining -= 20; + dwAddr = *pbPC++; + dwAddr |= ((UINT32) *pbPC++ << 8); + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, (cpu.z80IY & 0xff), psMemWrite); + psMemWrite->memoryCall(dwAddr + 1, (cpu.z80IY >> 8), psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = cpu.z80IY; + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr) + 1) = cpu.z80IY >> 8; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) cpu.z80IY; + cpu.z80Base[dwAddr + 1] = (UINT8) ((UINT32) cpu.z80IY >> 8); + } + + break; + } + case 0x23: + { + sdwCyclesRemaining -= 10; + cpu.z80IY++; + cpu.z80IY &= 0xffff; + break; + } + case 0x24: + { + sdwCyclesRemaining -= 9; + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostIncFlags[cpu.z80YH++]; + break; + } + case 0x25: + { + sdwCyclesRemaining -= 9; + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostDecFlags[cpu.z80YH--]; + break; + } + case 0x26: + { + sdwCyclesRemaining -= 9; + cpu.z80YH = *pbPC++; + break; + } + case 0x27: + { + InvalidInstruction(2); + break; + } + case 0x28: + { + InvalidInstruction(2); + break; + } + case 0x29: + { + sdwCyclesRemaining -= 15; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY); + dwTemp = cpu.z80IY + cpu.z80IY; + cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY) | (((cpu.z80IY ^ dwTemp ^ cpu.z80HL) >> 8) & Z80_FLAG_HALF_CARRY); + cpu.z80IY = dwTemp & 0xffff; + break; + } + case 0x2a: + { + sdwCyclesRemaining -= 20; + dwAddr = *pbPC++; + dwAddr |= ((UINT32) *pbPC++ << 8); + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemRead->lowAddr) && (dwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80IY = psMemRead->memoryCall(dwAddr, psMemRead); + cpu.z80IY |= (UINT32) ((UINT32) psMemRead->memoryCall(dwAddr + 1, psMemRead) << 8); + } + else + { + cpu.z80IY = *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr)); + cpu.z80IY |= (UINT32) ((UINT32) *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr + 1)) << 8); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80IY = cpu.z80Base[dwAddr]; + cpu.z80IY |= (UINT32) ((UINT32) cpu.z80Base[dwAddr + 1] << 8); + } + + break; + } + case 0x2b: + { + sdwCyclesRemaining -= 10; + cpu.z80IY--; + cpu.z80IY &= 0xffff; + break; + } + case 0x2c: + { + sdwCyclesRemaining -= 9; + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostIncFlags[cpu.z80YL++]; + break; + } + case 0x2d: + { + sdwCyclesRemaining -= 9; + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostDecFlags[cpu.z80YL--]; + break; + } + case 0x2e: + { + sdwCyclesRemaining -= 9; + cpu.z80YL = *pbPC++; + break; + } + case 0x2f: + { + InvalidInstruction(2); + break; + } + case 0x30: + { + InvalidInstruction(2); + break; + } + case 0x31: + { + InvalidInstruction(2); + break; + } + case 0x32: + { + InvalidInstruction(2); + break; + } + case 0x33: + { + InvalidInstruction(2); + break; + } + case 0x34: + { + sdwCyclesRemaining -= 23; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + dwAddr = (sdwAddr + (INT32) cpu.z80IY) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemRead->lowAddr) && (dwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(dwAddr, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[dwAddr]; + } + + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostIncFlags[bTemp++]; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0x35: + { + sdwCyclesRemaining -= 23; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + dwAddr = (sdwAddr + (INT32) cpu.z80IY) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemRead->lowAddr) && (dwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(dwAddr, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[dwAddr]; + } + + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostDecFlags[bTemp--]; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemWrite->lowAddr) && (dwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwAddr, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwAddr - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwAddr] = (UINT8) bTemp; + } + + break; + } + case 0x36: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IY + sdwAddr) & 0xffff; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemWrite->lowAddr) && (sdwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(sdwAddr, *pbPC++, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (sdwAddr - psMemWrite->lowAddr)) = *pbPC++; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[sdwAddr] = (UINT8) *pbPC++; + } + + break; + } + case 0x37: + { + InvalidInstruction(2); + break; + } + case 0x38: + { + InvalidInstruction(2); + break; + } + case 0x39: + { + sdwCyclesRemaining -= 15; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY); + dwTemp = cpu.z80IY + cpu.z80sp; + cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY) | (((cpu.z80IY ^ dwTemp ^ cpu.z80sp) >> 8) & Z80_FLAG_HALF_CARRY); + cpu.z80IY = dwTemp & 0xffff; + break; + } + case 0x3a: + { + InvalidInstruction(2); + break; + } + case 0x3b: + { + InvalidInstruction(2); + break; + } + case 0x3c: + { + InvalidInstruction(2); + break; + } + case 0x3d: + { + InvalidInstruction(2); + break; + } + case 0x3e: + { + InvalidInstruction(2); + break; + } + case 0x3f: + { + InvalidInstruction(2); + break; + } + case 0x40: + { + InvalidInstruction(2); + break; + } + case 0x41: + { + InvalidInstruction(2); + break; + } + case 0x42: + { + InvalidInstruction(2); + break; + } + case 0x43: + { + InvalidInstruction(2); + break; + } + case 0x44: + { + sdwCyclesRemaining -= 9; + cpu.z80B = cpu.z80YH; + break; + } + case 0x45: + { + sdwCyclesRemaining -= 9; + cpu.z80B = cpu.z80YL; + break; + } + case 0x46: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IY + sdwAddr) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemRead->lowAddr) && (sdwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80B = psMemRead->memoryCall(sdwAddr, psMemRead); + } + else + { + cpu.z80B = *((UINT8 *) psMemRead->pUserArea + (sdwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80B = cpu.z80Base[sdwAddr]; + } + + break; + } + case 0x47: + { + InvalidInstruction(2); + break; + } + case 0x48: + { + InvalidInstruction(2); + break; + } + case 0x49: + { + InvalidInstruction(2); + break; + } + case 0x4a: + { + InvalidInstruction(2); + break; + } + case 0x4b: + { + InvalidInstruction(2); + break; + } + case 0x4c: + { + sdwCyclesRemaining -= 9; + cpu.z80C = cpu.z80YH; + break; + } + case 0x4d: + { + sdwCyclesRemaining -= 9; + cpu.z80C = cpu.z80YL; + break; + } + case 0x4e: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IY + sdwAddr) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemRead->lowAddr) && (sdwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80C = psMemRead->memoryCall(sdwAddr, psMemRead); + } + else + { + cpu.z80C = *((UINT8 *) psMemRead->pUserArea + (sdwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80C = cpu.z80Base[sdwAddr]; + } + + break; + } + case 0x4f: + { + InvalidInstruction(2); + break; + } + case 0x50: + { + InvalidInstruction(2); + break; + } + case 0x51: + { + InvalidInstruction(2); + break; + } + case 0x52: + { + InvalidInstruction(2); + break; + } + case 0x53: + { + InvalidInstruction(2); + break; + } + case 0x54: + { + sdwCyclesRemaining -= 9; + cpu.z80D = cpu.z80YH; + break; + } + case 0x55: + { + sdwCyclesRemaining -= 9; + cpu.z80D = cpu.z80YL; + break; + } + case 0x56: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IY + sdwAddr) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemRead->lowAddr) && (sdwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80D = psMemRead->memoryCall(sdwAddr, psMemRead); + } + else + { + cpu.z80D = *((UINT8 *) psMemRead->pUserArea + (sdwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80D = cpu.z80Base[sdwAddr]; + } + + break; + } + case 0x57: + { + InvalidInstruction(2); + break; + } + case 0x58: + { + InvalidInstruction(2); + break; + } + case 0x59: + { + InvalidInstruction(2); + break; + } + case 0x5a: + { + InvalidInstruction(2); + break; + } + case 0x5b: + { + InvalidInstruction(2); + break; + } + case 0x5c: + { + sdwCyclesRemaining -= 9; + cpu.z80E = cpu.z80YH; + break; + } + case 0x5d: + { + sdwCyclesRemaining -= 9; + cpu.z80E = cpu.z80YL; + break; + } + case 0x5e: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IY + sdwAddr) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemRead->lowAddr) && (sdwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80E = psMemRead->memoryCall(sdwAddr, psMemRead); + } + else + { + cpu.z80E = *((UINT8 *) psMemRead->pUserArea + (sdwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80E = cpu.z80Base[sdwAddr]; + } + + break; + } + case 0x5f: + { + InvalidInstruction(2); + break; + } + case 0x60: + { + sdwCyclesRemaining -= 9; + cpu.z80YH = cpu.z80B; + break; + } + case 0x61: + { + sdwCyclesRemaining -= 9; + cpu.z80YH = cpu.z80C; + break; + } + case 0x62: + { + sdwCyclesRemaining -= 9; + cpu.z80YH = cpu.z80D; + break; + } + case 0x63: + { + sdwCyclesRemaining -= 9; + cpu.z80YH = cpu.z80E; + break; + } + case 0x64: + { + sdwCyclesRemaining -= 9; + break; + } + case 0x65: + { + sdwCyclesRemaining -= 9; + cpu.z80YH = cpu.z80YL; + break; + } + case 0x66: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IY + sdwAddr) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemRead->lowAddr) && (sdwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80H = psMemRead->memoryCall(sdwAddr, psMemRead); + } + else + { + cpu.z80H = *((UINT8 *) psMemRead->pUserArea + (sdwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80H = cpu.z80Base[sdwAddr]; + } + + break; + } + case 0x67: + { + sdwCyclesRemaining -= 9; + cpu.z80YH = cpu.z80A; + break; + } + case 0x68: + { + sdwCyclesRemaining -= 9; + cpu.z80YL = cpu.z80B; + break; + } + case 0x69: + { + sdwCyclesRemaining -= 9; + cpu.z80YL = cpu.z80C; + break; + } + case 0x6a: + { + sdwCyclesRemaining -= 9; + cpu.z80YL = cpu.z80D; + break; + } + case 0x6b: + { + sdwCyclesRemaining -= 9; + cpu.z80YL = cpu.z80E; + break; + } + case 0x6c: + { + sdwCyclesRemaining -= 9; + cpu.z80YL = cpu.z80YH; + break; + } + case 0x6d: + { + sdwCyclesRemaining -= 9; + break; + } + case 0x6e: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IY + sdwAddr) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemRead->lowAddr) && (sdwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80L = psMemRead->memoryCall(sdwAddr, psMemRead); + } + else + { + cpu.z80L = *((UINT8 *) psMemRead->pUserArea + (sdwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80L = cpu.z80Base[sdwAddr]; + } + + break; + } + case 0x6f: + { + sdwCyclesRemaining -= 9; + cpu.z80YL = cpu.z80A; + break; + } + case 0x70: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IY + sdwAddr) & 0xffff; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemWrite->lowAddr) && (sdwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(sdwAddr, cpu.z80B, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (sdwAddr - psMemWrite->lowAddr)) = cpu.z80B; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[sdwAddr] = (UINT8) cpu.z80B; + } + + break; + } + case 0x71: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IY + sdwAddr) & 0xffff; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemWrite->lowAddr) && (sdwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(sdwAddr, cpu.z80C, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (sdwAddr - psMemWrite->lowAddr)) = cpu.z80C; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[sdwAddr] = (UINT8) cpu.z80C; + } + + break; + } + case 0x72: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IY + sdwAddr) & 0xffff; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemWrite->lowAddr) && (sdwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(sdwAddr, cpu.z80D, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (sdwAddr - psMemWrite->lowAddr)) = cpu.z80D; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[sdwAddr] = (UINT8) cpu.z80D; + } + + break; + } + case 0x73: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IY + sdwAddr) & 0xffff; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemWrite->lowAddr) && (sdwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(sdwAddr, cpu.z80E, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (sdwAddr - psMemWrite->lowAddr)) = cpu.z80E; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[sdwAddr] = (UINT8) cpu.z80E; + } + + break; + } + case 0x74: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IY + sdwAddr) & 0xffff; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemWrite->lowAddr) && (sdwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(sdwAddr, cpu.z80H, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (sdwAddr - psMemWrite->lowAddr)) = cpu.z80H; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[sdwAddr] = (UINT8) cpu.z80H; + } + + break; + } + case 0x75: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IY + sdwAddr) & 0xffff; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemWrite->lowAddr) && (sdwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(sdwAddr, cpu.z80L, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (sdwAddr - psMemWrite->lowAddr)) = cpu.z80L; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[sdwAddr] = (UINT8) cpu.z80L; + } + + break; + } + case 0x76: + { + sdwCyclesRemaining -= 19; + InvalidInstruction(2); + break; + } + case 0x77: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IY + sdwAddr) & 0xffff; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemWrite->lowAddr) && (sdwAddr <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(sdwAddr, cpu.z80A, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (sdwAddr - psMemWrite->lowAddr)) = cpu.z80A; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[sdwAddr] = (UINT8) cpu.z80A; + } + + break; + } + case 0x78: + { + InvalidInstruction(2); + break; + } + case 0x79: + { + InvalidInstruction(2); + break; + } + case 0x7a: + { + InvalidInstruction(2); + break; + } + case 0x7b: + { + InvalidInstruction(2); + break; + } + case 0x7c: + { + sdwCyclesRemaining -= 9; + cpu.z80A = cpu.z80YH; + break; + } + case 0x7d: + { + sdwCyclesRemaining -= 9; + cpu.z80A = cpu.z80YL; + break; + } + case 0x7e: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; // Get the offset + sdwAddr = ((INT32) cpu.z80IY + sdwAddr) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((sdwAddr >= psMemRead->lowAddr) && (sdwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80A = psMemRead->memoryCall(sdwAddr, psMemRead); + } + else + { + cpu.z80A = *((UINT8 *) psMemRead->pUserArea + (sdwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80A = cpu.z80Base[sdwAddr]; + } + + break; + } + case 0x7f: + { + InvalidInstruction(2); + break; + } + case 0x80: + { + InvalidInstruction(2); + break; + } + case 0x81: + { + InvalidInstruction(2); + break; + } + case 0x82: + { + InvalidInstruction(2); + break; + } + case 0x83: + { + InvalidInstruction(2); + break; + } + case 0x84: + { + sdwCyclesRemaining -= 9; + bTemp2 = cpu.z80A + cpu.z80YH; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | cpu.z80YH]; + InvalidInstruction(2); + break; + } + case 0x85: + { + sdwCyclesRemaining -= 9; + bTemp2 = cpu.z80A + cpu.z80YL; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | cpu.z80YL]; + InvalidInstruction(2); + break; + } + case 0x86: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + dwAddr = (sdwAddr + (INT32) cpu.z80IY) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemRead->lowAddr) && (dwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(dwAddr, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[dwAddr]; + } + + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | bTemp]; + cpu.z80A += bTemp; + break; + } + case 0x87: + { + InvalidInstruction(2); + break; + } + case 0x88: + { + InvalidInstruction(2); + break; + } + case 0x89: + { + InvalidInstruction(2); + break; + } + case 0x8a: + { + InvalidInstruction(2); + break; + } + case 0x8b: + { + InvalidInstruction(2); + break; + } + case 0x8c: + { + sdwCyclesRemaining -= 9; + bTemp2 = cpu.z80A + cpu.z80YH + (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | cpu.z80YH | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + InvalidInstruction(2); + break; + } + case 0x8d: + { + sdwCyclesRemaining -= 9; + bTemp2 = cpu.z80A + cpu.z80YL + (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | cpu.z80YL | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + InvalidInstruction(2); + break; + } + case 0x8e: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + dwAddr = (sdwAddr + (INT32) cpu.z80IY) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemRead->lowAddr) && (dwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(dwAddr, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[dwAddr]; + } + + bTemp2 = (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | bTemp | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + cpu.z80A += bTemp + bTemp2; + break; + } + case 0x8f: + { + InvalidInstruction(2); + break; + } + case 0x90: + { + InvalidInstruction(2); + break; + } + case 0x91: + { + InvalidInstruction(2); + break; + } + case 0x92: + { + InvalidInstruction(2); + break; + } + case 0x93: + { + InvalidInstruction(2); + break; + } + case 0x94: + { + sdwCyclesRemaining -= 9; + bTemp2 = cpu.z80A - cpu.z80YH; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80YH]; + InvalidInstruction(2); + break; + } + case 0x95: + { + sdwCyclesRemaining -= 9; + bTemp2 = cpu.z80A - cpu.z80YL; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80YL]; + InvalidInstruction(2); + break; + } + case 0x96: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + dwAddr = (sdwAddr + (INT32) cpu.z80IY) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemRead->lowAddr) && (dwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(dwAddr, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[dwAddr]; + } + + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | bTemp]; + cpu.z80A -= bTemp; + break; + } + case 0x97: + { + InvalidInstruction(2); + break; + } + case 0x98: + { + InvalidInstruction(2); + break; + } + case 0x99: + { + InvalidInstruction(2); + break; + } + case 0x9a: + { + InvalidInstruction(2); + break; + } + case 0x9b: + { + InvalidInstruction(2); + break; + } + case 0x9c: + { + sdwCyclesRemaining -= 9; + bTemp2 = cpu.z80A - cpu.z80YH - (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80YH | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + InvalidInstruction(2); + break; + } + case 0x9d: + { + sdwCyclesRemaining -= 9; + bTemp2 = cpu.z80A - cpu.z80YL - (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80YL | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + InvalidInstruction(2); + break; + } + case 0x9e: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + dwAddr = (sdwAddr + (INT32) cpu.z80IY) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemRead->lowAddr) && (dwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(dwAddr, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[dwAddr]; + } + + bTemp2 = cpu.z80A; + cpu.z80A = cpu.z80A - bTemp - (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) bTemp2 << 8) | bTemp | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + break; + } + case 0x9f: + { + InvalidInstruction(2); + break; + } + case 0xa0: + { + InvalidInstruction(2); + break; + } + case 0xa1: + { + InvalidInstruction(2); + break; + } + case 0xa2: + { + InvalidInstruction(2); + break; + } + case 0xa3: + { + InvalidInstruction(2); + break; + } + case 0xa4: + { + sdwCyclesRemaining -= 9; + cpu.z80A &= cpu.z80YH; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostANDFlags[cpu.z80A]; + + InvalidInstruction(2); + break; + } + case 0xa5: + { + sdwCyclesRemaining -= 9; + cpu.z80A &= cpu.z80YL; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostANDFlags[cpu.z80A]; + + InvalidInstruction(2); + break; + } + case 0xa6: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + dwAddr = (sdwAddr + (INT32) cpu.z80IY) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemRead->lowAddr) && (dwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(dwAddr, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[dwAddr]; + } + + cpu.z80A &= bTemp; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostANDFlags[cpu.z80A]; + + break; + } + case 0xa7: + { + InvalidInstruction(2); + break; + } + case 0xa8: + { + InvalidInstruction(2); + break; + } + case 0xa9: + { + InvalidInstruction(2); + break; + } + case 0xaa: + { + InvalidInstruction(2); + break; + } + case 0xab: + { + InvalidInstruction(2); + break; + } + case 0xac: + { + sdwCyclesRemaining -= 9; + cpu.z80A ^= cpu.z80YH; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + InvalidInstruction(2); + break; + } + case 0xad: + { + sdwCyclesRemaining -= 9; + cpu.z80A ^= cpu.z80YL; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + InvalidInstruction(2); + break; + } + case 0xae: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + dwAddr = (sdwAddr + (INT32) cpu.z80IY) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemRead->lowAddr) && (dwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(dwAddr, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[dwAddr]; + } + + cpu.z80A ^= bTemp; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + break; + } + case 0xaf: + { + InvalidInstruction(2); + break; + } + case 0xb0: + { + InvalidInstruction(2); + break; + } + case 0xb1: + { + InvalidInstruction(2); + break; + } + case 0xb2: + { + InvalidInstruction(2); + break; + } + case 0xb3: + { + InvalidInstruction(2); + break; + } + case 0xb4: + { + sdwCyclesRemaining -= 9; + cpu.z80A |= cpu.z80YH; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + InvalidInstruction(2); + break; + } + case 0xb5: + { + sdwCyclesRemaining -= 9; + cpu.z80A |= cpu.z80YL; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + InvalidInstruction(2); + break; + } + case 0xb6: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + dwAddr = (sdwAddr + (INT32) cpu.z80IY) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemRead->lowAddr) && (dwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(dwAddr, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[dwAddr]; + } + + cpu.z80A |= bTemp; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + break; + } + case 0xb7: + { + InvalidInstruction(2); + break; + } + case 0xb8: + { + InvalidInstruction(2); + break; + } + case 0xb9: + { + InvalidInstruction(2); + break; + } + case 0xba: + { + InvalidInstruction(2); + break; + } + case 0xbb: + { + InvalidInstruction(2); + break; + } + case 0xbc: + { + sdwCyclesRemaining -= 9; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + InvalidInstruction(2); + break; + } + case 0xbd: + { + sdwCyclesRemaining -= 9; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + InvalidInstruction(2); + break; + } + case 0xbe: + { + sdwCyclesRemaining -= 19; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + dwAddr = (sdwAddr + (INT32) cpu.z80IY) & 0xffff; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemRead->lowAddr) && (dwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(dwAddr, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[dwAddr]; + } + + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | bTemp]; + break; + } + case 0xbf: + { + InvalidInstruction(2); + break; + } + case 0xc0: + { + InvalidInstruction(2); + break; + } + case 0xc1: + { + InvalidInstruction(2); + break; + } + case 0xc2: + { + InvalidInstruction(2); + break; + } + case 0xc3: + { + InvalidInstruction(2); + break; + } + case 0xc4: + { + InvalidInstruction(2); + break; + } + case 0xc5: + { + InvalidInstruction(2); + break; + } + case 0xc6: + { + InvalidInstruction(2); + break; + } + case 0xc7: + { + InvalidInstruction(2); + break; + } + case 0xc8: + { + InvalidInstruction(2); + break; + } + case 0xc9: + { + InvalidInstruction(2); + break; + } + case 0xca: + { + InvalidInstruction(2); + break; + } + case 0xcb: + { + DDFDCBHandler(1); + break; + } + case 0xcc: + { + InvalidInstruction(2); + break; + } + case 0xcd: + { + InvalidInstruction(2); + break; + } + case 0xce: + { + InvalidInstruction(2); + break; + } + case 0xcf: + { + InvalidInstruction(2); + break; + } + case 0xd0: + { + InvalidInstruction(2); + break; + } + case 0xd1: + { + InvalidInstruction(2); + break; + } + case 0xd2: + { + InvalidInstruction(2); + break; + } + case 0xd3: + { + InvalidInstruction(2); + break; + } + case 0xd4: + { + InvalidInstruction(2); + break; + } + case 0xd5: + { + InvalidInstruction(2); + break; + } + case 0xd6: + { + InvalidInstruction(2); + break; + } + case 0xd7: + { + InvalidInstruction(2); + break; + } + case 0xd8: + { + InvalidInstruction(2); + break; + } + case 0xd9: + { + InvalidInstruction(2); + break; + } + case 0xda: + { + InvalidInstruction(2); + break; + } + case 0xdb: + { + InvalidInstruction(2); + break; + } + case 0xdc: + { + InvalidInstruction(2); + break; + } + case 0xdd: + { + InvalidInstruction(2); + break; + } + case 0xde: + { + InvalidInstruction(2); + break; + } + case 0xdf: + { + InvalidInstruction(2); + break; + } + case 0xe0: + { + InvalidInstruction(2); + break; + } + case 0xe1: + { + sdwCyclesRemaining -= 14; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80sp >= psMemRead->lowAddr) && (cpu.z80sp <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80IY = psMemRead->memoryCall(cpu.z80sp, psMemRead); + cpu.z80IY |= (UINT32) ((UINT32) psMemRead->memoryCall(cpu.z80sp + 1, psMemRead) << 8); + } + else + { + cpu.z80IY = *((UINT8 *) psMemRead->pUserArea + (cpu.z80sp - psMemRead->lowAddr)); + cpu.z80IY |= (UINT32) ((UINT32) *((UINT8 *) psMemRead->pUserArea + (cpu.z80sp - psMemRead->lowAddr + 1)) << 8); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80IY = cpu.z80Base[cpu.z80sp]; + cpu.z80IY |= (UINT32) ((UINT32) cpu.z80Base[cpu.z80sp + 1] << 8); + } + + cpu.z80sp += 2; + pbSP = (cpu.z80Base + cpu.z80sp); /* Normalize the stack pointer */ + break; + } + case 0xe2: + { + InvalidInstruction(2); + break; + } + case 0xe3: + { + sdwCyclesRemaining -= 23; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80sp >= psMemRead->lowAddr) && (cpu.z80sp <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + dwAddr = psMemRead->memoryCall(cpu.z80sp, psMemRead); + dwAddr |= (UINT32) ((UINT32) psMemRead->memoryCall(cpu.z80sp + 1, psMemRead) << 8); + } + else + { + dwAddr = *((UINT8 *) psMemRead->pUserArea + (cpu.z80sp - psMemRead->lowAddr)); + dwAddr |= (UINT32) ((UINT32) *((UINT8 *) psMemRead->pUserArea + (cpu.z80sp - psMemRead->lowAddr + 1)) << 8); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + dwAddr = cpu.z80Base[cpu.z80sp]; + dwAddr |= (UINT32) ((UINT32) cpu.z80Base[cpu.z80sp + 1] << 8); + } + + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80sp >= psMemWrite->lowAddr) && (cpu.z80sp <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80sp, (cpu.z80IY & 0xff), psMemWrite); + psMemWrite->memoryCall(cpu.z80sp + 1, (cpu.z80IY >> 8), psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80sp - psMemWrite->lowAddr)) = cpu.z80IY; + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80sp - psMemWrite->lowAddr) + 1) = cpu.z80IY >> 8; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80sp] = (UINT8) cpu.z80IY; + cpu.z80Base[cpu.z80sp + 1] = (UINT8) ((UINT32) cpu.z80IY >> 8); + } + + cpu.z80IY = dwAddr; + break; + } + case 0xe4: + { + InvalidInstruction(2); + break; + } + case 0xe5: + { + sdwCyclesRemaining -= 15; + cpu.z80sp -= 2; + pbSP = (cpu.z80Base + cpu.z80sp); /* Normalize the stack pointer */ + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80sp >= psMemWrite->lowAddr) && (cpu.z80sp <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80sp, (cpu.z80IY & 0xff), psMemWrite); + psMemWrite->memoryCall(cpu.z80sp + 1, (cpu.z80IY >> 8), psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80sp - psMemWrite->lowAddr)) = cpu.z80IY; + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80sp - psMemWrite->lowAddr) + 1) = cpu.z80IY >> 8; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80sp] = (UINT8) cpu.z80IY; + cpu.z80Base[cpu.z80sp + 1] = (UINT8) ((UINT32) cpu.z80IY >> 8); + } + + break; + } + case 0xe6: + { + InvalidInstruction(2); + break; + } + case 0xe7: + { + InvalidInstruction(2); + break; + } + case 0xe8: + { + InvalidInstruction(2); + break; + } + case 0xe9: + { + sdwCyclesRemaining -= 8; + pbPC = cpu.z80Base + cpu.z80IY; + break; + } + case 0xea: + { + InvalidInstruction(2); + break; + } + case 0xeb: + { + InvalidInstruction(2); + break; + } + case 0xec: + { + InvalidInstruction(2); + break; + } + case 0xed: + { + InvalidInstruction(2); + break; + } + case 0xee: + { + InvalidInstruction(2); + break; + } + case 0xef: + { + InvalidInstruction(2); + break; + } + case 0xf0: + { + InvalidInstruction(2); + break; + } + case 0xf1: + { + InvalidInstruction(2); + break; + } + case 0xf2: + { + InvalidInstruction(2); + break; + } + case 0xf3: + { + InvalidInstruction(2); + break; + } + case 0xf4: + { + InvalidInstruction(2); + break; + } + case 0xf5: + { + InvalidInstruction(2); + break; + } + case 0xf6: + { + InvalidInstruction(2); + break; + } + case 0xf7: + { + InvalidInstruction(2); + break; + } + case 0xf8: + { + InvalidInstruction(2); + break; + } + case 0xf9: + { + sdwCyclesRemaining -= 10; + cpu.z80sp = cpu.z80IY; + break; + } + case 0xfa: + { + InvalidInstruction(2); + break; + } + case 0xfb: + { + InvalidInstruction(2); + break; + } + case 0xfc: + { + InvalidInstruction(2); + break; + } + case 0xfd: + { + InvalidInstruction(2); + break; + } + case 0xfe: + { + InvalidInstruction(2); + break; + } + case 0xff: + { + InvalidInstruction(2); + break; + } + } +} +/* Main execution entry point */ + +UINT32 mz80exec(UINT32 dwCycles) +{ + UINT8 bOpcode; + + dwReturnCode = 0x80000000; /* Assume it'll work */ + sdwCyclesRemaining = dwCycles; + dwOriginalCycles = dwCycles; + if (cpu.z80halted) + { + dwElapsedTicks += dwCycles; + return(0x80000000); + } + + pbPC = cpu.z80Base + cpu.z80pc; + + while (sdwCyclesRemaining > 0) + { + bOpcode = *pbPC++; + switch (bOpcode) + { + case 0x00: + { + sdwCyclesRemaining -= 4; + /* Intentionally not doing anything - NOP! */ + break; + } + case 0x01: + { + sdwCyclesRemaining -= 10; + cpu.z80BC = *pbPC++; /* LSB First */ + cpu.z80BC |= (((UINT32) *pbPC++ << 8)); /* Now the MSB */ + break; + } + case 0x02: + { + sdwCyclesRemaining -= 7; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80BC >= psMemWrite->lowAddr) && (cpu.z80BC <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80BC, cpu.z80A, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80BC - psMemWrite->lowAddr)) = cpu.z80A; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80BC] = (UINT8) cpu.z80A; + } + + break; + } + case 0x03: + { + sdwCyclesRemaining -= 6; + cpu.z80BC++; + cpu.z80BC &= 0xffff; + break; + } + case 0x04: + { + sdwCyclesRemaining -= 4; + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostIncFlags[cpu.z80B++]; + break; + } + case 0x05: + { + sdwCyclesRemaining -= 4; + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY); + cpu.z80F |= bPostDecFlags[cpu.z80B--]; + break; + } + case 0x06: + { + sdwCyclesRemaining -= 7; + cpu.z80B = *pbPC++; /* Get immediate byte into register */ + break; + } + case 0x07: + { + sdwCyclesRemaining -= 4; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY); + cpu.z80F |= (cpu.z80A >> 7); + cpu.z80A = (cpu.z80A << 1) | (cpu.z80A >> 7); + break; + } + case 0x08: + { + sdwCyclesRemaining -= 4; + dwAddr = (UINT32) cpu.z80AF; + cpu.z80AF = cpu.z80afprime; + cpu.z80afprime = dwAddr; + break; + } + case 0x09: + { + sdwCyclesRemaining -= 11; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY); + dwTemp = cpu.z80HL + cpu.z80BC; + cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY) | (((cpu.z80HL ^ dwTemp ^ cpu.z80BC) >> 8) & Z80_FLAG_HALF_CARRY); + cpu.z80HL = dwTemp & 0xffff; + break; + } + case 0x0a: + { + sdwCyclesRemaining -= 7; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80BC >= psMemRead->lowAddr) && (cpu.z80BC <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80A = psMemRead->memoryCall(cpu.z80BC, psMemRead); + } + else + { + cpu.z80A = *((UINT8 *) psMemRead->pUserArea + (cpu.z80BC - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80A = cpu.z80Base[cpu.z80BC]; + } + + break; + } + case 0x0b: + { + sdwCyclesRemaining -= 6; + cpu.z80BC--; + cpu.z80BC &= 0xffff; + break; + } + case 0x0c: + { + sdwCyclesRemaining -= 4; + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostIncFlags[cpu.z80C++]; + break; + } + case 0x0d: + { + sdwCyclesRemaining -= 4; + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY); + cpu.z80F |= bPostDecFlags[cpu.z80C--]; + break; + } + case 0x0e: + { + sdwCyclesRemaining -= 7; + cpu.z80C = *pbPC++; /* Get immediate byte into register */ + break; + } + case 0x0f: + { + sdwCyclesRemaining -= 4; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY); + cpu.z80F |= (cpu.z80A & Z80_FLAG_CARRY); + cpu.z80A = (cpu.z80A >> 1) | (cpu.z80A << 7); + break; + } + case 0x10: + { + sdwCyclesRemaining -= 8; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + if (--cpu.z80B) + { + dwElapsedTicks += 5; /* 5 More for jump taken */ + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + sdwAddr = (sdwAddr + (INT32) cpu.z80pc) & 0xffff; + pbPC = cpu.z80Base + sdwAddr; /* Normalize the address */ + } + break; + } + case 0x11: + { + sdwCyclesRemaining -= 10; + cpu.z80DE = *pbPC++; /* LSB First */ + cpu.z80DE |= (((UINT32) *pbPC++ << 8)); /* Now the MSB */ + break; + } + case 0x12: + { + sdwCyclesRemaining -= 7; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80DE >= psMemWrite->lowAddr) && (cpu.z80DE <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80DE, cpu.z80A, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80DE - psMemWrite->lowAddr)) = cpu.z80A; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80DE] = (UINT8) cpu.z80A; + } + + break; + } + case 0x13: + { + sdwCyclesRemaining -= 6; + cpu.z80DE++; + cpu.z80DE &= 0xffff; + break; + } + case 0x14: + { + sdwCyclesRemaining -= 4; + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostIncFlags[cpu.z80D++]; + break; + } + case 0x15: + { + sdwCyclesRemaining -= 4; + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY); + cpu.z80F |= bPostDecFlags[cpu.z80D--]; + break; + } + case 0x16: + { + sdwCyclesRemaining -= 7; + cpu.z80D = *pbPC++; /* Get immediate byte into register */ + break; + } + case 0x17: + { + sdwCyclesRemaining -= 4; + bTemp = cpu.z80A >> 7; + cpu.z80A = (cpu.z80A << 1) | (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY)) | bTemp; + break; + } + case 0x18: + { + sdwCyclesRemaining -= 12; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + sdwAddr = (sdwAddr + (INT32) cpu.z80pc) & 0xffff; + { + sdwCyclesRemaining -= 5; + pbPC = cpu.z80Base + sdwAddr; /* Normalize the address */ + } + break; + } + case 0x19: + { + sdwCyclesRemaining -= 11; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY); + dwTemp = cpu.z80HL + cpu.z80DE; + cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY) | (((cpu.z80HL ^ dwTemp ^ cpu.z80DE) >> 8) & Z80_FLAG_HALF_CARRY); + cpu.z80HL = dwTemp & 0xffff; + break; + } + case 0x1a: + { + sdwCyclesRemaining -= 7; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80DE >= psMemRead->lowAddr) && (cpu.z80DE <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80A = psMemRead->memoryCall(cpu.z80DE, psMemRead); + } + else + { + cpu.z80A = *((UINT8 *) psMemRead->pUserArea + (cpu.z80DE - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80A = cpu.z80Base[cpu.z80DE]; + } + + break; + } + case 0x1b: + { + sdwCyclesRemaining -= 6; + cpu.z80DE--; + cpu.z80DE &= 0xffff; + break; + } + case 0x1c: + { + sdwCyclesRemaining -= 4; + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostIncFlags[cpu.z80E++]; + break; + } + case 0x1d: + { + sdwCyclesRemaining -= 4; + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY); + cpu.z80F |= bPostDecFlags[cpu.z80E--]; + break; + } + case 0x1e: + { + sdwCyclesRemaining -= 7; + cpu.z80E = *pbPC++; /* Get immediate byte into register */ + break; + } + case 0x1f: + { + sdwCyclesRemaining -= 4; + bTemp = (cpu.z80F & Z80_FLAG_CARRY) << 7; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY)) | (cpu.z80A & Z80_FLAG_CARRY); + cpu.z80A = ((cpu.z80A >> 1) | bTemp); + break; + } + case 0x20: + { + sdwCyclesRemaining -= 7; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + sdwAddr = (sdwAddr + (INT32) cpu.z80pc) & 0xffff; + if (!(cpu.z80F & Z80_FLAG_ZERO)) + { + sdwCyclesRemaining -= 5; + pbPC = cpu.z80Base + sdwAddr; /* Normalize the address */ + } + break; + } + case 0x21: + { + sdwCyclesRemaining -= 10; + cpu.z80HL = *pbPC++; /* LSB First */ + cpu.z80HL |= (((UINT32) *pbPC++ << 8)); /* Now the MSB */ + break; + } + case 0x22: + { + sdwCyclesRemaining -= 16; + dwTemp = *pbPC++; + dwTemp |= ((UINT32) *pbPC++ << 8); + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwTemp >= psMemWrite->lowAddr) && (dwTemp <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwTemp, (cpu.z80HL & 0xff), psMemWrite); + psMemWrite->memoryCall(dwTemp + 1, (cpu.z80HL >> 8), psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwTemp - psMemWrite->lowAddr)) = cpu.z80HL; + *((UINT8 *) psMemWrite->pUserArea + (dwTemp - psMemWrite->lowAddr) + 1) = cpu.z80HL >> 8; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwTemp] = (UINT8) cpu.z80HL; + cpu.z80Base[dwTemp + 1] = (UINT8) ((UINT32) cpu.z80HL >> 8); + } + + break; + } + case 0x23: + { + sdwCyclesRemaining -= 6; + cpu.z80HL++; + cpu.z80HL &= 0xffff; + break; + } + case 0x24: + { + sdwCyclesRemaining -= 4; + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostIncFlags[cpu.z80H++]; + break; + } + case 0x25: + { + sdwCyclesRemaining -= 4; + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY); + cpu.z80F |= bPostDecFlags[cpu.z80H--]; + break; + } + case 0x26: + { + sdwCyclesRemaining -= 7; + cpu.z80H = *pbPC++; /* Get immediate byte into register */ + break; + } + case 0x27: + { + sdwCyclesRemaining -= 4; + dwAddr = (((cpu.z80F & Z80_FLAG_CARRY) | + ((cpu.z80F & Z80_FLAG_HALF_CARRY) >> 3) | + ((cpu.z80F & Z80_FLAG_NEGATIVE) << 1)) << 8) | cpu.z80A; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= (wDAATable[dwAddr] >> 8); + cpu.z80A = wDAATable[dwAddr] & 0xff; + break; + } + case 0x28: + { + sdwCyclesRemaining -= 7; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + sdwAddr = (sdwAddr + (INT32) cpu.z80pc) & 0xffff; + if (cpu.z80F & Z80_FLAG_ZERO) + { + sdwCyclesRemaining -= 5; + pbPC = cpu.z80Base + sdwAddr; /* Normalize the address */ + } + break; + } + case 0x29: + { + sdwCyclesRemaining -= 11; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY); + dwTemp = cpu.z80HL + cpu.z80HL; + cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY) | (((cpu.z80HL ^ dwTemp ^ cpu.z80HL) >> 8) & Z80_FLAG_HALF_CARRY); + cpu.z80HL = dwTemp & 0xffff; + break; + } + case 0x2a: + { + sdwCyclesRemaining -= 16; + dwAddr = *pbPC++; + dwAddr |= ((UINT32) *pbPC++ << 8); + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwAddr >= psMemRead->lowAddr) && (dwAddr <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80HL = psMemRead->memoryCall(dwAddr, psMemRead); + cpu.z80HL |= (UINT32) ((UINT32) psMemRead->memoryCall(dwAddr + 1, psMemRead) << 8); + } + else + { + cpu.z80HL = *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr)); + cpu.z80HL |= (UINT32) ((UINT32) *((UINT8 *) psMemRead->pUserArea + (dwAddr - psMemRead->lowAddr + 1)) << 8); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80HL = cpu.z80Base[dwAddr]; + cpu.z80HL |= (UINT32) ((UINT32) cpu.z80Base[dwAddr + 1] << 8); + } + + break; + } + case 0x2b: + { + sdwCyclesRemaining -= 6; + cpu.z80HL--; + cpu.z80HL &= 0xffff; + break; + } + case 0x2c: + { + sdwCyclesRemaining -= 4; + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostIncFlags[cpu.z80L++]; + break; + } + case 0x2d: + { + sdwCyclesRemaining -= 4; + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY); + cpu.z80F |= bPostDecFlags[cpu.z80L--]; + break; + } + case 0x2e: + { + sdwCyclesRemaining -= 7; + cpu.z80L = *pbPC++; /* Get immediate byte into register */ + break; + } + case 0x2f: + { + sdwCyclesRemaining -= 4; + cpu.z80A ^= 0xff; + cpu.z80F |= (Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY); + break; + } + case 0x30: + { + sdwCyclesRemaining -= 7; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + sdwAddr = (sdwAddr + (INT32) cpu.z80pc) & 0xffff; + if (!(cpu.z80F & Z80_FLAG_CARRY)) + { + sdwCyclesRemaining -= 5; + pbPC = cpu.z80Base + sdwAddr; /* Normalize the address */ + } + break; + } + case 0x31: + { + sdwCyclesRemaining -= 10; + cpu.z80sp = *pbPC++; /* LSB First */ + cpu.z80sp |= (((UINT32) *pbPC++ << 8)); /* Now the MSB */ + break; + } + case 0x32: + { + sdwCyclesRemaining -= 13; + dwTemp = *pbPC++; + dwTemp |= ((UINT32) *pbPC++ << 8); + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((dwTemp >= psMemWrite->lowAddr) && (dwTemp <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(dwTemp, cpu.z80A, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (dwTemp - psMemWrite->lowAddr)) = cpu.z80A; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[dwTemp] = (UINT8) cpu.z80A; + } + + break; + } + case 0x33: + { + sdwCyclesRemaining -= 6; + cpu.z80sp++; + cpu.z80sp &= 0xffff; + break; + } + case 0x34: + { + sdwCyclesRemaining -= 11; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostIncFlags[bTemp]; + bTemp++; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0x35: + { + sdwCyclesRemaining -= 11; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostDecFlags[bTemp]; + bTemp--; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, bTemp, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = bTemp; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) bTemp; + } + + break; + } + case 0x36: + { + sdwCyclesRemaining -= 10; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, *pbPC++, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = *pbPC++; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) *pbPC++; + } + + break; + } + case 0x37: + { + sdwCyclesRemaining -= 4; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE); + cpu.z80F |= Z80_FLAG_CARRY; + break; + } + case 0x38: + { + sdwCyclesRemaining -= 7; + sdwAddr = (INT8) *pbPC++; /* Get LSB first */ + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + sdwAddr = (sdwAddr + (INT32) cpu.z80pc) & 0xffff; + if (cpu.z80F & Z80_FLAG_CARRY) + { + sdwCyclesRemaining -= 5; + pbPC = cpu.z80Base + sdwAddr; /* Normalize the address */ + } + break; + } + case 0x39: + { + sdwCyclesRemaining -= 11; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_HALF_CARRY); + dwTemp = cpu.z80HL + cpu.z80sp; + cpu.z80F |= ((dwTemp >> 16) & Z80_FLAG_CARRY) | (((cpu.z80HL ^ dwTemp ^ cpu.z80sp) >> 8) & Z80_FLAG_HALF_CARRY); + cpu.z80HL = dwTemp & 0xffff; + break; + } + case 0x3a: + { + sdwCyclesRemaining -= 13; + dwTemp = *pbPC++; + dwTemp |= (((UINT32) *pbPC++) << 8); + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((dwTemp >= psMemRead->lowAddr) && (dwTemp <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80A = psMemRead->memoryCall(dwTemp, psMemRead); + } + else + { + cpu.z80A = *((UINT8 *) psMemRead->pUserArea + (dwTemp - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80A = cpu.z80Base[dwTemp]; + } + + break; + } + case 0x3b: + { + sdwCyclesRemaining -= 6; + cpu.z80sp--; + cpu.z80sp &= 0xffff; + break; + } + case 0x3c: + { + sdwCyclesRemaining -= 4; + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_NEGATIVE); + cpu.z80F |= bPostIncFlags[cpu.z80A++]; + break; + } + case 0x3d: + { + sdwCyclesRemaining -= 4; + cpu.z80F &= ~(Z80_FLAG_SIGN | Z80_FLAG_ZERO | Z80_FLAG_HALF_CARRY | Z80_FLAG_OVERFLOW_PARITY); + cpu.z80F |= bPostDecFlags[cpu.z80A--]; + break; + } + case 0x3e: + { + sdwCyclesRemaining -= 7; + cpu.z80A = *pbPC++; /* Get immediate byte into register */ + break; + } + case 0x3f: + { + sdwCyclesRemaining -= 4; + bTemp = (cpu.z80F & Z80_FLAG_CARRY) << 4; + cpu.z80F &= ~(Z80_FLAG_HALF_CARRY | Z80_FLAG_NEGATIVE); + cpu.z80F ^= Z80_FLAG_CARRY; + break; + } + case 0x40: + { + sdwCyclesRemaining -= 4; + break; + } + case 0x41: + { + sdwCyclesRemaining -= 4; + cpu.z80B = cpu.z80C; + break; + } + case 0x42: + { + sdwCyclesRemaining -= 4; + cpu.z80B = cpu.z80D; + break; + } + case 0x43: + { + sdwCyclesRemaining -= 4; + cpu.z80B = cpu.z80E; + break; + } + case 0x44: + { + sdwCyclesRemaining -= 4; + cpu.z80B = cpu.z80H; + break; + } + case 0x45: + { + sdwCyclesRemaining -= 4; + cpu.z80B = cpu.z80L; + break; + } + case 0x46: + { + sdwCyclesRemaining -= 7; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80B = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + cpu.z80B = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80B = cpu.z80Base[cpu.z80HL]; + } + + break; + } + case 0x47: + { + sdwCyclesRemaining -= 4; + cpu.z80B = cpu.z80A; + break; + } + case 0x48: + { + sdwCyclesRemaining -= 4; + cpu.z80C = cpu.z80B; + break; + } + case 0x49: + { + sdwCyclesRemaining -= 4; + break; + } + case 0x4a: + { + sdwCyclesRemaining -= 4; + cpu.z80C = cpu.z80D; + break; + } + case 0x4b: + { + sdwCyclesRemaining -= 4; + cpu.z80C = cpu.z80E; + break; + } + case 0x4c: + { + sdwCyclesRemaining -= 4; + cpu.z80C = cpu.z80H; + break; + } + case 0x4d: + { + sdwCyclesRemaining -= 4; + cpu.z80C = cpu.z80L; + break; + } + case 0x4e: + { + sdwCyclesRemaining -= 7; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80C = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + cpu.z80C = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80C = cpu.z80Base[cpu.z80HL]; + } + + break; + } + case 0x4f: + { + sdwCyclesRemaining -= 4; + cpu.z80C = cpu.z80A; + break; + } + case 0x50: + { + sdwCyclesRemaining -= 4; + cpu.z80D = cpu.z80B; + break; + } + case 0x51: + { + sdwCyclesRemaining -= 4; + cpu.z80D = cpu.z80C; + break; + } + case 0x52: + { + sdwCyclesRemaining -= 4; + break; + } + case 0x53: + { + sdwCyclesRemaining -= 4; + cpu.z80D = cpu.z80E; + break; + } + case 0x54: + { + sdwCyclesRemaining -= 4; + cpu.z80D = cpu.z80H; + break; + } + case 0x55: + { + sdwCyclesRemaining -= 4; + cpu.z80D = cpu.z80L; + break; + } + case 0x56: + { + sdwCyclesRemaining -= 7; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80D = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + cpu.z80D = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80D = cpu.z80Base[cpu.z80HL]; + } + + break; + } + case 0x57: + { + sdwCyclesRemaining -= 4; + cpu.z80D = cpu.z80A; + break; + } + case 0x58: + { + sdwCyclesRemaining -= 4; + cpu.z80E = cpu.z80B; + break; + } + case 0x59: + { + sdwCyclesRemaining -= 4; + cpu.z80E = cpu.z80C; + break; + } + case 0x5a: + { + sdwCyclesRemaining -= 4; + cpu.z80E = cpu.z80D; + break; + } + case 0x5b: + { + sdwCyclesRemaining -= 4; + break; + } + case 0x5c: + { + sdwCyclesRemaining -= 4; + cpu.z80E = cpu.z80H; + break; + } + case 0x5d: + { + sdwCyclesRemaining -= 4; + cpu.z80E = cpu.z80L; + break; + } + case 0x5e: + { + sdwCyclesRemaining -= 7; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80E = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + cpu.z80E = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80E = cpu.z80Base[cpu.z80HL]; + } + + break; + } + case 0x5f: + { + sdwCyclesRemaining -= 4; + cpu.z80E = cpu.z80A; + break; + } + case 0x60: + { + sdwCyclesRemaining -= 4; + cpu.z80H = cpu.z80B; + break; + } + case 0x61: + { + sdwCyclesRemaining -= 4; + cpu.z80H = cpu.z80C; + break; + } + case 0x62: + { + sdwCyclesRemaining -= 4; + cpu.z80H = cpu.z80D; + break; + } + case 0x63: + { + sdwCyclesRemaining -= 4; + cpu.z80H = cpu.z80E; + break; + } + case 0x64: + { + sdwCyclesRemaining -= 4; + break; + } + case 0x65: + { + sdwCyclesRemaining -= 4; + cpu.z80H = cpu.z80L; + break; + } + case 0x66: + { + sdwCyclesRemaining -= 7; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80H = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + cpu.z80H = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80H = cpu.z80Base[cpu.z80HL]; + } + + break; + } + case 0x67: + { + sdwCyclesRemaining -= 4; + cpu.z80H = cpu.z80A; + break; + } + case 0x68: + { + sdwCyclesRemaining -= 4; + cpu.z80L = cpu.z80B; + break; + } + case 0x69: + { + sdwCyclesRemaining -= 4; + cpu.z80L = cpu.z80C; + break; + } + case 0x6a: + { + sdwCyclesRemaining -= 4; + cpu.z80L = cpu.z80D; + break; + } + case 0x6b: + { + sdwCyclesRemaining -= 4; + cpu.z80L = cpu.z80E; + break; + } + case 0x6c: + { + sdwCyclesRemaining -= 4; + cpu.z80L = cpu.z80H; + break; + } + case 0x6d: + { + sdwCyclesRemaining -= 4; + break; + } + case 0x6e: + { + sdwCyclesRemaining -= 7; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80L = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + cpu.z80L = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80L = cpu.z80Base[cpu.z80HL]; + } + + break; + } + case 0x6f: + { + sdwCyclesRemaining -= 4; + cpu.z80L = cpu.z80A; + break; + } + case 0x70: + { + sdwCyclesRemaining -= 7; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, cpu.z80B, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = cpu.z80B; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) cpu.z80B; + } + + break; + } + case 0x71: + { + sdwCyclesRemaining -= 7; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, cpu.z80C, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = cpu.z80C; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) cpu.z80C; + } + + break; + } + case 0x72: + { + sdwCyclesRemaining -= 7; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, cpu.z80D, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = cpu.z80D; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) cpu.z80D; + } + + break; + } + case 0x73: + { + sdwCyclesRemaining -= 7; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, cpu.z80E, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = cpu.z80E; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) cpu.z80E; + } + + break; + } + case 0x74: + { + sdwCyclesRemaining -= 7; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, cpu.z80H, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = cpu.z80H; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) cpu.z80H; + } + + break; + } + case 0x75: + { + sdwCyclesRemaining -= 7; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, cpu.z80L, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = cpu.z80L; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) cpu.z80L; + } + + break; + } + case 0x76: + { + sdwCyclesRemaining -= 4; + cpu.z80halted = 1; + dwElapsedTicks += sdwCyclesRemaining; + sdwCyclesRemaining = 0; + break; + } + case 0x77: + { + sdwCyclesRemaining -= 7; + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemWrite->lowAddr) && (cpu.z80HL <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80HL, cpu.z80A, psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80HL - psMemWrite->lowAddr)) = cpu.z80A; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80HL] = (UINT8) cpu.z80A; + } + + break; + } + case 0x78: + { + sdwCyclesRemaining -= 4; + cpu.z80A = cpu.z80B; + break; + } + case 0x79: + { + sdwCyclesRemaining -= 4; + cpu.z80A = cpu.z80C; + break; + } + case 0x7a: + { + sdwCyclesRemaining -= 4; + cpu.z80A = cpu.z80D; + break; + } + case 0x7b: + { + sdwCyclesRemaining -= 4; + cpu.z80A = cpu.z80E; + break; + } + case 0x7c: + { + sdwCyclesRemaining -= 4; + cpu.z80A = cpu.z80H; + break; + } + case 0x7d: + { + sdwCyclesRemaining -= 4; + cpu.z80A = cpu.z80L; + break; + } + case 0x7e: + { + sdwCyclesRemaining -= 7; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80A = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + cpu.z80A = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80A = cpu.z80Base[cpu.z80HL]; + } + + break; + } + case 0x7f: + { + sdwCyclesRemaining -= 4; + break; + } + case 0x80: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A + cpu.z80B; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | cpu.z80B]; + cpu.z80A = bTemp2; + break; + } + case 0x81: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A + cpu.z80C; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | cpu.z80C]; + cpu.z80A = bTemp2; + break; + } + case 0x82: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A + cpu.z80D; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | cpu.z80D]; + cpu.z80A = bTemp2; + break; + } + case 0x83: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A + cpu.z80E; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | cpu.z80E]; + cpu.z80A = bTemp2; + break; + } + case 0x84: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A + cpu.z80H; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | cpu.z80H]; + cpu.z80A = bTemp2; + break; + } + case 0x85: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A + cpu.z80L; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | cpu.z80L]; + cpu.z80A = bTemp2; + break; + } + case 0x86: + { + sdwCyclesRemaining -= 7; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + bTemp2 = cpu.z80A + bTemp; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | bTemp]; + cpu.z80A = bTemp2; + break; + } + case 0x87: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A + cpu.z80A; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | cpu.z80A]; + cpu.z80A = bTemp2; + break; + } + case 0x88: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A + cpu.z80B + (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | cpu.z80B | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + cpu.z80A = bTemp2; + break; + } + case 0x89: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A + cpu.z80C + (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | cpu.z80C | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + cpu.z80A = bTemp2; + break; + } + case 0x8a: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A + cpu.z80D + (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | cpu.z80D | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + cpu.z80A = bTemp2; + break; + } + case 0x8b: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A + cpu.z80E + (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | cpu.z80E | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + cpu.z80A = bTemp2; + break; + } + case 0x8c: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A + cpu.z80H + (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | cpu.z80H | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + cpu.z80A = bTemp2; + break; + } + case 0x8d: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A + cpu.z80L + (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | cpu.z80L | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + cpu.z80A = bTemp2; + break; + } + case 0x8e: + { + sdwCyclesRemaining -= 7; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + bTemp2 = cpu.z80A + bTemp + (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | bTemp | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + cpu.z80A = bTemp2; + break; + } + case 0x8f: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A + cpu.z80A + (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | cpu.z80A | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + cpu.z80A = bTemp2; + break; + } + case 0x90: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A - cpu.z80B; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80B]; + cpu.z80A = bTemp2; + break; + } + case 0x91: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A - cpu.z80C; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80C]; + cpu.z80A = bTemp2; + break; + } + case 0x92: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A - cpu.z80D; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80D]; + cpu.z80A = bTemp2; + break; + } + case 0x93: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A - cpu.z80E; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80E]; + cpu.z80A = bTemp2; + break; + } + case 0x94: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A - cpu.z80H; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80H]; + cpu.z80A = bTemp2; + break; + } + case 0x95: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A - cpu.z80L; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80L]; + cpu.z80A = bTemp2; + break; + } + case 0x96: + { + sdwCyclesRemaining -= 7; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + bTemp2 = cpu.z80A - bTemp; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | bTemp]; + cpu.z80A = bTemp2; + break; + } + case 0x97: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A - cpu.z80A; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80A]; + cpu.z80A = bTemp2; + break; + } + case 0x98: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A - cpu.z80B - (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80B | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + cpu.z80A = bTemp2; + break; + } + case 0x99: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A - cpu.z80C - (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80C | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + cpu.z80A = bTemp2; + break; + } + case 0x9a: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A - cpu.z80D - (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80D | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + cpu.z80A = bTemp2; + break; + } + case 0x9b: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A - cpu.z80E - (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80E | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + cpu.z80A = bTemp2; + break; + } + case 0x9c: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A - cpu.z80H - (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80H | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + cpu.z80A = bTemp2; + break; + } + case 0x9d: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A - cpu.z80L - (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80L | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + cpu.z80A = bTemp2; + break; + } + case 0x9e: + { + sdwCyclesRemaining -= 7; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + bTemp2 = cpu.z80A - bTemp - (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | bTemp | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + cpu.z80A = bTemp2; + break; + } + case 0x9f: + { + sdwCyclesRemaining -= 4; + bTemp2 = cpu.z80A - cpu.z80A - (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80A | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + cpu.z80A = bTemp2; + break; + } + case 0xa0: + { + sdwCyclesRemaining -= 4; + cpu.z80A &= cpu.z80B; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostANDFlags[cpu.z80A]; + + break; + } + case 0xa1: + { + sdwCyclesRemaining -= 4; + cpu.z80A &= cpu.z80C; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostANDFlags[cpu.z80A]; + + break; + } + case 0xa2: + { + sdwCyclesRemaining -= 4; + cpu.z80A &= cpu.z80D; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostANDFlags[cpu.z80A]; + + break; + } + case 0xa3: + { + sdwCyclesRemaining -= 4; + cpu.z80A &= cpu.z80E; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostANDFlags[cpu.z80A]; + + break; + } + case 0xa4: + { + sdwCyclesRemaining -= 4; + cpu.z80A &= cpu.z80H; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostANDFlags[cpu.z80A]; + + break; + } + case 0xa5: + { + sdwCyclesRemaining -= 4; + cpu.z80A &= cpu.z80L; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostANDFlags[cpu.z80A]; + + break; + } + case 0xa6: + { + sdwCyclesRemaining -= 7; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + cpu.z80A &= bTemp; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostANDFlags[cpu.z80A]; + + break; + } + case 0xa7: + { + sdwCyclesRemaining -= 4; + cpu.z80A &= cpu.z80A; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostANDFlags[cpu.z80A]; + + break; + } + case 0xa8: + { + sdwCyclesRemaining -= 4; + cpu.z80A ^= cpu.z80B; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + break; + } + case 0xa9: + { + sdwCyclesRemaining -= 4; + cpu.z80A ^= cpu.z80C; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + break; + } + case 0xaa: + { + sdwCyclesRemaining -= 4; + cpu.z80A ^= cpu.z80D; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + break; + } + case 0xab: + { + sdwCyclesRemaining -= 4; + cpu.z80A ^= cpu.z80E; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + break; + } + case 0xac: + { + sdwCyclesRemaining -= 4; + cpu.z80A ^= cpu.z80H; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + break; + } + case 0xad: + { + sdwCyclesRemaining -= 4; + cpu.z80A ^= cpu.z80L; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + break; + } + case 0xae: + { + sdwCyclesRemaining -= 7; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + cpu.z80A ^= bTemp; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + break; + } + case 0xaf: + { + sdwCyclesRemaining -= 4; + cpu.z80A ^= cpu.z80A; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + break; + } + case 0xb0: + { + sdwCyclesRemaining -= 4; + cpu.z80A |= cpu.z80B; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + break; + } + case 0xb1: + { + sdwCyclesRemaining -= 4; + cpu.z80A |= cpu.z80C; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + break; + } + case 0xb2: + { + sdwCyclesRemaining -= 4; + cpu.z80A |= cpu.z80D; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + break; + } + case 0xb3: + { + sdwCyclesRemaining -= 4; + cpu.z80A |= cpu.z80E; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + break; + } + case 0xb4: + { + sdwCyclesRemaining -= 4; + cpu.z80A |= cpu.z80H; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + break; + } + case 0xb5: + { + sdwCyclesRemaining -= 4; + cpu.z80A |= cpu.z80L; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + break; + } + case 0xb6: + { + sdwCyclesRemaining -= 7; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + cpu.z80A |= bTemp; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + break; + } + case 0xb7: + { + sdwCyclesRemaining -= 4; + cpu.z80A |= cpu.z80A; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + break; + } + case 0xb8: + { + sdwCyclesRemaining -= 4; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80B]; + break; + } + case 0xb9: + { + sdwCyclesRemaining -= 4; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80C]; + break; + } + case 0xba: + { + sdwCyclesRemaining -= 4; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80D]; + break; + } + case 0xbb: + { + sdwCyclesRemaining -= 4; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80E]; + break; + } + case 0xbc: + { + sdwCyclesRemaining -= 4; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80H]; + break; + } + case 0xbd: + { + sdwCyclesRemaining -= 4; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80L]; + break; + } + case 0xbe: + { + sdwCyclesRemaining -= 7; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80HL >= psMemRead->lowAddr) && (cpu.z80HL <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + bTemp = psMemRead->memoryCall(cpu.z80HL, psMemRead); + } + else + { + bTemp = *((UINT8 *) psMemRead->pUserArea + (cpu.z80HL - psMemRead->lowAddr)); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + bTemp = cpu.z80Base[cpu.z80HL]; + } + + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | bTemp]; + break; + } + case 0xbf: + { + sdwCyclesRemaining -= 4; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | cpu.z80A]; + break; + } + case 0xc0: + { + sdwCyclesRemaining -= 5; + if (!(cpu.z80F & Z80_FLAG_ZERO)) + { + dwElapsedTicks += 6; + pbSP = cpu.z80Base + cpu.z80sp; /* Normalize our stack PTR */ + dwAddr = *pbSP++; /* Pop LSB */ + dwAddr |= ((UINT32) *pbSP << 8); /* Pop MSB */ + cpu.z80sp += 2; /* Pop the word off */ + pbPC = (cpu.z80Base + dwAddr); /* Point PC to our return address */ + } + break; + } + case 0xc1: + { + sdwCyclesRemaining -= 10; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80sp >= psMemRead->lowAddr) && (cpu.z80sp <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80BC = psMemRead->memoryCall(cpu.z80sp, psMemRead); + cpu.z80BC |= (UINT32) ((UINT32) psMemRead->memoryCall(cpu.z80sp + 1, psMemRead) << 8); + } + else + { + cpu.z80BC = *((UINT8 *) psMemRead->pUserArea + (cpu.z80sp - psMemRead->lowAddr)); + cpu.z80BC |= (UINT32) ((UINT32) *((UINT8 *) psMemRead->pUserArea + (cpu.z80sp - psMemRead->lowAddr + 1)) << 8); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80BC = cpu.z80Base[cpu.z80sp]; + cpu.z80BC |= (UINT32) ((UINT32) cpu.z80Base[cpu.z80sp + 1] << 8); + } + + cpu.z80sp += 2; + pbSP = (cpu.z80Base + cpu.z80sp); /* Normalize the stack pointer */ + break; + } + case 0xc2: + { + sdwCyclesRemaining -= 10; + dwAddr = *pbPC++; /* Get LSB first */ + dwAddr |= ((UINT32) *pbPC++ << 8); /* Get MSB last */ + if (!(cpu.z80F & Z80_FLAG_ZERO)) + { + pbPC = cpu.z80Base + dwAddr; /* Normalize the address */ + } + break; + } + case 0xc3: + { + sdwCyclesRemaining -= 10; + dwAddr = *pbPC++; /* Get LSB first */ + dwAddr |= ((UINT32) *pbPC++ << 8); /* Get MSB last */ + pbPC = cpu.z80Base + dwAddr; /* Normalize the address */ + break; + } + case 0xc4: + { + sdwCyclesRemaining -= 10; + dwAddr = *pbPC++; /* Get LSB first */ + dwAddr |= ((UINT32) *pbPC++ << 8); /* Get MSB last */ + if (!(cpu.z80F & Z80_FLAG_ZERO)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + pbSP = (cpu.z80Base + cpu.z80sp - 1); /* Normalize the stack pointer */ + *pbSP-- = cpu.z80pc >> 8; /* MSB */ + *pbSP = (UINT8) cpu.z80pc; /* LSB */ + cpu.z80sp -= 2; /* Back our stack up */ + pbPC = cpu.z80Base + dwAddr; /* Normalize the address */ + } + break; + } + case 0xc5: + { + sdwCyclesRemaining -= 11; + cpu.z80sp -= 2; + pbSP = (cpu.z80Base + cpu.z80sp); /* Normalize the stack pointer */ + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80sp >= psMemWrite->lowAddr) && (cpu.z80sp <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80sp, (cpu.z80BC & 0xff), psMemWrite); + psMemWrite->memoryCall(cpu.z80sp + 1, (cpu.z80BC >> 8), psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80sp - psMemWrite->lowAddr)) = cpu.z80BC; + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80sp - psMemWrite->lowAddr) + 1) = cpu.z80BC >> 8; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80sp] = (UINT8) cpu.z80BC; + cpu.z80Base[cpu.z80sp + 1] = (UINT8) ((UINT32) cpu.z80BC >> 8); + } + + break; + } + case 0xc6: + { + sdwCyclesRemaining -= 7; + bTemp = *pbPC++; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | bTemp]; + cpu.z80A += bTemp; + break; + } + case 0xc7: + { + sdwCyclesRemaining -= 11; + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + pbSP = (cpu.z80Base + cpu.z80sp - 1); /* Normalize the stack pointer */ + *pbSP-- = cpu.z80pc >> 8; /* LSB */ + *pbSP = (UINT8) cpu.z80pc; /* MSB */ + cpu.z80sp -= 2; /* Back our stack up */ + pbPC = cpu.z80Base + 0x00; /* Normalize the address */ + break; + } + case 0xc8: + { + sdwCyclesRemaining -= 5; + if (cpu.z80F & Z80_FLAG_ZERO) + { + dwElapsedTicks += 6; + pbSP = cpu.z80Base + cpu.z80sp; /* Normalize our stack PTR */ + dwAddr = *pbSP++; /* Pop LSB */ + dwAddr |= ((UINT32) *pbSP << 8); /* Pop MSB */ + cpu.z80sp += 2; /* Pop the word off */ + pbPC = (cpu.z80Base + dwAddr); /* Point PC to our return address */ + } + break; + } + case 0xc9: + { + sdwCyclesRemaining -= 10; + pbSP = cpu.z80Base + cpu.z80sp; /* Normalize our stack PTR */ + dwAddr = *pbSP++; /* Pop LSB */ + dwAddr |= ((UINT32) *pbSP << 8); /* Pop MSB */ + cpu.z80sp += 2; /* Pop the word off */ + pbPC = (cpu.z80Base + dwAddr); /* Point PC to our return address */ + break; + } + case 0xca: + { + sdwCyclesRemaining -= 10; + dwAddr = *pbPC++; /* Get LSB first */ + dwAddr |= ((UINT32) *pbPC++ << 8); /* Get MSB last */ + if (cpu.z80F & Z80_FLAG_ZERO) + { + pbPC = cpu.z80Base + dwAddr; /* Normalize the address */ + } + break; + } + case 0xcb: + { + CBHandler(); + break; + } + case 0xcc: + { + sdwCyclesRemaining -= 10; + dwAddr = *pbPC++; /* Get LSB first */ + dwAddr |= ((UINT32) *pbPC++ << 8); /* Get MSB last */ + if (cpu.z80F & Z80_FLAG_ZERO) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + pbSP = (cpu.z80Base + cpu.z80sp - 1); /* Normalize the stack pointer */ + *pbSP-- = cpu.z80pc >> 8; /* MSB */ + *pbSP = (UINT8) cpu.z80pc; /* LSB */ + cpu.z80sp -= 2; /* Back our stack up */ + pbPC = cpu.z80Base + dwAddr; /* Normalize the address */ + } + break; + } + case 0xcd: + { + sdwCyclesRemaining -= 17; + dwAddr = *pbPC++; /* Get LSB first */ + dwAddr |= ((UINT32) *pbPC++ << 8); /* Get MSB last */ + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + pbSP = (cpu.z80Base + cpu.z80sp - 1); /* Normalize the stack pointer */ + *pbSP-- = cpu.z80pc >> 8; /* LSB */ + *pbSP = (UINT8) cpu.z80pc; /* MSB */ + cpu.z80sp -= 2; /* Back our stack up */ + pbPC = cpu.z80Base + dwAddr; /* Normalize the address */ + break; + } + case 0xce: + { + sdwCyclesRemaining -= 7; + bTemp = *pbPC++ + (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbAddAdcTable[((UINT32) cpu.z80A << 8) | bTemp | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + cpu.z80A += bTemp; + break; + } + case 0xcf: + { + sdwCyclesRemaining -= 11; + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + pbSP = (cpu.z80Base + cpu.z80sp - 1); /* Normalize the stack pointer */ + *pbSP-- = cpu.z80pc >> 8; /* LSB */ + *pbSP = (UINT8) cpu.z80pc; /* MSB */ + cpu.z80sp -= 2; /* Back our stack up */ + pbPC = cpu.z80Base + 0x08; /* Normalize the address */ + break; + } + case 0xd0: + { + sdwCyclesRemaining -= 5; + if (!(cpu.z80F & Z80_FLAG_CARRY)) + { + dwElapsedTicks += 6; + pbSP = cpu.z80Base + cpu.z80sp; /* Normalize our stack PTR */ + dwAddr = *pbSP++; /* Pop LSB */ + dwAddr |= ((UINT32) *pbSP << 8); /* Pop MSB */ + cpu.z80sp += 2; /* Pop the word off */ + pbPC = (cpu.z80Base + dwAddr); /* Point PC to our return address */ + } + break; + } + case 0xd1: + { + sdwCyclesRemaining -= 10; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80sp >= psMemRead->lowAddr) && (cpu.z80sp <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80DE = psMemRead->memoryCall(cpu.z80sp, psMemRead); + cpu.z80DE |= (UINT32) ((UINT32) psMemRead->memoryCall(cpu.z80sp + 1, psMemRead) << 8); + } + else + { + cpu.z80DE = *((UINT8 *) psMemRead->pUserArea + (cpu.z80sp - psMemRead->lowAddr)); + cpu.z80DE |= (UINT32) ((UINT32) *((UINT8 *) psMemRead->pUserArea + (cpu.z80sp - psMemRead->lowAddr + 1)) << 8); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80DE = cpu.z80Base[cpu.z80sp]; + cpu.z80DE |= (UINT32) ((UINT32) cpu.z80Base[cpu.z80sp + 1] << 8); + } + + cpu.z80sp += 2; + pbSP = (cpu.z80Base + cpu.z80sp); /* Normalize the stack pointer */ + break; + } + case 0xd2: + { + sdwCyclesRemaining -= 10; + dwAddr = *pbPC++; /* Get LSB first */ + dwAddr |= ((UINT32) *pbPC++ << 8); /* Get MSB last */ + if (!(cpu.z80F & Z80_FLAG_CARRY)) + { + pbPC = cpu.z80Base + dwAddr; /* Normalize the address */ + } + break; + } + case 0xd3: + { + sdwCyclesRemaining -= 11; + dwTemp = *pbPC++; + psIoWrite = cpu.z80IoWrite; /* Beginning of our handler */ + while (psIoWrite->lowIoAddr != 0xffff) + { + if ((dwTemp >= psIoWrite->lowIoAddr) && (dwTemp <= psIoWrite->highIoAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + psIoWrite->IOCall(dwTemp, cpu.z80A, psIoWrite); + psIoWrite = NULL; + break; + } + ++psIoWrite; + } + + break; + } + case 0xd4: + { + sdwCyclesRemaining -= 10; + dwAddr = *pbPC++; /* Get LSB first */ + dwAddr |= ((UINT32) *pbPC++ << 8); /* Get MSB last */ + if (!(cpu.z80F & Z80_FLAG_CARRY)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + pbSP = (cpu.z80Base + cpu.z80sp - 1); /* Normalize the stack pointer */ + *pbSP-- = cpu.z80pc >> 8; /* MSB */ + *pbSP = (UINT8) cpu.z80pc; /* LSB */ + cpu.z80sp -= 2; /* Back our stack up */ + pbPC = cpu.z80Base + dwAddr; /* Normalize the address */ + } + break; + } + case 0xd5: + { + sdwCyclesRemaining -= 11; + cpu.z80sp -= 2; + pbSP = (cpu.z80Base + cpu.z80sp); /* Normalize the stack pointer */ + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80sp >= psMemWrite->lowAddr) && (cpu.z80sp <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80sp, (cpu.z80DE & 0xff), psMemWrite); + psMemWrite->memoryCall(cpu.z80sp + 1, (cpu.z80DE >> 8), psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80sp - psMemWrite->lowAddr)) = cpu.z80DE; + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80sp - psMemWrite->lowAddr) + 1) = cpu.z80DE >> 8; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80sp] = (UINT8) cpu.z80DE; + cpu.z80Base[cpu.z80sp + 1] = (UINT8) ((UINT32) cpu.z80DE >> 8); + } + + break; + } + case 0xd6: + { + sdwCyclesRemaining -= 7; + bTemp = *pbPC++; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | bTemp]; + cpu.z80A -= bTemp; + break; + } + case 0xd7: + { + sdwCyclesRemaining -= 11; + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + pbSP = (cpu.z80Base + cpu.z80sp - 1); /* Normalize the stack pointer */ + *pbSP-- = cpu.z80pc >> 8; /* LSB */ + *pbSP = (UINT8) cpu.z80pc; /* MSB */ + cpu.z80sp -= 2; /* Back our stack up */ + pbPC = cpu.z80Base + 0x10; /* Normalize the address */ + break; + } + case 0xd8: + { + sdwCyclesRemaining -= 5; + if (cpu.z80F & Z80_FLAG_CARRY) + { + dwElapsedTicks += 6; + pbSP = cpu.z80Base + cpu.z80sp; /* Normalize our stack PTR */ + dwAddr = *pbSP++; /* Pop LSB */ + dwAddr |= ((UINT32) *pbSP << 8); /* Pop MSB */ + cpu.z80sp += 2; /* Pop the word off */ + pbPC = (cpu.z80Base + dwAddr); /* Point PC to our return address */ + } + break; + } + case 0xd9: + { + sdwCyclesRemaining -= 4; + dwTemp = cpu.z80DE; + cpu.z80DE = cpu.z80deprime; + cpu.z80deprime = dwTemp; + dwTemp = cpu.z80BC; + cpu.z80BC = cpu.z80bcprime; + cpu.z80bcprime = dwTemp; + dwTemp = cpu.z80HL; + cpu.z80HL = cpu.z80hlprime; + cpu.z80hlprime = dwTemp; + break; + } + case 0xda: + { + sdwCyclesRemaining -= 10; + dwAddr = *pbPC++; /* Get LSB first */ + dwAddr |= ((UINT32) *pbPC++ << 8); /* Get MSB last */ + if (cpu.z80F & Z80_FLAG_CARRY) + { + pbPC = cpu.z80Base + dwAddr; /* Normalize the address */ + } + break; + } + case 0xdb: + { + sdwCyclesRemaining -= 11; + dwTemp = *pbPC++; + psIoRead = cpu.z80IoRead; /* Beginning of our handler */ + while (psIoRead->lowIoAddr != 0xffff) + { + if ((dwTemp >= psIoRead->lowIoAddr) && (dwTemp <= psIoRead->highIoAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + cpu.z80A = psIoRead->IOCall(dwTemp, psIoRead); + psIoRead = NULL; + break; + } + ++psIoRead; + } + + if (psIoRead) + { + cpu.z80A = 0xff; /* Unclaimed I/O read */ + } + + break; + } + case 0xdc: + { + sdwCyclesRemaining -= 10; + dwAddr = *pbPC++; /* Get LSB first */ + dwAddr |= ((UINT32) *pbPC++ << 8); /* Get MSB last */ + if (cpu.z80F & Z80_FLAG_CARRY) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + pbSP = (cpu.z80Base + cpu.z80sp - 1); /* Normalize the stack pointer */ + *pbSP-- = cpu.z80pc >> 8; /* MSB */ + *pbSP = (UINT8) cpu.z80pc; /* LSB */ + cpu.z80sp -= 2; /* Back our stack up */ + pbPC = cpu.z80Base + dwAddr; /* Normalize the address */ + } + break; + } + case 0xdd: + { + DDHandler(); + break; + } + case 0xde: + { + sdwCyclesRemaining -= 7; + bTemp = *pbPC++ + (cpu.z80F & Z80_FLAG_CARRY); + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | bTemp | (((UINT32) cpu.z80F & Z80_FLAG_CARRY) << 16)]; + cpu.z80A = cpu.z80A - bTemp; + break; + } + case 0xdf: + { + sdwCyclesRemaining -= 11; + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + pbSP = (cpu.z80Base + cpu.z80sp - 1); /* Normalize the stack pointer */ + *pbSP-- = cpu.z80pc >> 8; /* LSB */ + *pbSP = (UINT8) cpu.z80pc; /* MSB */ + cpu.z80sp -= 2; /* Back our stack up */ + pbPC = cpu.z80Base + 0x18; /* Normalize the address */ + break; + } + case 0xe0: + { + sdwCyclesRemaining -= 5; + if (!(cpu.z80F & Z80_FLAG_OVERFLOW_PARITY)) + { + dwElapsedTicks += 6; + pbSP = cpu.z80Base + cpu.z80sp; /* Normalize our stack PTR */ + dwAddr = *pbSP++; /* Pop LSB */ + dwAddr |= ((UINT32) *pbSP << 8); /* Pop MSB */ + cpu.z80sp += 2; /* Pop the word off */ + pbPC = (cpu.z80Base + dwAddr); /* Point PC to our return address */ + } + break; + } + case 0xe1: + { + sdwCyclesRemaining -= 10; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80sp >= psMemRead->lowAddr) && (cpu.z80sp <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80HL = psMemRead->memoryCall(cpu.z80sp, psMemRead); + cpu.z80HL |= (UINT32) ((UINT32) psMemRead->memoryCall(cpu.z80sp + 1, psMemRead) << 8); + } + else + { + cpu.z80HL = *((UINT8 *) psMemRead->pUserArea + (cpu.z80sp - psMemRead->lowAddr)); + cpu.z80HL |= (UINT32) ((UINT32) *((UINT8 *) psMemRead->pUserArea + (cpu.z80sp - psMemRead->lowAddr + 1)) << 8); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80HL = cpu.z80Base[cpu.z80sp]; + cpu.z80HL |= (UINT32) ((UINT32) cpu.z80Base[cpu.z80sp + 1] << 8); + } + + cpu.z80sp += 2; + pbSP = (cpu.z80Base + cpu.z80sp); /* Normalize the stack pointer */ + break; + } + case 0xe2: + { + sdwCyclesRemaining -= 10; + dwAddr = *pbPC++; /* Get LSB first */ + dwAddr |= ((UINT32) *pbPC++ << 8); /* Get MSB last */ + if (!(cpu.z80F & Z80_FLAG_OVERFLOW_PARITY)) + { + pbPC = cpu.z80Base + dwAddr; /* Normalize the address */ + } + break; + } + case 0xe3: + { + sdwCyclesRemaining -= 19; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80sp >= psMemRead->lowAddr) && (cpu.z80sp <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + dwAddr = psMemRead->memoryCall(cpu.z80sp, psMemRead); + dwAddr |= (UINT32) ((UINT32) psMemRead->memoryCall(cpu.z80sp + 1, psMemRead) << 8); + } + else + { + dwAddr = *((UINT8 *) psMemRead->pUserArea + (cpu.z80sp - psMemRead->lowAddr)); + dwAddr |= (UINT32) ((UINT32) *((UINT8 *) psMemRead->pUserArea + (cpu.z80sp - psMemRead->lowAddr + 1)) << 8); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + dwAddr = cpu.z80Base[cpu.z80sp]; + dwAddr |= (UINT32) ((UINT32) cpu.z80Base[cpu.z80sp + 1] << 8); + } + + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80sp >= psMemWrite->lowAddr) && (cpu.z80sp <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80sp, (cpu.z80HL & 0xff), psMemWrite); + psMemWrite->memoryCall(cpu.z80sp + 1, (cpu.z80HL >> 8), psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80sp - psMemWrite->lowAddr)) = cpu.z80HL; + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80sp - psMemWrite->lowAddr) + 1) = cpu.z80HL >> 8; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80sp] = (UINT8) cpu.z80HL; + cpu.z80Base[cpu.z80sp + 1] = (UINT8) ((UINT32) cpu.z80HL >> 8); + } + + cpu.z80HL = dwAddr; + break; + } + case 0xe4: + { + sdwCyclesRemaining -= 10; + dwAddr = *pbPC++; /* Get LSB first */ + dwAddr |= ((UINT32) *pbPC++ << 8); /* Get MSB last */ + if (!(cpu.z80F & Z80_FLAG_OVERFLOW_PARITY)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + pbSP = (cpu.z80Base + cpu.z80sp - 1); /* Normalize the stack pointer */ + *pbSP-- = cpu.z80pc >> 8; /* MSB */ + *pbSP = (UINT8) cpu.z80pc; /* LSB */ + cpu.z80sp -= 2; /* Back our stack up */ + pbPC = cpu.z80Base + dwAddr; /* Normalize the address */ + } + break; + } + case 0xe5: + { + sdwCyclesRemaining -= 11; + cpu.z80sp -= 2; + pbSP = (cpu.z80Base + cpu.z80sp); /* Normalize the stack pointer */ + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80sp >= psMemWrite->lowAddr) && (cpu.z80sp <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80sp, (cpu.z80HL & 0xff), psMemWrite); + psMemWrite->memoryCall(cpu.z80sp + 1, (cpu.z80HL >> 8), psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80sp - psMemWrite->lowAddr)) = cpu.z80HL; + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80sp - psMemWrite->lowAddr) + 1) = cpu.z80HL >> 8; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80sp] = (UINT8) cpu.z80HL; + cpu.z80Base[cpu.z80sp + 1] = (UINT8) ((UINT32) cpu.z80HL >> 8); + } + + break; + } + case 0xe6: + { + sdwCyclesRemaining -= 7; + cpu.z80A &= *pbPC++; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostANDFlags[cpu.z80A]; + + break; + } + case 0xe7: + { + sdwCyclesRemaining -= 11; + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + pbSP = (cpu.z80Base + cpu.z80sp - 1); /* Normalize the stack pointer */ + *pbSP-- = cpu.z80pc >> 8; /* LSB */ + *pbSP = (UINT8) cpu.z80pc; /* MSB */ + cpu.z80sp -= 2; /* Back our stack up */ + pbPC = cpu.z80Base + 0x20; /* Normalize the address */ + break; + } + case 0xe8: + { + sdwCyclesRemaining -= 5; + if (cpu.z80F & Z80_FLAG_OVERFLOW_PARITY) + { + dwElapsedTicks += 6; + pbSP = cpu.z80Base + cpu.z80sp; /* Normalize our stack PTR */ + dwAddr = *pbSP++; /* Pop LSB */ + dwAddr |= ((UINT32) *pbSP << 8); /* Pop MSB */ + cpu.z80sp += 2; /* Pop the word off */ + pbPC = (cpu.z80Base + dwAddr); /* Point PC to our return address */ + } + break; + } + case 0xe9: + { + sdwCyclesRemaining -= 4; + pbPC = cpu.z80Base + cpu.z80HL; + break; + } + case 0xea: + { + sdwCyclesRemaining -= 10; + dwAddr = *pbPC++; /* Get LSB first */ + dwAddr |= ((UINT32) *pbPC++ << 8); /* Get MSB last */ + if (cpu.z80F & Z80_FLAG_OVERFLOW_PARITY) + { + pbPC = cpu.z80Base + dwAddr; /* Normalize the address */ + } + break; + } + case 0xeb: + { + sdwCyclesRemaining -= 4; + dwAddr = cpu.z80DE; + cpu.z80DE = cpu.z80HL; + cpu.z80HL = dwAddr; + break; + } + case 0xec: + { + sdwCyclesRemaining -= 10; + dwAddr = *pbPC++; /* Get LSB first */ + dwAddr |= ((UINT32) *pbPC++ << 8); /* Get MSB last */ + if (cpu.z80F & Z80_FLAG_OVERFLOW_PARITY) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + pbSP = (cpu.z80Base + cpu.z80sp - 1); /* Normalize the stack pointer */ + *pbSP-- = cpu.z80pc >> 8; /* MSB */ + *pbSP = (UINT8) cpu.z80pc; /* LSB */ + cpu.z80sp -= 2; /* Back our stack up */ + pbPC = cpu.z80Base + dwAddr; /* Normalize the address */ + } + break; + } + case 0xed: + { + EDHandler(); + break; + } + case 0xee: + { + sdwCyclesRemaining -= 7; + cpu.z80A ^= *pbPC++; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + break; + } + case 0xef: + { + sdwCyclesRemaining -= 11; + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + pbSP = (cpu.z80Base + cpu.z80sp - 1); /* Normalize the stack pointer */ + *pbSP-- = cpu.z80pc >> 8; /* LSB */ + *pbSP = (UINT8) cpu.z80pc; /* MSB */ + cpu.z80sp -= 2; /* Back our stack up */ + pbPC = cpu.z80Base + 0x28; /* Normalize the address */ + break; + } + case 0xf0: + { + sdwCyclesRemaining -= 5; + if (!(cpu.z80F & Z80_FLAG_SIGN)) + { + dwElapsedTicks += 6; + pbSP = cpu.z80Base + cpu.z80sp; /* Normalize our stack PTR */ + dwAddr = *pbSP++; /* Pop LSB */ + dwAddr |= ((UINT32) *pbSP << 8); /* Pop MSB */ + cpu.z80sp += 2; /* Pop the word off */ + pbPC = (cpu.z80Base + dwAddr); /* Point PC to our return address */ + } + break; + } + case 0xf1: + { + sdwCyclesRemaining -= 10; + psMemRead = cpu.z80MemRead; /* Beginning of our handler */ + while (psMemRead->lowAddr != 0xffffffff) + { + if ((cpu.z80sp >= psMemRead->lowAddr) && (cpu.z80sp <= psMemRead->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemRead->memoryCall) + { + cpu.z80AF = psMemRead->memoryCall(cpu.z80sp, psMemRead); + cpu.z80AF |= (UINT32) ((UINT32) psMemRead->memoryCall(cpu.z80sp + 1, psMemRead) << 8); + } + else + { + cpu.z80AF = *((UINT8 *) psMemRead->pUserArea + (cpu.z80sp - psMemRead->lowAddr)); + cpu.z80AF |= (UINT32) ((UINT32) *((UINT8 *) psMemRead->pUserArea + (cpu.z80sp - psMemRead->lowAddr + 1)) << 8); + } + psMemRead = NULL; + break; + } + ++psMemRead; + } + + if (psMemRead) + { + cpu.z80AF = cpu.z80Base[cpu.z80sp]; + cpu.z80AF |= (UINT32) ((UINT32) cpu.z80Base[cpu.z80sp + 1] << 8); + } + + cpu.z80sp += 2; + pbSP = (cpu.z80Base + cpu.z80sp); /* Normalize the stack pointer */ + break; + } + case 0xf2: + { + sdwCyclesRemaining -= 10; + dwAddr = *pbPC++; /* Get LSB first */ + dwAddr |= ((UINT32) *pbPC++ << 8); /* Get MSB last */ + if (!(cpu.z80F & Z80_FLAG_SIGN)) + { + pbPC = cpu.z80Base + dwAddr; /* Normalize the address */ + } + break; + } + case 0xf3: + { + sdwCyclesRemaining -= 4; + cpu.z80iff &= (~IFF1); + break; + } + case 0xf4: + { + sdwCyclesRemaining -= 10; + dwAddr = *pbPC++; /* Get LSB first */ + dwAddr |= ((UINT32) *pbPC++ << 8); /* Get MSB last */ + if (!(cpu.z80F & Z80_FLAG_SIGN)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + pbSP = (cpu.z80Base + cpu.z80sp - 1); /* Normalize the stack pointer */ + *pbSP-- = cpu.z80pc >> 8; /* MSB */ + *pbSP = (UINT8) cpu.z80pc; /* LSB */ + cpu.z80sp -= 2; /* Back our stack up */ + pbPC = cpu.z80Base + dwAddr; /* Normalize the address */ + } + break; + } + case 0xf5: + { + sdwCyclesRemaining -= 11; + cpu.z80sp -= 2; + pbSP = (cpu.z80Base + cpu.z80sp); /* Normalize the stack pointer */ + psMemWrite = cpu.z80MemWrite; /* Beginning of our handler */ + while (psMemWrite->lowAddr != 0xffffffff) + { + if ((cpu.z80sp >= psMemWrite->lowAddr) && (cpu.z80sp <= psMemWrite->highAddr)) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + if (psMemWrite->memoryCall) + { + psMemWrite->memoryCall(cpu.z80sp, (cpu.z80AF & 0xff), psMemWrite); + psMemWrite->memoryCall(cpu.z80sp + 1, (cpu.z80AF >> 8), psMemWrite); + } + else + { + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80sp - psMemWrite->lowAddr)) = cpu.z80AF; + *((UINT8 *) psMemWrite->pUserArea + (cpu.z80sp - psMemWrite->lowAddr) + 1) = cpu.z80AF >> 8; + } + psMemWrite = NULL; + break; + } + ++psMemWrite; + } + + if (psMemWrite) + { + cpu.z80Base[cpu.z80sp] = (UINT8) cpu.z80AF; + cpu.z80Base[cpu.z80sp + 1] = (UINT8) ((UINT32) cpu.z80AF >> 8); + } + + break; + } + case 0xf6: + { + sdwCyclesRemaining -= 7; + cpu.z80A |= *pbPC++; + cpu.z80F &= ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN); + cpu.z80F |= bPostORFlags[cpu.z80A]; + + break; + } + case 0xf7: + { + sdwCyclesRemaining -= 11; + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + pbSP = (cpu.z80Base + cpu.z80sp - 1); /* Normalize the stack pointer */ + *pbSP-- = cpu.z80pc >> 8; /* LSB */ + *pbSP = (UINT8) cpu.z80pc; /* MSB */ + cpu.z80sp -= 2; /* Back our stack up */ + pbPC = cpu.z80Base + 0x30; /* Normalize the address */ + break; + } + case 0xf8: + { + sdwCyclesRemaining -= 5; + if (cpu.z80F & Z80_FLAG_SIGN) + { + dwElapsedTicks += 6; + pbSP = cpu.z80Base + cpu.z80sp; /* Normalize our stack PTR */ + dwAddr = *pbSP++; /* Pop LSB */ + dwAddr |= ((UINT32) *pbSP << 8); /* Pop MSB */ + cpu.z80sp += 2; /* Pop the word off */ + pbPC = (cpu.z80Base + dwAddr); /* Point PC to our return address */ + } + break; + } + case 0xf9: + { + sdwCyclesRemaining -= 6; + cpu.z80sp = cpu.z80HL; + break; + } + case 0xfa: + { + sdwCyclesRemaining -= 10; + dwAddr = *pbPC++; /* Get LSB first */ + dwAddr |= ((UINT32) *pbPC++ << 8); /* Get MSB last */ + if (cpu.z80F & Z80_FLAG_SIGN) + { + pbPC = cpu.z80Base + dwAddr; /* Normalize the address */ + } + break; + } + case 0xfb: + { + sdwCyclesRemaining -= 4; + cpu.z80iff |= IFF1; + break; + } + case 0xfc: + { + sdwCyclesRemaining -= 10; + dwAddr = *pbPC++; /* Get LSB first */ + dwAddr |= ((UINT32) *pbPC++ << 8); /* Get MSB last */ + if (cpu.z80F & Z80_FLAG_SIGN) + { + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + pbSP = (cpu.z80Base + cpu.z80sp - 1); /* Normalize the stack pointer */ + *pbSP-- = cpu.z80pc >> 8; /* MSB */ + *pbSP = (UINT8) cpu.z80pc; /* LSB */ + cpu.z80sp -= 2; /* Back our stack up */ + pbPC = cpu.z80Base + dwAddr; /* Normalize the address */ + } + break; + } + case 0xfd: + { + FDHandler(); + break; + } + case 0xfe: + { + sdwCyclesRemaining -= 7; + cpu.z80F = (cpu.z80F & ~(Z80_FLAG_CARRY | Z80_FLAG_NEGATIVE | Z80_FLAG_OVERFLOW_PARITY | + Z80_FLAG_HALF_CARRY | Z80_FLAG_ZERO | Z80_FLAG_SIGN)) | + pbSubSbcTable[((UINT32) cpu.z80A << 8) | *pbPC++]; + break; + } + case 0xff: + { + sdwCyclesRemaining -= 11; + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + pbSP = (cpu.z80Base + cpu.z80sp - 1); /* Normalize the stack pointer */ + *pbSP-- = cpu.z80pc >> 8; /* LSB */ + *pbSP = (UINT8) cpu.z80pc; /* MSB */ + cpu.z80sp -= 2; /* Back our stack up */ + pbPC = cpu.z80Base + 0x38; /* Normalize the address */ + break; + } + } + } + + dwElapsedTicks += (dwOriginalCycles - sdwCyclesRemaining); + + cpu.z80pc = (UINT32) pbPC - (UINT32) cpu.z80Base; + return(dwReturnCode); /* Indicate success */ +} + +/* Get mz80's context */ + +void mz80GetContext(void *pData) +{ + memcpy(pData, &cpu, sizeof(CONTEXTMZ80)); +} + +/* Set mz80's context */ + +void mz80SetContext(void *pData) +{ + memcpy(&cpu, pData, sizeof(CONTEXTMZ80)); +} + +/* Get mz80's context size */ + +UINT32 mz80GetContextSize(void) +{ + return(sizeof(CONTEXTMZ80)); +} + +/* This will return the elapsed ticks */ + +UINT32 mz80GetElapsedTicks(UINT32 dwClear) +{ + UINT32 dwTemp = dwElapsedTicks; + + if (dwClear) + { + dwElapsedTicks = 0; + } + + return(dwTemp); +} + +/* Releases mz80 from its current timeslice */ + +void mz80ReleaseTimeslice(void) +{ + dwOriginalCycles -= sdwCyclesRemaining; + sdwCyclesRemaining = 0; +} + +/* This routine is mz80's reset handler */ + +void mz80reset(void) +{ + cpu.z80halted = 0; + cpu.z80AF = 0; + cpu.z80F = Z80_FLAG_ZERO; + cpu.z80BC = 0; + cpu.z80DE = 0; + cpu.z80HL = 0; + cpu.z80afprime = 0; + cpu.z80bcprime = 0; + cpu.z80deprime = 0; + cpu.z80hlprime = 0; + cpu.z80i = 0; + cpu.z80r = 0; + cpu.z80IX = 0xffff; /* Yes, this is intentional */ + cpu.z80IY = 0xffff; /* Yes, this is intentional */ + cpu.z80pc = 0; + cpu.z80sp = 0; + cpu.z80interruptMode = 0; + cpu.z80intAddr = 0x38; + cpu.z80nmiAddr = 0x66; +} + +/* Interrupt handler */ + +UINT32 mz80int(UINT32 dwLowAddr) +{ + cpu.z80halted = 0; + if (0 == (cpu.z80iff & IFF1)) + return(0xffffffff); + cpu.z80iff &= ~(IFF1 | IFF2); + pbSP = (cpu.z80Base + cpu.z80sp - 1); /* Normalize the stack pointer */ + *pbSP-- = cpu.z80pc >> 8; /* LSB */ + *pbSP = (UINT8) cpu.z80pc; /* MSB */ + cpu.z80sp -= 2; /* Back our stack up */ + if (2 == cpu.z80interruptMode) + { + cpu.z80pc = ((UINT16) cpu.z80i << 8) | (dwLowAddr & 0xff); + cpu.z80pc = ((UINT16) cpu.z80Base[cpu.z80pc + 1] << 8) | (cpu.z80Base[cpu.z80pc]); + } + else + { + cpu.z80pc = cpu.z80intAddr; + } + pbPC = cpu.z80Base + cpu.z80pc; /* Normalize the address */ + return(0); +} + +/* NMI Handler */ + +UINT32 mz80nmi(void) +{ + cpu.z80halted = 0; + pbSP = (cpu.z80Base + cpu.z80sp - 1); /* Normalize the stack pointer */ + *pbSP-- = cpu.z80pc >> 8; /* LSB */ + *pbSP = (UINT8) cpu.z80pc; /* MSB */ + cpu.z80sp -= 2; /* Back our stack up */ + cpu.z80pc = cpu.z80nmiAddr; /* Our NMI */ + return(0); +} + +/* Initialize MZ80 for action */ + +void mz80init(void) +{ + UINT32 dwLoop; + UINT8 *pbTempPtr; + UINT8 *pbTempPtr2; + UINT8 bNewAdd; + UINT8 bNewSub; + UINT8 bFlag; + UINT8 bLow; + UINT8 bHigh; + UINT8 bCarry; + + if (NULL == pbAddAdcTable) + { + pbAddAdcTable = malloc(256*256*2); + + if (NULL == pbAddAdcTable) + { + return; + } + + pbTempPtr = pbAddAdcTable; + + pbSubSbcTable = malloc(256*256*2); + + if (NULL == pbSubSbcTable) + { + return; + } + + pbTempPtr2 = pbSubSbcTable; + + for (dwLoop = 0; dwLoop < (256*256*2); dwLoop++) + { + bLow = dwLoop & 0xff; + bHigh = (dwLoop >> 8) & 0xff; + bCarry = (dwLoop >> 16); + + bFlag = 0; + bNewAdd = bHigh + bLow + bCarry; + + if (0 == bNewAdd) + { + bFlag |= Z80_FLAG_ZERO; + } + else + { + bFlag = bNewAdd & 0x80; /* Sign flag */ + } + + if (((UINT32) bLow + (UINT32) bHigh + (UINT32) bCarry) >= 0x100) + { + bFlag |= Z80_FLAG_CARRY; + } + + if ( ((bLow ^ bHigh ^ 0x80) & (bLow ^ (bNewAdd & 0x80))) & 0x80) + { + bFlag |= Z80_FLAG_OVERFLOW_PARITY; + } + + if (((bLow & 0x0f) + (bHigh & 0x0f) + bCarry) >= 0x10) + { + bFlag |= Z80_FLAG_HALF_CARRY; + } + + *pbTempPtr++ = bFlag; /* Store our new flag */ + + // Now do subtract - Zero + + bFlag = Z80_FLAG_NEGATIVE; + bNewSub = bHigh - bLow - bCarry; + + if (0 == bNewSub) + { + bFlag |= Z80_FLAG_ZERO; + } + else + { + bFlag |= bNewSub & 0x80; /* Sign flag */ + } + + if ( ((INT32) bHigh - (INT32) bLow - (INT32) bCarry) < 0) + { + bFlag |= Z80_FLAG_CARRY; + } + + if ( ((INT32) (bHigh & 0xf) - (INT32) (bLow & 0x0f) - (INT32) bCarry) < 0) + { + bFlag |= Z80_FLAG_HALF_CARRY; + } + + if ( ((bLow ^ bHigh) & (bHigh ^ bNewSub) & 0x80) ) + { + bFlag |= Z80_FLAG_OVERFLOW_PARITY; + } + + *pbTempPtr2++ = bFlag; /* Store our sub flag */ + + } + } +} +/* Shut down MZ80 */ + +void mz80shutdown(void) +{ + // notaz: why weren't these here? + free(pbAddAdcTable); + pbAddAdcTable = 0; + free(pbSubSbcTable); + pbSubSbcTable = 0; +} + diff --git a/cpu/mz80/mz80.h b/cpu/mz80/mz80.h new file mode 100644 index 00000000..1e2c47c7 --- /dev/null +++ b/cpu/mz80/mz80.h @@ -0,0 +1,394 @@ +/* Multi-Z80 32 Bit emulator */ + +/* Copyright 1996, Neil Bradley, All rights reserved + * + * License agreement: + * + * The mZ80 emulator may be distributed in unmodified form to any medium. + * + * mZ80 May not be sold, or sold as a part of a commercial package without + * the express written permission of Neil Bradley (neil@synthcom.com). This + * includes shareware. + * + * Modified versions of mZ80 may not be publicly redistributed without author + * approval (neil@synthcom.com). This includes distributing via a publicly + * accessible LAN. You may make your own source modifications and distribute + * mZ80 in object only form. + * + * mZ80 Licensing for commercial applications is available. Please email + * neil@synthcom.com for details. + * + * Synthcom Systems, Inc, and Neil Bradley will not be held responsible for + * any damage done by the use of mZ80. It is purely "as-is". + * + * If you use mZ80 in a freeware application, credit in the following text: + * + * "Multi-Z80 CPU emulator by Neil Bradley (neil@synthcom.com)" + * + * must accompany the freeware application within the application itself or + * in the documentation. + * + * Legal stuff aside: + * + * If you find problems with mZ80, please email the author so they can get + * resolved. If you find a bug and fix it, please also email the author so + * that those bug fixes can be propogated to the installed base of mZ80 + * users. If you find performance improvements or problems with mZ80, please + * email the author with your changes/suggestions and they will be rolled in + * with subsequent releases of mZ80. + * + * The whole idea of this emulator is to have the fastest available 32 bit + * Multi-z80 emulator for the PC, giving maximum performance. + */ + +/* General z80 based defines */ + +#ifndef _MZ80_H_ +#define _MZ80_H_ + +#ifndef UINT32 +#define UINT32 unsigned long int +#endif + +#ifndef UINT16 +#define UINT16 unsigned short int +#endif + +#ifndef UINT8 +#define UINT8 unsigned char +#endif + +#ifndef INT32 +#define INT32 signed long int +#endif + +#ifndef INT16 +#define INT16 signed short int +#endif + +#ifndef INT8 +#define INT8 signed char +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _MEMORYREADWRITEBYTE_ +#define _MEMORYREADWRITEBYTE_ + +struct MemoryWriteByte +{ + UINT32 lowAddr; + UINT32 highAddr; + void (*memoryCall)(UINT32, UINT8, struct MemoryWriteByte *); + void *pUserArea; +}; + +struct MemoryReadByte +{ + UINT32 lowAddr; + UINT32 highAddr; + UINT8 (*memoryCall)(UINT32, struct MemoryReadByte *); + void *pUserArea; +}; + +#endif // _MEMORYREADWRITEBYTE_ + +struct z80PortWrite +{ + UINT16 lowIoAddr; + UINT16 highIoAddr; + void (*IOCall)(UINT16, UINT8, struct z80PortWrite *); + void *pUserArea; +}; + +struct z80PortRead +{ + UINT16 lowIoAddr; + UINT16 highIoAddr; + UINT16 (*IOCall)(UINT16, struct z80PortRead *); + void *pUserArea; +}; + +struct z80TrapRec +{ + UINT16 trapAddr; + UINT8 skipCnt; + UINT8 origIns; +}; + +typedef union +{ + UINT32 af; + + struct + { +#ifdef WORDS_BIGENDIAN + UINT16 wFiller; + UINT8 a; + UINT8 f; +#else + UINT8 f; + UINT8 a; + UINT16 wFiller; +#endif + } half; +} reg_af; + +#define z80AF z80af.af +#define z80A z80af.half.a +#define z80F z80af.half.f + +typedef union +{ + UINT32 bc; + + struct + { +#ifdef WORDS_BIGENDIAN + UINT16 wFiller; + UINT8 b; + UINT8 c; +#else + UINT8 c; + UINT8 b; + UINT16 wFiller; +#endif + } half; +} reg_bc; + +#define z80BC z80bc.bc +#define z80B z80bc.half.b +#define z80C z80bc.half.c + +typedef union +{ + UINT32 de; + + struct + { +#ifdef WORDS_BIGENDIAN + UINT16 wFiller; + UINT8 d; + UINT8 e; +#else + UINT8 e; + UINT8 d; + UINT16 wFiller; +#endif + } half; +} reg_de; + +#define z80DE z80de.de +#define z80D z80de.half.d +#define z80E z80de.half.e + +typedef union +{ + UINT32 hl; + + struct + { +#ifdef WORDS_BIGENDIAN + UINT16 wFiller; + UINT8 h; + UINT8 l; +#else + UINT8 l; + UINT8 h; + UINT16 wFiller; +#endif + } half; +} reg_hl; + +#define z80HL z80hl.hl +#define z80H z80hl.half.h +#define z80L z80hl.half.l + +#define z80SP z80sp.sp + +typedef union +{ + UINT32 ix; + + struct + { +#ifdef WORDS_BIGENDIAN + UINT16 wFiller; + UINT8 xh; + UINT8 xl; +#else + UINT8 xl; + UINT8 xh; + UINT16 wFiller; +#endif + } half; +} reg_ix; + +#define z80IX z80ix.ix +#define z80XH z80ix.half.xh +#define z80XL z80ix.half.xl + +typedef union +{ + UINT32 iy; + + struct + { +#ifdef WORDS_BIGENDIAN + UINT16 wFiller; + UINT8 yh; + UINT8 yl; +#else + UINT8 yl; + UINT8 yh; + UINT16 wFiller; +#endif + } half; +} reg_iy; + +#define z80IY z80iy.iy +#define z80YH z80iy.half.yh +#define z80YL z80iy.half.yl + +struct mz80context +{ + UINT8 *z80Base; + struct MemoryReadByte *z80MemRead; + struct MemoryWriteByte *z80MemWrite; + struct z80PortRead *z80IoRead; + struct z80PortWrite *z80IoWrite; + UINT32 z80clockticks; + UINT32 z80iff; + UINT32 z80interruptMode; + UINT32 z80halted; + + reg_af z80af; + reg_bc z80bc; + reg_de z80de; + reg_hl z80hl; + UINT32 z80afprime; + UINT32 z80bcprime; + UINT32 z80deprime; + UINT32 z80hlprime; + reg_ix z80ix; + reg_iy z80iy; + UINT32 z80sp; + UINT32 z80pc; + UINT32 z80nmiAddr; + UINT32 z80intAddr; + UINT32 z80rCounter; + UINT8 z80i; + UINT8 z80r; + UINT8 z80intPending; +}; + +// These are the enumerations used for register access. DO NOT ALTER THEIR +// ORDER! It must match the same order as in the mz80.c/mz80.asm files! + +enum +{ +#ifndef CPUREG_PC + CPUREG_PC = 0, +#endif + CPUREG_Z80_AF = 1, + CPUREG_Z80_BC, + CPUREG_Z80_DE, + CPUREG_Z80_HL, + CPUREG_Z80_AFPRIME, + CPUREG_Z80_BCPRIME, + CPUREG_Z80_DEPRIME, + CPUREG_Z80_HLPRIME, + CPUREG_Z80_IX, + CPUREG_Z80_IY, + CPUREG_Z80_SP, + CPUREG_Z80_I, + CPUREG_Z80_R, + CPUREG_Z80_A, + CPUREG_Z80_B, + CPUREG_Z80_C, + CPUREG_Z80_D, + CPUREG_Z80_E, + CPUREG_Z80_H, + CPUREG_Z80_L, + CPUREG_Z80_F, + CPUREG_Z80_CARRY, + CPUREG_Z80_NEGATIVE, + CPUREG_Z80_PARITY, + CPUREG_Z80_OVERFLOW, + CPUREG_Z80_HALFCARRY, + CPUREG_Z80_ZERO, + CPUREG_Z80_SIGN, + CPUREG_Z80_IFF1, + CPUREG_Z80_IFF2, + + // Leave this here! + + CPUREG_Z80_MAX_INDEX +}; + +extern UINT32 mz80exec(UINT32); +extern UINT32 mz80GetContextSize(void); +extern UINT32 mz80GetElapsedTicks(UINT32); +extern void mz80ReleaseTimeslice(void); +extern void mz80GetContext(void *); +extern void mz80SetContext(void *); +extern void mz80reset(void); +extern void mz80ClearPendingInterrupt(void); +extern UINT32 mz80int(UINT32); +extern UINT32 mz80nmi(void); +extern void mz80init(void); +extern void mz80shutdown(void); +extern UINT32 z80intAddr; +extern UINT32 z80nmiAddr; + +// Debugger useful routines + +extern UINT8 mz80SetRegisterValue(void *, UINT32, UINT32); +extern UINT32 mz80GetRegisterValue(void *, UINT32); +extern UINT32 mz80GetRegisterTextValue(void *, UINT32, UINT8 *); +extern UINT8 *mz80GetRegisterName(UINT32); + +// Memory/IO read/write commands + +#ifndef VALUE_BYTE +#define VALUE_BYTE 0 +#endif + +#ifndef VALUE_WORD +#define VALUE_WORD 1 +#endif + +#ifndef VALUE_DWORD +#define VALUE_DWORD 2 +#endif + +#ifndef VALUE_IO +#define VALUE_IO 3 +#endif + +extern void mz80WriteValue(UINT8 bWhat, UINT32 dwAddr, UINT32 dwData); +extern UINT32 mz80ReadValue(UINT8 bWhat, UINT32 dwAddr); + +// Flag definitions + +#define Z80_FLAG_CARRY 0x01 +#define Z80_FLAG_NEGATIVE 0x02 +#define Z80_FLAG_OVERFLOW_PARITY 0x04 +#define Z80_FLAG_UNDEFINED1 0x08 +#define Z80_FLAG_HALF_CARRY 0x10 +#define Z80_FLAG_UNDEFINED2 0x20 +#define Z80_FLAG_ZERO 0x40 +#define Z80_FLAG_SIGN 0x80 + +#define IFF1 0x01 +#define IFF2 0x02 + +typedef struct mz80context CONTEXTMZ80; + +#ifdef __cplusplus +}; +#endif + +#endif // _MZ80_H_ diff --git a/cpu/mz80/mz80.txt b/cpu/mz80/mz80.txt new file mode 100644 index 00000000..c4f84447 --- /dev/null +++ b/cpu/mz80/mz80.txt @@ -0,0 +1,809 @@ +Multi-Z80 32 Bit emulator +Copyright 1996, 1997, 1998, 1999, 2000 - Neil Bradley, All rights reserved + + MZ80 License agreement + ----------------------- + +(MZ80 Refers to both the assembly code emitted by makez80.c and makez80.c +itself) + +MZ80 May be distributed in unmodified form to any medium. + +MZ80 May not be sold, or sold as a part of a commercial package without +the express written permission of Neil Bradley (neil@synthcom.com). This +includes shareware. + +Modified versions of MZ80 may not be publicly redistributed without author +approval (neil@synthcom.com). This includes distributing via a publicly +accessible LAN. You may make your own source modifications and distribute +MZ80 in source or object form, but if you make modifications to MZ80 +then it should be noted in the top as a comment in makez80.c. + +MZ80 Licensing for commercial applications is available. Please email +neil@synthcom.com for details. + +Synthcom Systems, Inc, and Neil Bradley will not be held responsible for +any damage done by the use of MZ80. It is purely "as-is". + +If you use MZ80 in a freeware application, credit in the following text: + +"Multi-Z80 CPU emulator by Neil Bradley (neil@synthcom.com)" + +must accompany the freeware application within the application itself or +in the documentation. + +Legal stuff aside: + +If you find problems with MZ80, please email the author so they can get +resolved. If you find a bug and fix it, please also email the author so +that those bug fixes can be propogated to the installed base of MZ80 +users. If you find performance improvements or problems with MZ80, please +email the author with your changes/suggestions and they will be rolled in +with subsequent releases of MZ80. + +The whole idea of this emulator is to have the fastest available 32 bit +Multi-Z80 emulator for the x86, giving maximum performance. + + MZ80 Contact information + ------------------------- + +Author : Neil Bradley (neil@synthcom.com) +Distribution: ftp://ftp.synthcom.com/pub/emulators/cpu/makez80.zip (latest) + +You can join the cpuemu mailing list on Synthcom for discussion of Neil +Bradley's Z80 (and other) CPU emulators. Send a message to +"cpuemu-request@synthcom.com" with "subscribe" in the message body. The +traffic is fairly low, and is used as a general discussion and announcement +for aforementioned emulators. + + + MZ80 Documentation + ------------------- + +MZ80 Is a full featured Z80 emulator coded in 32 bit assembly. It runs well +over a hundred games, in addition to it supporting many undocumented Z80 +instructions required to run some of the Midway MCR games, Galaga, and +countless other wonderful Z80 based arcade games. + +MZ80 Contains a makez80.c program that must be compiled. It is the program +that emits the assembly code that NASM will compile. This minimizes the +possibility of bugs creeping in to MZ80 for the different addressing modes +for each instruction. It requires NASM 0.97 or greater. + +The goal of MZ80 is to have a high performance Z80 emulator that is capable +of running multiple emulations concurrently at full speed, even on lower-end +machines (486/33). MZ80 Harnesses the striking similarities of both the Z80 +and the x86 instruction sets to take advantage of flag handling which greatly +reduces the time required to emulate a processor, so no extra time is spent +computing things that are already available in the native x86 processor, +allowing it to perform leaps and bounds over comparable C based Z80 emulators +on the same platform. + +MZ80 Is designed exclusively for use with NASM, the Netwide Assembler. This +gives the ultimate in flexibility, as NASM can emit object files that work +with Watcom, Microsoft Visual C++ (4.0-current), DJGPP, Borland C++, and +gcc under FreeBSD or Linux. MZ80 Has been tested with each one of these +compilers and is known to work properly on each. + + + What's in the package + --------------------- + +MZ80.TXT - This text file + +MAKEZ80.C - Multi Z80 32 Bit emulator emitter program + +MZ80.H - C Header file for MZ80 functions + + + What's new in this release + -------------------------- + +Revision 3.4: + + * Fixed the overflow flag not getting cleared in the SetOverflow() + routine. It caused strange problems with a handful of Genesis games + * Removed invalid instruction in the C version so that more + instructions will execute + +Revision 3.3: + + * Undocumented opcodes added to the C emitter + * Bug fix to the C emission that properly handles shared RAM regions + (I.E. with handlers that are NULL) + * Now using 32 bit registers to do register/memory access. Slight + speed increase (assembly version only) + +Revision 3.2: + + * R Register emulation now accurate with a real Z80 + * mz80int() Called when interrupts are disabled causes the + z80intPending flag to be set, and an interrupt will be caused after + the execution of EI and the next instruction. See "IMPORTANT NOTE + ABOUT INTERRUPTS" below + * The instruction after EI executes fully before interrupt status is + checked. (as does a real Z80) + + +Revision 3.1: + + * Fixed bug in memory dereference when handler was set to NULL (keeps + system from crashing or faulting) + * Removed the only stricmp() from the entire file and replaced it + with strcmp() so that stdlibs without it will compile + * Changed cyclesRemaining > 0 to cyclesRemaining >= 0 to be compatible + with the ASM core + * Removed additional sub [dwCyclesRemaining], 5 at the beginning of + mz80exec() (ASM Core only). Increases timing accuracy. + * NMIs And INTs add additional time to dwElapsedTicks as it should + * mz80ReleaseTimeslice() Sets remaining clocks to 0 instead of 1 + + +Revision 3.0: + + * All instructions validated against a real Z80. Used an ISA card + with a Z80 on it to validate flag handling, instruction handling, + timing, and other goodies. The only thing not implemented/emulated + is flag bit 3 & 5 emulation. Believed to be 100% bug free! + * 80% Speed improvement over version 2.7 of mz80 + * z80stb.c Removed. Use -c to emit a C version of mz80! API compatible! + Note that this is mostly, but not fully, debugged, so consider the + C version a beta! It's at least healthier than z80stb.c was. The C + version does not include the undocumented Z80 instructions. + * mz80nmi() No longer trashes registers it uses when using -cs + * IN/OUT Instructions work properly when using -16 + * IN A, (xxh) uses A as high 8 bits of I/O fetch address when using -16 + * IM 0/IM 1 Description in documentation fixed + * Sizes of all context registers increased to 32 bits - for speed! + * IFF1/IFF2 Now properly emulated + * JR Instruction offset can fetch from $ffff and properly wrap + * LDIR/LDDR Instruction now won't go to completion - instead it will + run until BC=0 or the # of cycles to execute have expired. These + instructions used to run to completion - even beyond the # of cycles + left to execute + * INI/IND/INIR/INDR countdown bug fixed - it was decrementing B twice + for each IN! Whoops! + * If you specify NULL as a handler address to a memory region, mz80 will + use vpData as a pointer to where that block of data resides. Quite + useful for multiprocessor emulations that share the same memory. + * EDI Now keeps track of cycle counting for faster execution + * Modified memory region scanning code to use 32 bit registers instead + of their 16 bit counterparts + * Get/SetContext() uses rep movsd/movsb. Insignificant overall, but + why waste the time? + * Debugging routines added. See the "DEBUGGING" section below for more + information. NOTE: The debugging routines are not yet available in + the C emission. + * Timing done slightly differently now. Mz80 now executes one + instruction past the timing given on input. For example, mz80exec(0) + will cause a single instruction to be executed (thusly -ss was + removed). + +Revision 2.7: + + * Fixed OTIR/OTDR/INIR/INDR instructions so their 16 bit counterparts + work properly + * Emulation core 30-70% faster overall than 2.6 due to optimization to + the timing routines + * Replaced word reads/writes with a special word write routine rather + than the standard calling to read/write byte functions + * z80stb.c (the C equivalent of mz80) compiles properly now + * Fixed OS/2 text/segment issue + * Fixed bug in set/getCPU context that ensures that ES=DS and avoids + crashes. Caused crashes under OS/2 and other OS's + +Revision 2.6: + + * Emulator core 5-30% faster overall. Some 16 and 8 bit instructions + sped up when using their 32 bit equivalents. + * Fix to -l so that proper labels without leading and trailing + underscores so Linux/FreeBSD compiles will work properly + * Single step now executes the # of instructions passed in to z80exec() + instead of just 1 as it had in prior releases. This is only active + when the -ss option is used. + * The -nt option was added. This will cause the timing information to + not be added in, speeding up execution. Warning: Only do this if your + emulated target does not require instruction timing! + * Updated documentation errors + * C Version of mz80 (mz80.c) that is API compliant is distributed with + the archive (With kind permission of Edward Massey). + +Revision 2.5: + + * Fixed an unconditional flag being cleared in the ddcbxx instructions. + It caused Donkey Kong's barrels to not roll. + +Revision 2.4: + + * Fixed improper HALT handling (didn't advance the PTR when it should) + * Fixed SRL (IX+$xx) instruction so that carry wasn't trashed + * Fixed single stepping problems with it giving too much time to + any given instruction + * Fixed half carry flag handling with 16 bit SBC and ADD instructions + * Fixed DAA emulation so that parity flags weren't getting trashed + +Revision 2.3: + + * Fixed many stack handling bugs + * Timing problems fixed. The prior version was causing massive + overruns on maximum timeslices with some insutructions. + +Revision 2.2: + + * Fixed a bug in CPI/CPD/CPIR/CPDR that mishandled flags + * All known bugs are out of mz80 now + * Added the -cs option to route all stack operations through the + handlers (required for games like Galaga) + +Revision 2.1: + + * Fixed a bug in CPI/CPD/CPIR/CPDR that caused intermittent lockups. + Also fixed a bug that caused erratic behavior in several video games. + * Added INI/IND/INIR/INDR instruction group + * Added OUTI/OUTD/OTIR/OTDR instruction group + +Revision 1.0: + + * First release! The whole thing is new! + + +ASSEMBLING FOR USE WITH WATCOM C/C++ +------------------------------------ + +Watcom, by default, uses register calling conventions, as does MZ80. To +create a proper emulator for Watcom: + + makez80 MZ80.asm -x86 + +From here: + + nasm -f win32 MZ80.asm + +Link the MZ80.obj with your Watcom linker. + + +ASSEMBLING FOR USE WITH MICROSOFT VISUAL C++ AND BORLAND C++ +-------------------------------------------------------------------- + +Visual C++ and Borland C++ use stack calling conventions by default. To +create a proper emulator for these compilers: + + makez80 MZ80.asm -s -x86 + +For Visual C++ or Borland C++: + + nasm -f win32 MZ80.asm + +Link with your standard Visual C++ or Borland C++. + + +ASSEMBLING FOR USE WITH DJGPP, GCC/FREEBSD, OR GCC/LINUX +-------------------------------------------------------------------- + +DJGPP Uses stack calling conventions: + + makez80 MZ80.asm -s -x86 + +To assemble: + + nasm -f coff MZ80.asm + +Link with your standard DJGPP linker. The same holds true for GCC under +FreeBSD or Linux. If you're using GCC, use the -l option to generate "plain" +labels so that gcc's linker will properly link things. + + +MAKEZ80 COMMAND LINE OPTIONS +---------------------------- + +-s - Use stack calling conventions (DJGPP, MSVC, Borland, etc...) + +-cs - Force all stack operations to go through the Read/Write memory handlers. + This slows things down, but is useful when needed. + +-16 - Treat all I/O input and output as 16 bit (BC) + +-l - Create 'plain' labels - ones without leading and trailing underscores + +-nt - Do not generate timing code - this speeds the emulator up, but the + downside is that no timing info is available. + +-c - Emit a C mz80 emulator (API Compatible with the assembly version - + handy for porters!) + +-x86 - Emit an assembly (x86) mz80 emulator + +-os2 - Generate OS/2 compatible segmentation + + +IMPORTANT NOTE ABOUT INTERRUPTS +------------------------------- + +A minor change was made between the 3.1 and 3.2 versions of makez80 in the +way that interrupts were handled. + +On a real Z80, the !INT line is a level triggered interrupt, meaning that if +the interrupt line is held low, the Z80 will continue to take interrupts +immediately after the instruction after the EI instruction is executed until +the interrupt line is high again. + +In 3.1, if an interrupt came in and interrupts were disabled, the interrupt +would never be "latched" for later execution. The Z80 does not have any +internal latching capabilities, however external hardware often does hold +the interrupt line low until the interrupt is executed, in effect, a latch. + +I've only found one video game so far that requires the "raising/lowering" +of the interrupt line (Ataxx). In the games that I've tried, it has improved +performance, in some cases drastically, and in others not at all. This can +be accounted for by interrupts being taken now, where they were being dropped +in prior mz80 releases. + +mz80 Emulates the most commonly used scenario. Now when mz80int() is executed +and a nonzero value is returned (indicating interrupts were disabled), it +will set z80intPending, and the interrupt will be taken after execution of +one instruction beyond the EI instruction. + +So now, if mz80int() returns a nonzero value, that means an interrupt is +latched. If clearing this latch is desired or the old behavior of 3.1 is +desired, make a call to the mz80ClearPendingInterrupt() call. It's a 2 +instruction call that has extremely small overhead and will not affect +performance in any measurable way. + +In any case, MZ80 will now execute one instruction after EI regardless of +how much time is available to avoid the possibility of an interrupt request +coming in directly after the EI instruction. + + +STEPS TO EMULATION +------------------ + +NOTE: -16 Is a command line option that will treat all I/O as 16 bit. That +is, in an instruction like "IN AL, (C)", the addressed passed to the I/O +handler will be BC instead of just C. Bear this in mind when considering your +emulated platform. + +There are a few steps you want to go through to get proper emulation, and a +few guidelines must be followed. + +1) Create a MZ80CONTEXT + +2) Create your virtual 64K memory space using whatever means of obtaining + memory you need to do. + +3) Set mz80Base in your context to be the base of your 64K memory space + +4) Load up your image to be emulated within that 64K address space. + +5) Set z80IoRead and z80IoWrite to their appropriate structure arrays. Here's + an example: + +struct z80PortRead ReadPorts[] = +{ + {0x10, 0x1f, SoundChip1Read}, + {0x20, 0x2f, SoundChip2Read} + {(UINT32) -1, (UINT32) -1, NULL} +}; + +When an IN instruction occurs, mz80 will probe this table looking for a +handler to the address of the "IN" instruction. If it is found in the list, +it's up to the handler to return the proper value. Otherwise, a value of +0ffh is returned internally if no handler for that I/O address is found. In +the case above, SoundChip1Read is called when the I/O address is between 0x10- +0x1f. A similar structure is used for I/O writes as well (OUT): + +struct z80PortWrite WritePorts[] = +{ + {0x20, 0x2f, SoundChip2Write}, + {0x30, 0x36, VideoCtrlWrite}, + {(UINT32) -1, (UINT32) -1, NULL} +} + +Of course, this does the opposite that the z80PortRead struct, and instead +looks for a handler to hand some data to. If it doesn't find an appropriate +handler, nothing happens. + +6) Set mz80MemoryRead & mz80MemoryWrite to their appropriate structure + arrays. Here is an example: + +struct MemoryWriteByte GameWrite[] = +{ + {0x3000, 0x3fff, VideoWrite}, + {0x4000, 0x4fff, SpriteWrite}, + {(UINT32) -1, (UINT32) -1, NULL} +}; + +The above example says that any time a write occurs in the 0x3000-0x3fff +range, call the VideoWrite routine. The same holds true for the SpriteWrite +region as well. + +NOTE: When your write handler is called, it is passed the address of the +write and the data that is to be written to it. If your handler doesn't +write the data to the virtual image, the mz80 internal code will not. + +NOTE: These routines will *NOT* be called when execution asks for these +addresses. It will only call them when a particular instruction uses the +memory at these locations. + +If you wish for a region to be RAM, just leave it out of your memory region +exception list. The WriteMemoryByte routine will treat it as read/write +RAM and will write to mz80Base + addr directly. + +If you wish to protect ROM regions (not often necessary), create a range that +encompasses the ROM image, and have it call a routine that does nothing. This +will prevent data from being written back onto the ROM image. + +Leave your last entry in the table as shown above, with a null handler and +0xffffffff-0xffffffff as your read address. Even though the Z80 only +addresses 64K of space, the read/write handlers are defined as 32 bit so +the compiler won't pass junk in the upper 16 bits of the address lines. Not +only that, it allows orthoganality for future CPU emulators that may use +these upper bits. + +You can do a mz80GetContext() if you'd like to read the current context of +the registers. Note that by the time your handler gets called, the program +counter will be pointing to the *NEXT* instruction. + +struct MemoryReadByte GameRead[] = +{ + {0x2000, 0x200f, ReadHandler}, + {(UINT32) -1, (UINT32) -1, NULL} +}; + +Same story here. If you have a special handler for an attempted read at a +particular address, place its range in this table and create a handler +routine for it. + +If you don't define a handler for a particular region, then the ReadMemoryByte +in mz80.ASM will actually read the value out of mz80Base + the offset +required to complete the instruction. + +7) Set the intAddr and nmiAddr to the addresses where you want mz80 to start + executing when an interrupt or NMI happens. Take a look at the section + entitled "INTERRUPTS" below for more information on this. + +8) Call mz80SetContext() on your Z80 context + +9) Call mz80Reset(). This will prime the program counter and cause a virtual + CPU-wide reset. + +10) Once you have those defined, you're ready to begin emulation. There's some + sort of main loop that you'll want. Maybe something like: + + while (hit == 0) + { + if (lastSec != (UINT32) time(0)) + { + diff = (mz80clockticks - prior) / 3000000; + printf("%ld Clockticks, %ld frames, %ld Times original speed\n", MZ80clockticks - prior, frames, diff); + frames = 0; + prior = mz80clockticks; + lastSec = time(0); + if (kbhit()) + { + getch(); + hit = 1; + } + } + + /* 9000 Cycles per NMI (~3 milliseconds @ 3MHZ) */ + + dwResult = mz80exec(9000); + mz80clockticks += mz80GetElapsedTicks(TRUE); + mz80nmi(); + + /* If the result is not 0x80000000, it's an address where + an invalid instruction was hit. */ + + if (0x80000000 != dwResult) + { + mz80GetContext(&sCpu1); + printf("Invalid instruction at %.2x\n", sCpu1.MZ80pc); + exit(1); + } + } + +Call mz80exec() With the # of virtual CPU cycles you'd like mz80 to +execute. Be sure to use the mz80GetElapsedTicks() call *AFTER* execution to +see how many virtual CPU cycles it actually executed. For example, if you tell +mz80 to execute 500 virtual CPU cycles, it will execute slightly more. Anything +from 500 to 524 (24 cycles being the longest any 1 instruction takes in the +Z80). + +Use the mz80GetElapsedTicks() call for more accurate cycle counting. Of course, +this is only if you have *NOT* included the -nt option. + +If you pass FALSE to the mz80GetElapsedTicks() function, the internal CPU +elapsed tick clock will not be reset. The elapsed tick counter is something +that continues to increase every emulated instruction, and like an odometer, +will keep counting unless you pass TRUE to mz80GetElapsedTicks(), of which +case it will return you the current value of the elapsed ticks and set it to +0 when complete. + +NOTE: The bigger value you pass to mz80exec, the greater benefit you get out +of the virtual registers persisting within the emulator, and it will run +faster. Pass in a value that is large enough to take advantage of it, but +not so often that you can't handle nmi or int's properly. + +If you wish to create a virtual NMI, call mz80nmi(), and it will be taken +the next time you call mz80exec, or alternately if you have a handler call +mz80nmi/mz80int(), the interrupt will be taken upon return. Note that +mz80nmi() doesn't actually execute any code - it only primes the emulator to +begin executing NMI/INT code. + +NOTE: mz80int() is defined with a UINT32 as a formal parameter. Depending +upon what interrupt mode you're executing in (described later), it may or may +not take a value. + +NMI's can interrupt interrupts, but not the other way around - just like a +real Z80. If your program is already in an interrupt, another one will not be +taken. The same holds true for an NMI - Just like a real Z80! + + +MUTLI-PROCESSOR NOTES +--------------------- + +Doing multi processor support is a bit trickier, but is still fairly straight- +forward. + +For each processor to be emulated, go through steps 1-7 above - giving each +CPU its own memory space, register storage, and read/write handlers. + + +EXECUTION OF MULTI-CPUS: +------------------------- + +When you're ready to execute a given CPU, do the following: + + mz80SetContext(contextPointer); + +This will load up all information saved before into the emulator and ready it +for execution. Then execute step 7 above to do your virtual NMI's, interrupts, +etc... All CPU state information is saved within a context. + +When the execution cycle is complete, do the following to save the updated +context away for later: + + mz80GetContext(contextPointer); + +Give each virtual processor a slice of time to execute. Don't make the values +too small or it will spend its time swapping contexts. While this in itself +isn't particularly CPU expensive, the more time you spend executing the better. +mz80 Keeps all of the Z80 register in native x86 register (including most +of the flags, HL, BC, and A). If no context swap is needed, then you get the +added advantage of the register storage. For example, let's say you were +running two Z80s - one at 2.0MHZ and one at 3.0MHZ. An example like this +might be desirable: + + mz80SetContext(cpu1Context); // Set CPU #1's information + mz80exec(2000); // 2000 Instructions for 2.0MHZ CPU + mz80GetContext(cpu1Context); // Get CPU #1's state info + + mz80SetContext(cpu2Context); // Set CPU #2's state information + mz80exec(3000); // 3000 Instructions for 3.0MHZ CPU + mz80GetContext(cpu2Context); // Get CPU #2's state information + +This isn't entirely realistic, but if you keep the instruction or timing +ratios between the emulated CPUs even, then timing is a bit more accurate. + +NOTE: If you need to make a particular CPU give up its own time cycle because +of a memory read/write, simply trap a particular address (say, a write to a +slave processor) and call mz80ReleaseTimeslice(). It will not execute any +further instructions, and will give up its timeslice. Put this in your +read/write memory trap. + +NOTE: You are responsible for "holding back" the processor emulator from +running too fast. + + +INTERRUPTS +---------- + +The Z80 has three interrupt modes: IM 0 - IM 2. Each act differently. Here's +a description of each: + +IM 0 + +This mode will cause the Z80 to be able to pull a "single byte instruction" +off the bus when an interrupt occurs. Since we're not doing bus cycle +emulation, it acts identically to mode 1 (described below). The formal +parameter to mz80int() is ignored. There is really no point in actually +emulating the instruction execution since any instruction that would be +executed would be a branch instruction! + +IM 1 + +This mode is the "default" mode that the Z80 (and mz80 for that matter) comes +up in. When you call mz80reset(), the interrupt address is set to 38h and +the NMI address is set to 66h. So when you're in IM 1 and mz80int() is +called, the formal parameter is ignored and the z80intAddr/z80nmiAddr values +are appropriately loaded into the program counter. + +IM 2 + +This mode causes the Z80 to read the upper 8 bits from the current value +of the "I" register, and the lower 8 bits from the value passed into mz80int(). +So, if I contained 35h, and you did an mz80int(0x64), then an interrupt at +address 3564h would be taken. Simple! + + +OTHER GOODIES +------------- + +MZ80 Has a nice feature for allowing the same handler to handle different +data regions on a single handler. Here's an example: + +struct PokeyDataStruct Pokey1; +struct PokeyDataStruct Pokey2; + +struct MemoryWriteByte GameWrite[] = +{ + {0x1000, 0x100f, PokeyHandler, Pokey1}, + {0x1010, 0x101f, PokeyHandler, Pokey2}, + {(UINT32) -1, (UINT32) -1, NULL} +}; + +void PokeyHandler(UINT32 dwAddr, UINT8 bData, struct sMemoryWriteByte *psMem) +{ + struct PokeyDataStruct *psPokey = psMem->pUserArea; + + // Do stuff with psPokey here.... +} + +This passes in the pointer to the sMemoryWriteByte structure that caused +the handler to be called. The pUserArea is a user defined address that can +be anything. It is not necessary to fill it in with anything or even +initialize it if the handler doesn't actually use it. + +This allows a single handler to handle multiple data references. This is +particularly useful when handling sound chip emulation, where there might +be more than one of a given device. Sure beats having multiple unique +handlers that are identical with the exception of the data area where it +writes! This allows a good deal of flexibility. + +The same construct holds for MemoryReadByte, z80PortRead, and z80PortWrite, +so all can take advantage of this feature. + + +SHARED MEMORY FEATURES +---------------------- + +MZ80 Also has another useful feature for dealing with shared memory regions: + +UINT8 bSharedRAM[0x100]; + +struct MemoryWriteByte Processor1[] = +{ + {0x1000, 0x10ff, NULL, bSharedRAM}, + {(UINT32) -1, (UINT32) -1, NULL} +}; + +struct MemoryWriteByte Processor2[] = +{ + {0x1000, 0x10ff, NULL, bSharedRAM}, + {(UINT32) -1, (UINT32) -1, NULL} +}; + +If the handler address is NULL, mz80 will look at the pUserArea field as a +pointer to RAM to read from/write to. This comes in extremely handy when you +have an emulation that requires two or more processors writing to the same +memory block. And it's lots faster than creating a handler that writes to +a common area as well. + + +DEBUGGING +--------- + +Several new functions have been added to mz80 that assist the emulator +author by providing a standard set of functions for register access: + +UINT8 mz80SetRegisterValue(void *pContext, UINT32 dwRegister, UINT32 dwValue) + +This allows setting of any register within the Z80. The register field can be +one of the following values (defined in mz80.h): + + CPUREG_PC + CPUREG_Z80_AF + CPUREG_Z80_BC + CPUREG_Z80_DE + CPUREG_Z80_HL + CPUREG_Z80_AFPRIME + CPUREG_Z80_BCPRIME + CPUREG_Z80_DEPRIME + CPUREG_Z80_HLPRIME + CPUREG_Z80_IX + CPUREG_Z80_IY + CPUREG_Z80_SP + CPUREG_Z80_I + CPUREG_Z80_R + CPUREG_Z80_A + CPUREG_Z80_B + CPUREG_Z80_C + CPUREG_Z80_D + CPUREG_Z80_E + CPUREG_Z80_H + CPUREG_Z80_L + CPUREG_Z80_F + CPUREG_Z80_CARRY + CPUREG_Z80_NEGATIVE + CPUREG_Z80_PARITY + CPUREG_Z80_OVERFLOW + CPUREG_Z80_HALFCARRY + CPUREG_Z80_ZERO + CPUREG_Z80_SIGN + CPUREG_Z80_IFF1 + CPUREG_Z80_IFF2 + +Each individual register's value can be set, including the flags at the end. +The only valid values for the flags are 1 and 0. Setting these will +automatically adjust the "F" register. + +If pContext is NULL, then the registers in the currently active context are +changed. If pContext points to a non-NULL area, that area is assumed to be +a CONTEXTMZ80 structure where the new register value will be written. + +If mz80SetRegisterValue() returns a nonzero value, either the register value +or register is out of range or invalid. + + +UINT32 mz80GetRegisterValue(void *pContext, UINT32 dwRegister) + +This returns the value of the register given on input (listed above as +CPUREG_Z80_xxxxx). Flag values will be 1 or 0. + +If pContext is NULL, then the registers in the currently active context are +read. If pContext points to a non-NULL area, that area is assumed to be +a CONTEXTMZ80 structure from which register values are pulled. + + +UINT32 mz80GetRegisterTextValue(void *pContext, UINT32 dwRegister, + UINT8 *pbTextArea) + +This returns the textual representation of the value of a given register. +It is a text printable string that can be used in sprintf() statements and +the like. This function is useful because different representations for +registers (like flags) can be a group of 8 flag bytes instead of a single +value. + +On entry, pContext being set to NULL indicates that mz80 should get the +register value from the currently active context. Otherwise, it is assumed +to be pointing to a CONTEXTMZ80 structure, which contains the value of the +registers to be read. + +pbTextArea points to a buffer where the value text can be written. This points +to a user supplied buffer. + +On exit, if any nonzero value is encountered, either the register # is out +of range or pbTextArea is NULL. + + +UINT8 *mz80GetRegisterName(UINT32 dwRegister) + +This returns a pointer to the textual name of the register passed in. NULL +Is returned if the register index (CPUREG_Z80_xxxx table described above) is +out of range. DO NOT MODIFY THE TEXT! It is static data. + + +FINAL NOTES +----------- + +I have debugged MZ80.ASM to the best of my abilities. There might still be +a few bugs floating around in it, but I'm not aware of any. I've validated +all instructions (That I could) against a custom built Z80 on an ISA card +(that fits in a PC) so I'm quite confident that it works just like a real +Z80. + +If you see any problems, please point them out to me, as I am eager to make +mz80 the best emulator that I can. + +If you have questions, comments, etc... about mz80, please don't hesitate +to send me an email. And if you use mz80 in your emulator, I'd love to take +a look at your work. If you have special needs, or need implementation +specific hints, feel free to email me, Neil Bradley (neil@synthcom.com). I +will do my best to help you. + +Enjoy! + +Neil Bradley +neil@synthcom.com + + diff --git a/platform/gp2x/940.c b/platform/gp2x/940.c new file mode 100644 index 00000000..c3f0b112 --- /dev/null +++ b/platform/gp2x/940.c @@ -0,0 +1,93 @@ +#include "940shared.h" + +/* this code assumes that we live @ 0x3000000 bank */ +//static volatile unsigned short *gp2x_memregs = (void *) 0x0xbd000000; +//static volatile unsigned long *gp2x_memregl = (void *) 0x0xbd000000; + +static _940_data_t *shared_data = (_940_data_t *) 0x100000; +static _940_ctl_t *shared_ctl = (_940_ctl_t *) 0x200000; +YM2612 *ym2612_940; +int *mix_buffer; + +// from init.s +void wait_irq(void); +void spend_cycles(int c); +void cache_clean(void); +void cache_clean_flush(void); + +// asm volatile ("mov r0, #0" ::: "r0"); +// asm volatile ("mcr p15, 0, r0, c7, c6, 0" ::: "r0"); /* flush dcache */ +// asm volatile ("mcr p15, 0, r0, c7, c10, 4" ::: "r0"); /* drain write buffer */ + +void Main940(int startvector) +{ + ym2612_940 = &shared_data->ym2612; + mix_buffer = shared_data->mix_buffer; + + // debug + shared_ctl->vstarts[startvector]++; + asm volatile ("mcr p15, 0, r0, c7, c10, 4" ::: "r0"); + + /* unmask IRQs */ + + for (;; shared_ctl->loopc++) + { +/* + while (!shared_ctl->busy) + { + //shared_ctl->waitc++; + spend_cycles(256); + } +*/ + if (!shared_ctl->busy) + { + wait_irq(); + } + + switch (shared_ctl->job) + { + case JOB940_YM2612INIT: + shared_ctl->writebuff0[0] = shared_ctl->writebuff1[0] = 0xffff; + YM2612Init_(shared_ctl->baseclock, shared_ctl->rate); + break; + + case JOB940_YM2612RESETCHIP: + YM2612ResetChip_(); + break; + + case JOB940_PICOSTATELOAD: + YM2612PicoStateLoad_(); + break; + + case JOB940_YM2612UPDATEONE: { + int i, dw, *wbuff; + if (shared_ctl->writebuffsel == 1) { + wbuff = (int *) shared_ctl->writebuff1; + } else { + wbuff = (int *) shared_ctl->writebuff0; + } + + /* playback all writes */ + for (i = 2048/2; i > 0; i--) { + UINT16 d; + dw = *wbuff++; + d = dw; + if (d == 0xffff) break; + YM2612Write_(d >> 8, d); + d = (dw>>16); + if (d == 0xffff) break; + YM2612Write_(d >> 8, d); + } + + YM2612UpdateOne_(0, shared_ctl->length, shared_ctl->stereo); +// cache_clean_flush(); + cache_clean(); +// asm volatile ("mov r0, #0" ::: "r0"); +// asm volatile ("mcr p15, 0, r0, c7, c10, 4" ::: "r0"); /* drain write buffer, should be done on nonbuffered write */ + break; + } + } + + shared_ctl->busy = 0; + } +} diff --git a/platform/gp2x/940ctl_ym2612.c b/platform/gp2x/940ctl_ym2612.c new file mode 100644 index 00000000..d8a10b23 --- /dev/null +++ b/platform/gp2x/940ctl_ym2612.c @@ -0,0 +1,451 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "940shared.h" +#include "gp2x.h" +#include "emu.h" +#include "menu.h" +#include "asmutils.h" + +/* we will need some gp2x internals here */ +extern volatile unsigned short *gp2x_memregs; /* from minimal library rlyeh */ +extern volatile unsigned long *gp2x_memregl; + +static unsigned char *shared_mem = 0; +static _940_data_t *shared_data = 0; +static _940_ctl_t *shared_ctl = 0; + +int crashed_940 = 0; + + +/***********************************************************/ + +#define MAXOUT (+32767) +#define MINOUT (-32768) + +/* limitter */ +#define Limit(val, max,min) { \ + if ( val > max ) val = max; \ + else if ( val < min ) val = min; \ +} + +/* these will be managed locally on our side */ +extern int *ym2612_dacen; +extern INT32 *ym2612_dacout; +extern void *ym2612_regs; + +static UINT8 *REGS = 0; /* we will also keep local copy of regs for savestates and such */ +static INT32 addr_A1; /* address line A1 */ +static int dacen; +static INT32 dacout; +static UINT8 ST_address; /* address register */ +static UINT8 ST_status; /* status flag */ +static UINT8 ST_mode; /* mode CSM / 3SLOT */ +static int ST_TA; /* timer a */ +static int ST_TAC; /* timer a maxval */ +static int ST_TAT; /* timer a ticker */ +static UINT8 ST_TB; /* timer b */ +static int ST_TBC; /* timer b maxval */ +static int ST_TBT; /* timer b ticker */ + +static int writebuff_ptr = 0; + + +/* OPN Mode Register Write */ +static void set_timers( int v ) +{ + /* b7 = CSM MODE */ + /* b6 = 3 slot mode */ + /* b5 = reset b */ + /* b4 = reset a */ + /* b3 = timer enable b */ + /* b2 = timer enable a */ + /* b1 = load b */ + /* b0 = load a */ + ST_mode = v; + + /* reset Timer b flag */ + if( v & 0x20 ) + ST_status &= ~2; + + /* reset Timer a flag */ + if( v & 0x10 ) + ST_status &= ~1; +} + +/* YM2612 write */ +/* a = address */ +/* v = value */ +/* returns 1 if sample affecting state changed */ +int YM2612Write_940(unsigned int a, unsigned int v) +{ + int addr; //, ret=1; + + v &= 0xff; /* adjust to 8 bit bus */ + a &= 3; + + switch( a ) { + case 0: /* address port 0 */ + ST_address = v; + addr_A1 = 0; + //ret=0; + break; + + case 1: /* data port 0 */ + if (addr_A1 != 0) { + return 0; /* verified on real YM2608 */ + } + + addr = ST_address; + REGS[addr] = v; + + switch( addr & 0xf0 ) + { + case 0x20: /* 0x20-0x2f Mode */ + switch( addr ) + { + case 0x24: { // timer A High 8 + int TAnew = (ST_TA & 0x03)|(((int)v)<<2); + if(ST_TA != TAnew) { + // we should reset ticker only if new value is written. Outrun requires this. + ST_TA = TAnew; + ST_TAC = (1024-TAnew)*18; + ST_TAT = 0; + } + return 0; + } + case 0x25: { // timer A Low 2 + int TAnew = (ST_TA & 0x3fc)|(v&3); + if(ST_TA != TAnew) { + ST_TA = TAnew; + ST_TAC = (1024-TAnew)*18; + ST_TAT = 0; + } + return 0; + } + case 0x26: // timer B + if(ST_TB != v) { + ST_TB = v; + ST_TBC = (256-v)<<4; + ST_TBC *= 18; + ST_TBT = 0; + } + return 0; + case 0x27: /* mode, timer control */ + set_timers( v ); + break; // other side needs ST.mode for 3slot mode + case 0x2a: /* DAC data (YM2612) */ + dacout = ((int)v - 0x80) << 6; /* level unknown (notaz: 8 seems to be too much) */ + return 0; + case 0x2b: /* DAC Sel (YM2612) */ + /* b7 = dac enable */ + dacen = v & 0x80; + break; // other side has to know this + default: + break; + } + break; + } + break; + + case 2: /* address port 1 */ + ST_address = v; + addr_A1 = 1; + //ret=0; + break; + + case 3: /* data port 1 */ + if (addr_A1 != 1) { + return 0; /* verified on real YM2608 */ + } + + addr = ST_address | 0x100; + REGS[addr] = v; + break; + } + + if(currentConfig.EmuOpt & 4) { + /* queue this write for 940 */ + if (writebuff_ptr < 2047) { + if (shared_ctl->writebuffsel == 1) { + shared_ctl->writebuff0[writebuff_ptr++] = (a<<8)|v; + } else { + shared_ctl->writebuff1[writebuff_ptr++] = (a<<8)|v; + } + } else { + printf("warning: writebuff_ptr > 2047\n"); + } + } + + return 0; // cause the engine to do updates once per frame only +} + +UINT8 YM2612Read_940(void) +{ + return ST_status; +} + + +int YM2612PicoTick_940(int n) +{ + //int ret = 0; + + // timer A + if(ST_mode & 0x01 && (ST_TAT+=64*n) >= ST_TAC) { + ST_TAT -= ST_TAC; + if(ST_mode & 0x04) ST_status |= 1; + // CSM mode total level latch and auto key on +/* FIXME + if(ST_mode & 0x80) { + CSMKeyControll( &(ym2612_940->CH[2]) ); // Vectorman2, etc. + ret = 1; + } +*/ + } + + // timer B + if(ST_mode & 0x02 && (ST_TBT+=64*n) >= ST_TBC) { + ST_TBT -= ST_TBC; + if(ST_mode & 0x08) ST_status |= 2; + } + + return 0; +} + + +static void wait_busy_940(void) +{ + int i; +#if 0 + printf("940 busy, entering wait loop.. (cnt: %i, wc: %i, ve: ", shared_ctl->loopc, shared_ctl->waitc); + for (i = 0; i < 8; i++) + printf("%i ", shared_ctl->vstarts[i]); + printf(")\n"); + + for (i = 0; shared_ctl->busy; i++) + { + spend_cycles(1024); /* needs tuning */ + } + printf("wait iterations: %i\n", i); +#else + for (i = 0; shared_ctl->busy && i < 0x10000; i++) + spend_cycles(4*1024); + if (i < 0x10000) return; + + /* 940 crashed */ + printf("940 crashed (cnt: %i, wc: %i, ve: ", shared_ctl->loopc, shared_ctl->waitc); + for (i = 0; i < 8; i++) + printf("%i ", shared_ctl->vstarts[i]); + printf(")\n"); + strcpy(menuErrorMsg, "940 crashed."); + engineState = PGS_Menu; + crashed_940 = 1; +#endif +} + + +static void add_job_940(int job) +{ + shared_ctl->job = job; + shared_ctl->busy = 1; + gp2x_memregs[0x3B3E>>1] = 0xffff; // cause an IRQ for 940 +} + + +void YM2612PicoStateLoad_940(void) +{ + int i, old_A1 = addr_A1; + + if (shared_ctl->busy) wait_busy_940(); + + // feed all the registers and update internal state + for(i = 0; i < 0x100; i++) { + YM2612Write_940(0, i); + YM2612Write_940(1, REGS[i]); + } + for(i = 0; i < 0x100; i++) { + YM2612Write_940(2, i); + YM2612Write_940(3, REGS[i|0x100]); + } + + addr_A1 = old_A1; + + add_job_940(JOB940_PICOSTATELOAD); +} + + +static void internal_reset(void) +{ + writebuff_ptr = 0; + ST_mode = 0; + ST_status = 0; /* normal mode */ + ST_TA = 0; + ST_TAC = 0; + ST_TB = 0; + ST_TBC = 0; + dacen = 0; +} + + +extern char **g_argv; + +/* none of the functions in this file should be called before this one */ +void YM2612Init_940(int baseclock, int rate) +{ + printf("YM2612Init_940()\n"); + //printf("sizeof(*shared_data): %i (%x)\n", sizeof(*shared_data), sizeof(*shared_data)); + //printf("sizeof(*shared_ctl): %i (%x)\n", sizeof(*shared_ctl), sizeof(*shared_ctl)); + + Reset940(1); + Pause940(1); + + gp2x_memregs[0x3B46>>1] = 0xffff; // clear pending DUALCPU interrupts for 940 + gp2x_memregs[0x3B42>>1] = 0xffff; // enable DUALCPU interrupts for 940 + + gp2x_memregl[0x4508>>2] = ~(1<<26); // unmask DUALCPU ints in the undocumented 940's interrupt controller + + if (shared_mem == NULL) + { + shared_mem = (unsigned char *) mmap(0, 0x210000, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0x3000000); + if(shared_mem == MAP_FAILED) + { + printf("mmap(shared_data) failed with %i\n", errno); + exit(1); + } + shared_data = (_940_data_t *) (shared_mem+0x100000); + /* this area must not get buffered on either side */ + shared_ctl = (_940_ctl_t *) (shared_mem+0x200000); + crashed_940 = 1; + } + + if (crashed_940) + { + unsigned char ucData[1024]; + int nRead, i, nLen = 0; + char binpath[1024]; + FILE *fp; + + strncpy(binpath, g_argv[0], 1023); + binpath[1023] = 0; + for (i = strlen(binpath); i > 0; i--) + if (binpath[i] == '/') { binpath[i] = 0; break; } + strcat(binpath, "/code940.bin"); + + fp = fopen(binpath, "rb"); + if(!fp) + { + memset(gp2x_screen, 0, 320*240); + gp2x_text_out8(10, 100, "failed to open required file:"); + gp2x_text_out8(10, 110, "code940.bin"); + gp2x_video_flip(); + printf("failed to open %s\n", binpath); + exit(1); + } + + while(1) + { + nRead = fread(ucData, 1, 1024, fp); + if(nRead <= 0) + break; + memcpy(shared_mem + nLen, ucData, nRead); + nLen += nRead; + } + fclose(fp); + crashed_940 = 0; + } + + memset(shared_data, 0, sizeof(*shared_data)); + memset(shared_ctl, 0, sizeof(*shared_ctl)); + + REGS = YM2612GetRegs(); + + ym2612_dacen = &dacen; + ym2612_dacout = &dacout; + + internal_reset(); + + /* now cause 940 to init it's ym2612 stuff */ + shared_ctl->baseclock = baseclock; + shared_ctl->rate = rate; + shared_ctl->job = JOB940_YM2612INIT; + shared_ctl->busy = 1; + + /* start the 940 */ + Reset940(0); + Pause940(0); + + // YM2612ResetChip_940(); // will be done on JOB940_YM2612INIT +} + + +void YM2612ResetChip_940(void) +{ + printf("YM2612ResetChip_940()\n"); + if (shared_data == NULL) { + printf("YM2612ResetChip_940: reset before init?\n"); + return; + } + + if (shared_ctl->busy) wait_busy_940(); + + internal_reset(); + + add_job_940(JOB940_YM2612RESETCHIP); +} + + +void YM2612UpdateOne_940(short *buffer, int length, int stereo) +{ + int i, *mix_buffer = shared_data->mix_buffer; + + //printf("YM2612UpdateOne_940()\n"); + if (shared_ctl->busy) wait_busy_940(); + + //printf("940 (cnt: %i, wc: %i, ve: ", shared_ctl->loopc, shared_ctl->waitc); + //for (i = 0; i < 8; i++) + // printf("%i ", shared_ctl->vstarts[i]); + //printf(")\n"); + + /* mix data from previous go */ + if (stereo) { + int *mb = mix_buffer; + for (i = length; i > 0; i--) { + int l, r; + l = r = *buffer; + l += *mb++, r += *mb++; + Limit( l, MAXOUT, MINOUT ); + Limit( r, MAXOUT, MINOUT ); + *buffer++ = l; *buffer++ = r; + } + } else { + for (i = 0; i < length; i++) { + int l = mix_buffer[i]; + l += buffer[i]; + Limit( l, MAXOUT, MINOUT ); + buffer[i] = l; + } + } + + //printf("new writes: %i\n", writebuff_ptr); + if (shared_ctl->writebuffsel == 1) { + shared_ctl->writebuff0[writebuff_ptr] = 0xffff; + } else { + shared_ctl->writebuff1[writebuff_ptr] = 0xffff; + } + writebuff_ptr = 0; + + /* give 940 another job */ + shared_ctl->writebuffsel ^= 1; + shared_ctl->length = length; + shared_ctl->stereo = stereo; + add_job_940(JOB940_YM2612UPDATEONE); + //spend_cycles(512); + //printf("SRCPND: %08lx, INTMODE: %08lx, INTMASK: %08lx, INTPEND: %08lx\n", + // gp2x_memregl[0x4500>>2], gp2x_memregl[0x4504>>2], gp2x_memregl[0x4508>>2], gp2x_memregl[0x4510>>2]); +} diff --git a/platform/gp2x/940ctl_ym2612.h b/platform/gp2x/940ctl_ym2612.h new file mode 100644 index 00000000..7d94c133 --- /dev/null +++ b/platform/gp2x/940ctl_ym2612.h @@ -0,0 +1,9 @@ +void YM2612Init_940(int baseclock, int rate); +void YM2612ResetChip_940(void); +void YM2612UpdateOne_940(short *buffer, int length, int stereo); + +int YM2612Write_940(unsigned int a, unsigned int v); +unsigned char YM2612Read_940(void); + +int YM2612PicoTick_940(int n); +void YM2612PicoStateLoad_940(void); diff --git a/platform/gp2x/940init.s b/platform/gp2x/940init.s new file mode 100644 index 00000000..e28b453b --- /dev/null +++ b/platform/gp2x/940init.s @@ -0,0 +1,174 @@ +.global code940 + +code940: @ interrupt table: + b .b_reset @ reset + b .b_undef @ undefined instructions + b .b_swi @ software interrupt + b .b_pabort @ prefetch abort + b .b_dabort @ data abort + b .b_reserved @ reserved + b .b_irq @ IRQ + b .b_fiq @ FIQ + +@ test +.b_reset: + mov r12, #0 + b .Begin +.b_undef: + mov r12, #1 + b .Begin +.b_swi: + mov r12, #2 + b .Begin +.b_pabort: + mov r12, #3 + b .Begin +.b_dabort: + mov r12, #4 + b .Begin +.b_reserved: + mov r12, #5 + b .Begin +.b_irq: + mov r12, #6 + mov sp, #0x100000 @ reset stack + sub sp, sp, #4 + mov r1, #0xbd000000 @ assume we live @ 0x3000000 bank + orr r2, r1, #0x3B00 + orr r2, r2, #0x0046 + mvn r3, #0 + strh r3, [r2] @ clear any pending interrupts from the DUALCPU unit + orr r2, r1, #0x4500 + str r3, [r2] @ clear all pending interrupts in irq controller's SRCPND register + orr r2, r2, #0x0010 + str r3, [r2] @ clear all pending interrupts in irq controller's INTPND register + b .Enter +.b_fiq: + mov r12, #7 + b .Begin + +.Begin: + mov sp, #0x100000 @ set the stack top (1M) + sub sp, sp, #4 @ minus 4 + + @ set up memory region 0 -- the whole 4GB address space + mov r0, #(0x1f<<1)|1 @ region data + mcr p15, 0, r0, c6, c0, 0 @ opcode2 ~ data/instr + mcr p15, 0, r0, c6, c0, 1 + + @ set up region 1 which is the first 2 megabytes. + mov r0, #(0x14<<1)|1 @ region data + mcr p15, 0, r0, c6, c1, 0 + mcr p15, 0, r0, c6, c1, 1 + + @ set up region 2: 64k 0x200000-0x210000 + mov r0, #(0x0f<<1)|1 + orr r0, r0, #0x200000 + mcr p15, 0, r0, c6, c2, 0 + mcr p15, 0, r0, c6, c2, 1 + + @ set up region 3: 64k 0xbd000000-0xbd010000 (hw control registers) + mov r0, #(0x0f<<1)|1 + orr r0, r0, #0xbd000000 + mcr p15, 0, r0, c6, c3, 0 + mcr p15, 0, r0, c6, c3, 1 + + @ set region 1 to be cacheable (so the first 2M will be cacheable) + mov r0, #2 + mcr p15, 0, r0, c2, c0, 0 + mcr p15, 0, r0, c2, c0, 1 + + @ set region 1 to be bufferable too (only data) + mcr p15, 0, r0, c3, c0, 0 + + @ set protection, allow accsess only to regions 1 and 2 + mov r0, #(3<<6)|(3<<4)|(3<<2)|(0) @ data: [full, full, full, no access] for regions [3 2 1 0] + mcr p15, 0, r0, c5, c0, 0 + mov r0, #(0<<6)|(0<<4)|(3<<2)|(0) @ instructions: [no access, no, full, no] + mcr p15, 0, r0, c5, c0, 1 + + mrc p15, 0, r0, c1, c0, 0 @ fetch current control reg + orr r0, r0, #1 @ 0x00000001: enable protection unit + orr r0, r0, #4 @ 0x00000004: enable D cache + orr r0, r0, #0x1000 @ 0x00001000: enable I cache + orr r0, r0, #0xC0000000 @ 0xC0000000: async+fastbus + mcr p15, 0, r0, c1, c0, 0 @ set control reg + + @ flush (invalidate) the cache (just in case) + mov r0, #0 + mcr p15, 0, r0, c7, c6, 0 + +.Enter: + mov r0, r12 + bl Main940 + + @ we should never get here +.b_deadloop: + b .b_deadloop + + + +@ so asm utils are also defined here: +.global spend_cycles @ c + +spend_cycles: + mov r0, r0, lsr #2 @ 4 cycles/iteration + sub r0, r0, #2 @ entry/exit/init +.sc_loop: + subs r0, r0, #1 + bpl .sc_loop + + bx lr + + +@ clean-flush function from ARM940T technical reference manual +.global cache_clean_flush + +cache_clean_flush: + mov r1, #0 @ init line counter +ccf_outer_loop: + mov r0, #0 @ segment counter +ccf_inner_loop: + orr r2, r1, r0 @ make segment and line address + mcr p15, 0, r2, c7, c14, 2 @ clean and flush that line + add r0, r0, #0x10 @ incremet secment counter + cmp r0, #0x40 @ complete all 4 segments? + bne ccf_inner_loop + add r1, r1, #0x04000000 @ increment line counter + cmp r1, #0 @ complete all lines? + bne ccf_outer_loop + bx lr + + +@ clean-only version +.global cache_clean + +cache_clean: + mov r1, #0 @ init line counter +cf_outer_loop: + mov r0, #0 @ segment counter +cf_inner_loop: + orr r2, r1, r0 @ make segment and line address + mcr p15, 0, r2, c7, c10, 2 @ clean that line + add r0, r0, #0x10 @ incremet secment counter + cmp r0, #0x40 @ complete all 4 segments? + bne cf_inner_loop + add r1, r1, #0x04000000 @ increment line counter + cmp r1, #0 @ complete all lines? + bne cf_outer_loop + bx lr + + +.global wait_irq + +wait_irq: + mrs r0, cpsr + bic r0, r0, #0x80 + msr cpsr_c, r0 @ enable interrupts + + mov r0, #0 + mcr p15, 0, r0, c7, c0, 4 @ wait for IRQ +@ mcr p15, 0, r0, c15, c8, 2 + b .b_reserved + +.pool diff --git a/platform/gp2x/940shared.h b/platform/gp2x/940shared.h new file mode 100644 index 00000000..71114da6 --- /dev/null +++ b/platform/gp2x/940shared.h @@ -0,0 +1,33 @@ +#include "../../Pico/sound/ym2612.h" + +enum _940_job_t { + JOB940_YM2612INIT = 1, + JOB940_YM2612RESETCHIP, + JOB940_YM2612UPDATEONE, + JOB940_PICOSTATELOAD, + JOB940_NUMJOBS +}; + + +typedef struct +{ + YM2612 ym2612; /* current state of the emulated YM2612 */ + int mix_buffer[44100/50*2]; /* this is where the YM2612 samples will be mixed to */ +} _940_data_t; + + +typedef struct +{ + int job; /* a job for second core */ + int busy; /* busy status of the 940 core */ + int length; /* number of samples to mix (882 max) */ + int stereo; /* mix samples as stereo, doubles sample count automatically */ + int baseclock; /* ym2612 settings */ + int rate; + int writebuffsel; /* which write buffer to use (from 940 side) */ + UINT16 writebuff0[2048]; /* 1024 for savestates, 1024 extra */ + UINT16 writebuff1[2048]; + int vstarts[8]; /* debug: number of starts from each of 8 vectors */ + int loopc; /* debug: main loop counter */ + int waitc; /* debug: wait loop counter */ +} _940_ctl_t; diff --git a/platform/gp2x/Makefile b/platform/gp2x/Makefile new file mode 100644 index 00000000..c634c3dd --- /dev/null +++ b/platform/gp2x/Makefile @@ -0,0 +1,191 @@ + +# you may or may not need to change this +#devkit_path = x:/stuff/dev/devkitgp2x/ +devkit_path = /usr/local/devkitPro/devkitGP2X/ +lgcc_path = $(devkit_path)lib/gcc/arm-linux/4.0.3/ +CROSS = arm-linux- +#CROSS = $(devkit_path)bin/arm-linux- + +# settings +dprint = 1 +#mz80 = 1 +#debug_cyclone = 1 +asm_memory = 1 +asm_render = 1 +asm_ym2612 = 1 +#profile = 1 +#use_musashi = 1 +#up = 1 + +DEFINC = -I../.. -I. -D__GP2X__ -D_UNZIP_SUPPORT # -DBENCHMARK +COPT_COMMON = -static -s -O3 -ftracer -fstrength-reduce -Wall -funroll-loops -fomit-frame-pointer -fstrict-aliasing -ffast-math +ifeq "$(profile)" "1" +COPT_COMMON += -fprofile-generate +endif +ifeq "$(profile)" "2" +COPT_COMMON += -fprofile-use +endif +COPT = $(COPT_COMMON) -mtune=arm920t +ASOPT = -mcpu=arm920t -mfloat-abi=soft +GCC = $(CROSS)gcc +STRIP = $(CROSS)strip +AS = $(CROSS)as +LD = $(CROSS)ld +OBJCOPY = $(CROSS)objcopy + +# frontend +OBJS += main.o menu.o gp2x.o usbjoy.o emu.o squidgehack.o asmutils.o cpuctrl.o +# 940 core control +OBJS += 940ctl_ym2612.o +# Pico +OBJS += ../../Pico/Area.o ../../Pico/Cart.o ../../Pico/Utils.o ../../Pico/Memory.o ../../Pico/Misc.o \ + ../../Pico/Pico.o ../../Pico/Sek.o ../../Pico/VideoPort.o ../../Pico/Draw2.o ../../Pico/Draw.o +# asm stuff +ifeq "$(asm_render)" "1" +DEFINC += -D_ASM_DRAW_C +OBJS += ../../Pico/draw_asm.o ../../Pico/draw2_asm.o +endif +ifeq "$(asm_memory)" "1" +DEFINC += -D_ASM_MEMORY_C +OBJS += ../../Pico/memory_asm.o +endif +ifeq "$(asm_ym2612)" "1" +DEFINC += -D_ASM_YM2612_C +OBJS += ../../Pico/sound/ym2612_asm.o +endif +# Pico - sound +OBJS += ../../Pico/sound/sound.o ../../Pico/sound/sn76496.o ../../Pico/sound/ym2612.o +# zlib +OBJS += ../../zlib/gzio.o ../../zlib/inffast.o ../../zlib/inflate.o ../../zlib/inftrees.o ../../zlib/trees.o \ + ../../zlib/deflate.o ../../zlib/crc32.o ../../zlib/adler32.o ../../zlib/zutil.o ../../zlib/compress.o +# unzip +OBJS += ../../unzip/unzip.o +# CPU cores +ifeq "$(use_musashi)" "1" +DEFINC += -DEMU_M68K +OBJS += _build\m68kcpu.o _build\m68kopac.o _build\m68kopdm.o _build\m68kopnz.o _build\m68kops.o +else +DEFINC += -DEMU_C68K +OBJS += ../../cpu/Cyclone/proj/Cyclone.o +endif +# drz80/mz80 +ifeq "$(mz80)" "1" +DEFINC += -D_USE_MZ80 +OBJS += ../../cpu/mz80/mz80.o +else +DEFINC += -D_USE_DRZ80 +OBJS += ../../cpu/DrZ80/drz80.o +endif + +all: PicoDrive.gpe code940.bin + +PicoDrive.gpe : $(OBJS) + @echo $@ + @$(GCC) $(COPT) $(OBJS) $(PRELIBS) -lm -o $@ + @$(STRIP) $@ +# @$(GCC) $(COPT) $(OBJS) $(PRELIBS) -lm -o PicoDrive_.gpe +# @gpecomp PicoDrive_.gpe $@ +ifeq "$(up)" "1" + @cmd //C copy $@ \\\\10.0.1.2\\gp2x\\mnt\\sd\\games\\PicoDrive\\ +endif + +up: up940 + @cmd //C copy PicoDrive.gpe \\\\10.0.1.2\\gp2x\\mnt\\sd\\games\\PicoDrive\\ +up940: + @cmd //C copy code940.bin \\\\10.0.1.2\\gp2x\\mnt\\sd\\games\\PicoDrive\\ + +testrefr.gpe : test.o gp2x.o asmutils.o + @echo $@ + @$(GCC) $(COPT) $^ $(PRELIBS) -o $@ + @$(STRIP) $@ + +.c.o: + @echo $< + @$(GCC) $(COPT) $(DEFINC) -c $< -o $@ +.s.o: + @echo $< + @$(GCC) $(COPT) $(DEFINC) -c $< -o $@ + +../../Pico/draw_asm.o : ../../Pico/Draw.s + @echo $< + @$(AS) $(ASOPT) $< -o $@ +../../Pico/draw2_asm.o : ../../Pico/Draw2.s + @echo $< + @$(AS) $(ASOPT) $< -o $@ +../../Pico/memory_asm.o : ../../Pico/Memory.s + @echo $< + @$(AS) $(ASOPT) $< -o $@ +../../Pico/sound/ym2612_asm.o : ../../Pico/sound/ym2612.s + @echo $< + @$(AS) $(ASOPT) $< -o $@ + +# build Cyclone +../../cpu/Cyclone/proj/Cyclone.s : + @echo building Cyclone... + @make -C ../../cpu/Cyclone/proj -f Makefile.linux + + +# stuff for 940 core + +# init, emu_control, emu +OBJS940 += 940init.o 940.o 940ym2612.o +# the asm code seems to be faster when run on 920, but not on 940 for some reason +# OBJS940 += ../../Pico/sound/ym2612_asm.o + +# uClibc library code +OBJS940 += uClibc/memset.o uClibc/s_floor.o uClibc/e_pow.o uClibc/e_sqrt.o uClibc/s_fabs.o +OBJS940 += uClibc/s_scalbn.o uClibc/s_copysign.o uClibc/k_sin.o uClibc/k_cos.o uClibc/s_sin.o +OBJS940 += uClibc/e_rem_pio2.o uClibc/k_rem_pio2.o uClibc/e_log.o uClibc/wrappers.o + +code940.bin : code940.gpe + @echo $@ + @$(OBJCOPY) -O binary $< $@ + +code940.gpe : $(OBJS940) + @echo $@ + @$(LD) -static -e code940 -Ttext 0x0 $^ -L$(lgcc_path) -lgcc -o $@ + +940ym2612.o : ../../Pico/sound/ym2612.c + @echo $@ + @$(GCC) $(COPT_COMMON) -mtune=arm940t $(DEFINC) -DEXTERNAL_YM2612 -c $< -o $@ + + +# cleanup +clean: clean_pd clean_940 +tidy: tidy_pd tidy_940 + +clean_pd: tidy_pd + @$(RM) PicoDrive.gpe +tidy_pd: + @$(RM) $(OBJS) +# @make -C ../../cpu/Cyclone/proj -f Makefile.linux clean + +clean_940: tidy_940 + @$(RM) code940.bin +tidy_940: + @$(RM) code940.gpe $(OBJS940) + +clean_prof: + find ../.. -name '*.gcno' -delete + find ../.. -name '*.gcda' -delete + +# test +usbjoy.o : usbjoy.c + @echo $< + @$(GCC) $(COPT) $(DEFINC) -fno-profile-generate -c $< -o $@ + +../../Pico/Cart.o : ../../Pico/Cart.c + @echo $< + @$(GCC) $(COPT) $(DEFINC) -fno-profile-generate -c $< -o $@ + +../../zlib/trees.o : ../../zlib/trees.c + @echo $< + @$(GCC) $(COPT) $(DEFINC) -fno-profile-generate -c $< -o $@ + +uClibc/e_pow.o : uClibc/e_pow.c + @echo $< + @$(GCC) $(COPT) $(DEFINC) -fno-profile-generate -c $< -o $@ + +uClibc/e_sqrt.o : uClibc/e_sqrt.c + @echo $< + @$(GCC) $(COPT) $(DEFINC) -fno-profile-generate -c $< -o $@ diff --git a/platform/gp2x/asmutils.h b/platform/gp2x/asmutils.h new file mode 100644 index 00000000..d9226900 --- /dev/null +++ b/platform/gp2x/asmutils.h @@ -0,0 +1,12 @@ +// (c) Copyright 2006 notaz, All rights reserved. +// Free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + +void vidConvCpyRGB32 (void *to, void *from, int pixels); +void vidConvCpyRGB32sh(void *to, void *from, int pixels); +void vidConvCpyRGB32hi(void *to, void *from, int pixels); +void vidCpyM2_40col(void *dest, void *src); +void vidCpyM2_32col(void *dest, void *src); +void vidCpyM2_32col_nobord(void *dest, void *src); +void spend_cycles(int c); // utility diff --git a/platform/gp2x/asmutils.s b/platform/gp2x/asmutils.s new file mode 100644 index 00000000..e1e09451 --- /dev/null +++ b/platform/gp2x/asmutils.s @@ -0,0 +1,210 @@ +@ some color conversion and blitting routines + +@ (c) Copyright 2006, notaz +@ All Rights Reserved + + +@ Convert 0000bbb0 ggg0rrr0 0000bbb0 ggg0rrr0 +@ to 00000000 rrr00000 ggg00000 bbb00000 ... + +@ lr = 0x00e000e0, out: r3=lower_pix, r2=higher_pix; trashes rin +@ if sh==2, r8=0x00404040 (sh!=0 destroys flags!) +.macro convRGB32_2 rin sh=0 + and r2, lr, \rin, lsr #4 @ blue + and r3, \rin, lr + orr r2, r2, r3, lsl #8 @ g0b0g0b0 + + mov r3, r2, lsl #16 @ g0b00000 + and \rin,lr, \rin, ror #12 @ 00r000r0 (reversed) + orr r3, r3, \rin, lsr #16 @ g0b000r0 +.if \sh == 1 + mov r3, r3, ror #17 @ shadow mode +.elseif \sh == 2 + adds r3, r3, #0x40000000 @ green + orrcs r3, r3, #0xe0000000 + mov r3, r3, ror #8 + adds r3, r3, #0x40000000 + orrcs r3, r3, #0xe0000000 + mov r3, r3, ror #16 + adds r3, r3, #0x40000000 + orrcs r3, r3, #0xe0000000 + mov r3, r3, ror #24 +.else + mov r3, r3, ror #16 @ r3=low +.endif + + orr r3, r3, r3, lsr #3 + str r3, [r0], #4 + + mov r2, r2, lsr #16 + orr r2, r2, \rin, lsl #16 +.if \sh == 1 + mov r2, r2, lsr #1 +.elseif \sh == 2 + mov r2, r2, ror #8 + adds r2, r2, #0x40000000 @ blue + orrcs r2, r2, #0xe0000000 + mov r2, r2, ror #8 + adds r2, r2, #0x40000000 + orrcs r2, r2, #0xe0000000 + mov r2, r2, ror #8 + adds r2, r2, #0x40000000 + orrcs r2, r2, #0xe0000000 + mov r2, r2, ror #8 +.endif + + orr r2, r2, r2, lsr #3 + str r2, [r0], #4 +.endm + + +.global vidConvCpyRGB32 @ void *to, void *from, int pixels + +vidConvCpyRGB32: + stmfd sp!, {r4-r7,lr} + + mov r12, r2, lsr #3 @ repeats + mov lr, #0x00e00000 + orr lr, lr, #0x00e0 + +.loopRGB32: + subs r12, r12, #1 + + ldmia r1!, {r4-r7} + convRGB32_2 r4 + convRGB32_2 r5 + convRGB32_2 r6 + convRGB32_2 r7 + + bgt .loopRGB32 + + ldmfd sp!, {r4-r7,lr} + bx lr + + +.global vidConvCpyRGB32sh @ void *to, void *from, int pixels + +vidConvCpyRGB32sh: + stmfd sp!, {r4-r7,lr} + + mov r12, r2, lsr #3 @ repeats + mov lr, #0x00e00000 + orr lr, lr, #0x00e0 + +.loopRGB32sh: + subs r12, r12, #1 + + ldmia r1!, {r4-r7} + convRGB32_2 r4, 1 + convRGB32_2 r5, 1 + convRGB32_2 r6, 1 + convRGB32_2 r7, 1 + + bgt .loopRGB32sh + + ldmfd sp!, {r4-r7,lr} + bx lr + + +.global vidConvCpyRGB32hi @ void *to, void *from, int pixels + +vidConvCpyRGB32hi: + stmfd sp!, {r4-r7,lr} + + mov r12, r2, lsr #3 @ repeats + mov lr, #0x00e00000 + orr lr, lr, #0x00e0 + +.loopRGB32hi: + ldmia r1!, {r4-r7} + convRGB32_2 r4, 2 + convRGB32_2 r5, 2 + convRGB32_2 r6, 2 + convRGB32_2 r7, 2 + + subs r12, r12, #1 + bgt .loopRGB32hi + + ldmfd sp!, {r4-r7,lr} + bx lr + + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + +@ mode2 blitter for 40 cols +.global vidCpyM2_40col @ void *dest, void *src + +vidCpyM2_40col: + stmfd sp!, {r4-r6,lr} + + mov r12, #224 @ lines + add r1, r1, #8 + +vidCpyM2_40_loop_out: + mov r6, #10 +vidCpyM2_40_loop: + subs r6, r6, #1 + ldmia r1!, {r2-r5} + stmia r0!, {r2-r5} + ldmia r1!, {r2-r5} + stmia r0!, {r2-r5} + bne vidCpyM2_40_loop + subs r12,r12,#1 + add r1, r1, #8 + bne vidCpyM2_40_loop_out + + ldmfd sp!, {r4-r6,lr} + bx lr + + +@ mode2 blitter for 32 cols +.global vidCpyM2_32col @ void *dest, void *src + +vidCpyM2_32col: + stmfd sp!, {r4-r6,lr} + + mov r12, #224 @ lines + add r1, r1, #8 + add r0, r0, #32 + +vidCpyM2_32_loop_out: + mov r6, #8 +vidCpyM2_32_loop: + subs r6, r6, #1 + ldmia r1!, {r2-r5} + stmia r0!, {r2-r5} + ldmia r1!, {r2-r5} + stmia r0!, {r2-r5} + bne vidCpyM2_32_loop + subs r12,r12,#1 + add r0, r0, #64 + add r1, r1, #8+64 + bne vidCpyM2_32_loop_out + + ldmfd sp!, {r4-r6,lr} + bx lr + + +@ mode2 blitter for 32 cols with no borders +.global vidCpyM2_32col_nobord @ void *dest, void *src + +vidCpyM2_32col_nobord: + stmfd sp!, {r4-r6,lr} + + mov r12, #224 @ lines + add r1, r1, #8 + b vidCpyM2_32_loop_out + + +@ test +.global spend_cycles @ c + +spend_cycles: + mov r0, r0, lsr #2 @ 4 cycles/iteration + sub r0, r0, #2 @ entry/exit/init +.sc_loop: + subs r0, r0, #1 + bpl .sc_loop + + bx lr diff --git a/platform/gp2x/config.txt b/platform/gp2x/config.txt new file mode 100644 index 00000000..0874946b --- /dev/null +++ b/platform/gp2x/config.txt @@ -0,0 +1,138 @@ +As PicoDrive is multiplatform emulator, this is GP2X specific part of readme +about configuration. + + +Configuration +------------- + +1. "Renderer" +8bit fast: +This enables alternative heavily optimized tile-based renderer, which renders +pixels not line-by-line (this is what accurate renderers do), but in 8x8 tiles, +which is much faster. But because of the way it works it can't render any +mid-frame image changes (raster effects), so it is useful only with some games. + +Other two are accurate line-based renderers. The 8bit is faster but does not +run well with some games like Street Racer. + +2. "Accurate timing" +This adds some more emulation precision, but slows the emulation down. Whithout +this option some games do not boot (Red Zone for example), others have sound +problems. + +3. "Accurate sprites" +This option improves emulation of sprite priorities, it also enables emulation +of sprite collision bit. If you see one sprite being drawn incorrectly above +the other (often seen in Sonic 3D Blast), you can enable this to fix the problem. +This only works with the default renderer (see first option). + +4. "Show FPS" +Self-explanatory. Format is XX/YY, where XX is the number of rendered frames and +YY is the number of emulated frames per second. + +5. "Frameskip" +How many frames to skip rendering before displaying another. +"Auto" is recommended. + +6. "Enable sound" +Does what it says. You must enable at least YM2612 or SN76496 (in advanced options, +see below) for this to make sense. + +7. "Sound Quality" +Sound rate and stereo mode. If you want 44100Hz sound, it is recommended to enable +the second core (next option). + +8. "Use ARM940 core for sound" +This option causes PicoDrive to use ARM940T core (GP2X's second CPU) for sound +(i.e. to generate YM2612 samples) to improve performance noticeably. + +9. "6 button pad" +If you enable this, games will think that 6 button gamepad is connected. If you +go and reconfigure your keys, you will be able to bind X,Y,Z and mode actions. + +10. "Genesis Region" +This option lets you force the game to think it is running on machine from the +specified region. + +11. "Use SRAM savestates" +This will automatically read/write SRAM savestates for games which are using them. +SRAM is saved whenever you pause your game or exit the emulator. + +12. "GP2X CPU clocks" +Here you can change clocks of both GP2X's CPUs. Larger values increase performance. +There is no separate option for the second CPU because both CPUs use the same clock +source. Setting this option to 200 will cause PicoDrive NOT to change GP2X's clocks +at all. + +13. "[advanced options]" +Enters advanced options menu (see below). + +14. "Save cfg as default" +If you save your config here it will be loaded on next ROM load, but only if there +is no game specific config saved (which will be loaded in that case). + +15. "Save cfg for current game only" +Whenever you load current ROM again these settings will be loaded (squidgehack and +RAM settings will not take effect until emulator is restarted). + +Advanced configuration +---------------------- + +Enter [advanced options] in config menu to see these options. + +1. "Scale 32 column mode" +This enables hardware scaling for lower-res genesis mode (where width is +32 8-pixel tiles, instead of 40 in other mode). + +2. "Gamma correction" +Alters image gamma through GP2X hardware. Larger values make image to look brighter, +lower - darker (default is 1.0). + +3. "Emulate Z80" +Enables emulation of Z80 chip, which was mostly used to drive the other sound chips. +Some games do complex sync with it, so you must enable it even if you don't use +sound to be able to play them. + +4. "Emulate YM2612 (FM)" +This enables emulation of six-channel FM sound synthesizer chip, which was used to +produce sound effects and music. + +5. "Emulate SN76496 (PSG)" +This enables emulation of additional sound chip for additional effects. + +Note: if you change sound settings AFTER loading a ROM, you may need to reset +game to get sound. This is because most games initialize sound chips on +startup, and this data is lost when sound chips are being enabled/disabled. + +6. "gzip savestates" +This will always apply gzip compression on your savestates, allowing you to +save some space and load/save time. + +7. "USB joy controls player X" +If you are able to use USB joysticks with your GP2X, this options selects which +player the joystick controls. + +8. "Don't save config on exit" +This will disable config autowrite on exit (which might cause SD card corruption +according to DaveC). + +9. "craigix's RAM timings" +This overclocks the GP2X RAM chips, but may cause instability. Recommended if you +use the second core for sound. Needs emulator restart to take effect. +See this thread: +http://www.gp32x.com/board/index.php?showtopic=32319 + +10. "squidgehack" +Well known way to improve the GP2X performance. You must restart the emulator +for the change of this option to take effect. + + +Key configuration +----------------- + +When you select "Configure controls" from the menu, you enter a key configuration +mode, where you use SELECT to change an action, and then press a key you like to +bind to that action. You can press the same key again to unbind. Select "DONE" +action and press any key to finish. + + diff --git a/platform/gp2x/cpuctrl.c b/platform/gp2x/cpuctrl.c new file mode 100644 index 00000000..7bbdb675 --- /dev/null +++ b/platform/gp2x/cpuctrl.c @@ -0,0 +1,156 @@ +/* cpuctrl for GP2X + Copyright (C) 2005 Hermes/PS2Reality + the gamma-routine was provided by theoddbot + parts (c) Rlyehs Work & (C) 2006 god_at_hell + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include +#include +#include "cpuctrl.h" + + +/* system registers */ +static struct +{ + unsigned short SYSCLKENREG,SYSCSETREG,FPLLVSETREG,DUALINT920,DUALINT940,DUALCTRL940,MEMTIMEX0,MEMTIMEX1; +} +system_reg; + +static unsigned short dispclockdiv; + +static volatile unsigned short *MEM_REG; + +#define SYS_CLK_FREQ 7372800 + + +void cpuctrl_init(void) +{ + extern volatile unsigned short *gp2x_memregs; /* from minimal library rlyeh */ + MEM_REG=&gp2x_memregs[0]; + system_reg.SYSCSETREG=MEM_REG[0x91c>>1]; + system_reg.FPLLVSETREG=MEM_REG[0x912>>1]; + system_reg.SYSCLKENREG=MEM_REG[0x904>>1]; + system_reg.DUALINT920=MEM_REG[0x3B40>>1]; + system_reg.DUALINT940=MEM_REG[0x3B42>>1]; + system_reg.DUALCTRL940=MEM_REG[0x3B48>>1]; + system_reg.MEMTIMEX0=MEM_REG[0x3802>>1]; + system_reg.MEMTIMEX1=MEM_REG[0x3804>>1]; + dispclockdiv=MEM_REG[0x924>>1]; +} + + +void cpuctrl_deinit(void) +{ + MEM_REG[0x91c>>1]=system_reg.SYSCSETREG; + MEM_REG[0x910>>1]=system_reg.FPLLVSETREG; + MEM_REG[0x3B40>>1]=system_reg.DUALINT920; + MEM_REG[0x3B42>>1]=system_reg.DUALINT940; + MEM_REG[0x3B48>>1]=system_reg.DUALCTRL940; + MEM_REG[0x904>>1]=system_reg.SYSCLKENREG; + MEM_REG[0x924>>1]=dispclockdiv; + MEM_REG[0x3802>>1]=system_reg.MEMTIMEX0; + MEM_REG[0x3804>>1]=system_reg.MEMTIMEX1 /*| 0x9000*/; +} + + +void set_display_clock_div(unsigned div) +{ + div=((div & 63) | 64)<<8; + MEM_REG[0x924>>1]=(MEM_REG[0x924>>1] & ~(255<<8)) | div; +} + + +void set_FCLK(unsigned MHZ) +{ + unsigned v; + unsigned mdiv,pdiv=3,scale=0; + MHZ*=1000000; + mdiv=(MHZ*pdiv)/SYS_CLK_FREQ; + mdiv=((mdiv-8)<<8) & 0xff00; + pdiv=((pdiv-2)<<2) & 0xfc; + scale&=3; + v=mdiv | pdiv | scale; + MEM_REG[0x910>>1]=v; +} + + +void set_920_Div(unsigned short div) +{ + unsigned short v; + v = MEM_REG[0x91c>>1] & (~0x3); + MEM_REG[0x91c>>1] = (div & 0x7) | v; +} + + +void set_DCLK_Div( unsigned short div ) +{ + unsigned short v; + v = (unsigned short)( MEM_REG[0x91c>>1] & (~(0x7 << 6)) ); + MEM_REG[0x91c>>1] = ((div & 0x7) << 6) | v; +} + +/* +void Disable_940(void) +{ + MEM_REG[0x3B42>>1]; + MEM_REG[0x3B42>>1]=0; + MEM_REG[0x3B46>>1]=0xffff; + MEM_REG[0x3B48>>1]|= (1 << 7); + MEM_REG[0x904>>1]&=0xfffe; +} +*/ + +void set_RAM_Timings(int tRC, int tRAS, int tWR, int tMRD, int tRFC, int tRP, int tRCD) +{ + tRC -= 1; tRAS -= 1; tWR -= 1; tMRD -= 1; tRFC -= 1; tRP -= 1; tRCD -= 1; // ??? + MEM_REG[0x3802>>1] = ((tMRD & 0xF) << 12) | ((tRFC & 0xF) << 8) | ((tRP & 0xF) << 4) | (tRCD & 0xF); + MEM_REG[0x3804>>1] = /*0x9000 |*/ ((tRC & 0xF) << 8) | ((tRAS & 0xF) << 4) | (tWR & 0xF); +} + + +/* +void gp2x_video_wait_vsync(void) +{ + MEM_REG[0x2846>>1]=(MEM_REG[0x2846>>1] | 0x20) & ~2; + while(!(MEM_REG[0x2846>>1] & 2)); +} +*/ + +void set_gamma(int g100) +{ + float gamma = (float) g100 / 100; + int i; + //printf ("set gamma = %f\r\n",gamma); + gamma = 1/gamma; + + //enable gamma + MEM_REG[0x2880>>1]&=~(1<<12); + + MEM_REG[0x295C>>1]=0; + for(i=0; i<256; i++) + { + unsigned char g; + unsigned short s; + g =(unsigned char)(255.0*pow(i/255.0,gamma)); + s = (g<<8) | g; + MEM_REG[0x295E>>1]= s; + MEM_REG[0x295E>>1]= g; + } +} + diff --git a/platform/gp2x/cpuctrl.gpl.txt b/platform/gp2x/cpuctrl.gpl.txt new file mode 100644 index 00000000..3912109b --- /dev/null +++ b/platform/gp2x/cpuctrl.gpl.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/platform/gp2x/cpuctrl.h b/platform/gp2x/cpuctrl.h new file mode 100644 index 00000000..5b482a55 --- /dev/null +++ b/platform/gp2x/cpuctrl.h @@ -0,0 +1,16 @@ +#ifndef __CPUCTRL_H__ +#define __CPUCTRL_H__ + +extern void cpuctrl_init(void); /* call this at first */ +extern void save_system_regs(void); /* save some registers */ +extern void cpuctrl_deinit(void); +extern void set_display_clock_div(unsigned div); +extern void set_FCLK(unsigned MHZ); /* adjust the clock frequency (in Mhz units) */ +extern void set_920_Div(unsigned short div); /* 0 to 7 divider (freq=FCLK/(1+div)) */ +extern void set_DCLK_Div(unsigned short div); /* 0 to 7 divider (freq=FCLK/(1+div)) */ +//extern void Disable_940(void); /* 940t down */ +//extern void gp2x_video_wait_vsync(void); +extern void set_RAM_Timings(int tRC, int tRAS, int tWR, int tMRD, int tRFC, int tRP, int tRCD); +extern void set_gamma(int g100); + +#endif diff --git a/platform/gp2x/emu.c b/platform/gp2x/emu.c new file mode 100644 index 00000000..0e4fdd74 --- /dev/null +++ b/platform/gp2x/emu.c @@ -0,0 +1,1121 @@ +// (c) Copyright 2006 notaz, All rights reserved. +// Free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + +#include +#include +#include +#include +#include +#include + +#include + +#include "emu.h" +#include "gp2x.h" +#include "usbjoy.h" +#include "menu.h" +#include "asmutils.h" +#include "cpuctrl.h" + +#include "Pico/PicoInt.h" +#include "zlib/zlib.h" + + +#ifdef BENCHMARK +#define OSD_FPS_X 220 +#else +#define OSD_FPS_X 260 +#endif + +// PicoPad[] format: SACB RLDU +char *actionNames[] = { + "UP", "DOWN", "LEFT", "RIGHT", "B", "C", "A", "START", + 0, 0, 0, 0, 0, 0, 0, 0, // Z, Y, X, MODE (enabled only when needed), ?, ?, ?, ? + 0, 0, 0, 0, 0, 0, 0, "ENTER MENU", // player2_flag, ?, ?, ?, ?, ?, ?, menu + "NEXT SAVE SLOT", "PREV SAVE SLOT", "SWITCH RENDERER", "SAVE STATE", + "LOAD STATE", "VOLUME UP", "VOLUME DOWN", "DONE" +}; + +int engineState; +int select_exits = 0; +char *PicoConfigFile = "picoconfig.bin"; +currentConfig_t currentConfig; + +char romFileName[PATH_MAX]; +unsigned char *rom_data = NULL; + +extern int crashed_940; + +static char noticeMsg[64]; // notice msg to draw +static struct timeval noticeMsgTime = { 0, 0 }; // when started showing +static int reset_timing, osd_fps_x; +static int combo_keys = 0, combo_acts = 0; // keys and actions which need button combos +static int gp2x_old_gamma = 100; +static unsigned char *movie_data = NULL; +static int movie_size = 0; +static int frame_count = 0; +unsigned char *framebuff = 0; // temporary buffer for alt renderer +int state_slot = 0; + +/* +// tmp +static FILE *logf = NULL; + +void pprintf(char *texto, ...) +{ + va_list args; + + va_start(args,texto); + vfprintf(logf,texto,args); + va_end(args); + fflush(logf); + sync(); +} +*/ +// utilities +static void strlwr(char* string) +{ + while ( (*string++ = (char)tolower(*string)) ); +} + +static int try_rfn_ext(char *ext) +{ + FILE *tmp; + char *p; + + p = romFileName + strlen(romFileName) - 4; + if (p < romFileName) p = romFileName; + strcpy(p, ext); + + if((tmp = fopen(romFileName, "rb"))) { + fclose(tmp); + return 1; + } + return 0; +} + +int emu_ReloadRom(void) +{ + unsigned int rom_size = 0; + char ext[5], *p; + FILE *rom; + int ret; + + printf("emu_ReloadRom(%s)\n", romFileName); + + // detect wrong extensions (.srm and .mds) + p = romFileName + strlen(romFileName) - 4; + if (p < romFileName) p = romFileName; + strncpy(ext, p, 4); + ext[4] = 0; + strlwr(ext); + + if(!strcmp(ext, ".srm") || !strcmp(ext, "s.gz") || !strcmp(ext, ".mds")) { // s.gz ~ .mds.gz + sprintf(menuErrorMsg, "Not a ROM selected."); + return 0; + } + + // check for movie file + if(movie_data) { + free(movie_data); + movie_data = 0; + } + if(!strcmp(ext, ".gmv")) { + // check for both gmv and rom + int dummy; + FILE *movie_file = fopen(romFileName, "rb"); + if(!movie_file) { + sprintf(menuErrorMsg, "Failed to open movie."); + return 0; + } + fseek(movie_file, 0, SEEK_END); + movie_size = ftell(movie_file); + fseek(movie_file, 0, SEEK_SET); + if(movie_size < 64+3) { + sprintf(menuErrorMsg, "Invalid GMV file."); + fclose(movie_file); + return 0; + } + movie_data = malloc(movie_size); + if(movie_data == NULL) { + sprintf(menuErrorMsg, "low memory."); + fclose(movie_file); + return 0; + } + fread(movie_data, 1, movie_size, movie_file); + fclose(movie_file); + if (strncmp((char *)movie_data, "Gens Movie TEST", 15) != 0) { + sprintf(menuErrorMsg, "Invalid GMV file."); + return 0; + } + dummy = try_rfn_ext(".zip") || try_rfn_ext(".bin") || + try_rfn_ext(".smd") || try_rfn_ext(".gen"); + if (!dummy) { + sprintf(menuErrorMsg, "Could't find a ROM for movie."); + return 0; + } + } + + rom = fopen(romFileName, "rb"); + if(!rom) { + sprintf(menuErrorMsg, "Failed to open rom."); + return 0; + } + + if(rom_data) { + free(rom_data); + rom_data = 0; + rom_size = 0; + } + + // zipfile support + if(!strcasecmp(ext, ".zip")) { + fclose(rom); + ret = CartLoadZip(romFileName, &rom_data, &rom_size); + if(ret) { + if (ret == 4) strcpy(menuErrorMsg, "No ROMs in zip found."); + else sprintf(menuErrorMsg, "Unzip failed with code %i", ret); + printf("%s\n", menuErrorMsg); + return 0; + } + } else { + if( (ret = PicoCartLoad(rom, &rom_data, &rom_size)) ) { + sprintf(menuErrorMsg, "PicoCartLoad() failed."); + printf("%s\n", menuErrorMsg); + fclose(rom); + return 0; + } + fclose(rom); + } + + // detect wrong files (Pico crashes on very small files), also see if ROM EP is good + if(rom_size <= 0x200 || strncmp((char *)rom_data, "Pico", 4) == 0 || + ((*(unsigned short *)(rom_data+4)<<16)|(*(unsigned short *)(rom_data+6))) >= (int)rom_size) { + if (rom_data) free(rom_data); + rom_data = 0; + sprintf(menuErrorMsg, "Not a ROM selected."); + return 0; + } + + printf("PicoCartInsert(%p, %d);\n", rom_data, rom_size); + if(PicoCartInsert(rom_data, rom_size)) { + sprintf(menuErrorMsg, "Failed to load ROM."); + return 0; + } + + // load config for this ROM + ret = emu_ReadConfig(1); + if (!ret) + emu_ReadConfig(0); + + // emu_ReadConfig() might have messed currentConfig.lastRomFile + strncpy(currentConfig.lastRomFile, romFileName, sizeof(currentConfig.lastRomFile)-1); + currentConfig.lastRomFile[sizeof(currentConfig.lastRomFile)-1] = 0; + + // additional movie stuff + if(movie_data) { + if(movie_data[0x14] == '6') + PicoOpt |= 0x20; // 6 button pad + else PicoOpt &= ~0x20; + if(movie_data[0xF] >= 'A') { + //Pico.m.pal = movie_data[0x16] >> 7; + // TODO: bits 6 & 5 + } + strcpy(noticeMsg, "MOVIE LOADED"); + } + else + { + if(Pico.m.pal) { + strcpy(noticeMsg, "PAL SYSTEM / 50 FPS"); + } else { + strcpy(noticeMsg, "NTSC SYSTEM / 60 FPS"); + } + } + gettimeofday(¬iceMsgTime, 0); + + // load SRAM for this ROM + if(currentConfig.EmuOpt & 1) + emu_SaveLoadGame(1, 1); + + frame_count = 0; + + return 1; +} + + +void emu_Init(void) +{ + // make temp buffer for alt renderer + framebuff = malloc((8+320)*(8+240+8)); + if (!framebuff) + { + printf("framebuff == 0\n"); + } + + PicoInit(); + +// logf = fopen("log.txt", "w"); +} + + +static void romfname_ext(char *dst, char *ext) +{ + char *p; + + // make save filename + for (p = romFileName+strlen(romFileName)-1; p >= romFileName && *p != '/'; p--); p++; + strncpy(dst, p, 511); + dst[511-8] = 0; + if(dst[strlen(dst)-4] == '.') dst[strlen(dst)-4] = 0; + strcat(dst, ext); +} + + +static void find_combos(void) +{ + int act, u; + + // find out which keys and actions are combos + combo_keys = combo_acts = 0; + for (act = 0; act < 32; act++) + { + int keyc = 0; + if (act == 16) continue; // player2 flag + for (u = 0; u < 32; u++) + { + if (currentConfig.KeyBinds[u] & (1 << act)) keyc++; + } + if (keyc > 1) + { + // loop again and mark those keys and actions as combo + for (u = 0; u < 32; u++) + { + if (currentConfig.KeyBinds[u] & (1 << act)) { + combo_keys |= 1 << u; + combo_acts |= 1 << act; + } + } + } + } + // printf("combo keys/acts: %08x %08x\n", combo_keys, combo_acts); +} + + +int emu_ReadConfig(int game) +{ + FILE *f; + char cfg[512]; + int bread = 0; + + if (!game) + { + // set default config + memset(¤tConfig, 0, sizeof(currentConfig)); + currentConfig.lastRomFile[0] = 0; + currentConfig.EmuOpt = 0x1f; + currentConfig.PicoOpt = 0x0f; + currentConfig.PsndRate = 22050; + currentConfig.PicoRegion = 0; // auto + currentConfig.Frameskip = -1; // auto + currentConfig.CPUclock = 200; + currentConfig.volume = 50; + currentConfig.KeyBinds[ 0] = 1<<0; // SACB RLDU + currentConfig.KeyBinds[ 4] = 1<<1; + currentConfig.KeyBinds[ 2] = 1<<2; + currentConfig.KeyBinds[ 6] = 1<<3; + currentConfig.KeyBinds[14] = 1<<4; + currentConfig.KeyBinds[13] = 1<<5; + currentConfig.KeyBinds[12] = 1<<6; + currentConfig.KeyBinds[ 8] = 1<<7; + currentConfig.KeyBinds[15] = 1<<26; // switch rend + currentConfig.KeyBinds[10] = 1<<27; // save state + currentConfig.KeyBinds[11] = 1<<28; // load state + currentConfig.KeyBinds[23] = 1<<29; // vol up + currentConfig.KeyBinds[22] = 1<<30; // vol down + currentConfig.gamma = 100; + strncpy(cfg, PicoConfigFile, 511); + cfg[511] = 0; + } else { + romfname_ext(cfg, ".pbcfg"); + } + + printf("emu_ReadConfig: %s ", cfg); + f = fopen(cfg, "rb"); + if (f) { + bread = fread(¤tConfig, 1, sizeof(currentConfig), f); + fclose(f); + } + printf((bread == sizeof(currentConfig)) ? "(ok)\n" : "(failed)\n"); + + PicoOpt = currentConfig.PicoOpt; + PsndRate = currentConfig.PsndRate; + PicoRegionOverride = currentConfig.PicoRegion; + if (PicoOpt & 0x20) { + actionNames[ 8] = "Z"; actionNames[ 9] = "Y"; + actionNames[10] = "X"; actionNames[11] = "MODE"; + } + // some sanity checks + if (currentConfig.CPUclock < 1 || currentConfig.CPUclock > 4096) currentConfig.CPUclock = 200; + if (currentConfig.gamma < 10 || currentConfig.gamma > 300) currentConfig.gamma = 100; + // if volume keys are unbound, bind them to volume control + if (!currentConfig.KeyBinds[23] && !currentConfig.KeyBinds[22]) { + currentConfig.KeyBinds[23] = 1<<29; // vol up + currentConfig.KeyBinds[22] = 1<<30; // vol down + } + + return (bread == sizeof(currentConfig)); +} + + +int emu_WriteConfig(int game) +{ + FILE *f; + char cfg[512]; + int bwrite = 0; + + if (!game) + { + strncpy(cfg, PicoConfigFile, 511); + cfg[511] = 0; + } else { + romfname_ext(cfg, ".pbcfg"); + } + + printf("emu_WriteConfig: %s ", cfg); + f = fopen(cfg, "wb"); + if (f) { + currentConfig.PicoOpt = PicoOpt; + currentConfig.PsndRate = PsndRate; + currentConfig.PicoRegion = PicoRegionOverride; + bwrite = fwrite(¤tConfig, 1, sizeof(currentConfig), f); + fflush(f); + fclose(f); + sync(); + } + printf((bwrite == sizeof(currentConfig)) ? "(ok)\n" : "(failed)\n"); + + return (bwrite == sizeof(currentConfig)); +} + + +void emu_Deinit(void) +{ + // save SRAM + if((currentConfig.EmuOpt & 1) && SRam.changed) { + emu_SaveLoadGame(0, 1); + SRam.changed = 0; + } + + if (!(currentConfig.EmuOpt & 0x20)) + emu_WriteConfig(0); + free(framebuff); + + PicoExit(); +// fclose(logf); + + // restore gamma + if (gp2x_old_gamma != 100) + set_gamma(100); +} + + +void osd_text(int x, int y, char *text) +{ + int len = strlen(text)*8; + + if ((PicoOpt&0x10)||!(currentConfig.EmuOpt&0x80)) { + int *p, i, h, black, white; + if (PicoOpt&0x10) { + black = 0x40404040; white = 0x41; + } else { + black = 0xe0e0e0e0; white = 0xf0; + } + x &= ~3; // align x + len = (len+3) >> 2; + for (h = 0; h < 8; h++) { + p = (int *) ((unsigned char *) gp2x_screen+x+320*(y+h)); + for (i = len; i; i--, p++) *p = black; + } + gp2x_text_out8_2(x, y, text, white); + } else { + int *p, i, h; + x &= ~1; // align x + len = (len+1) >> 1; + for (h = 0; h < 8; h++) { + p = (int *) ((unsigned short *) gp2x_screen+x+320*(y+h)); + for (i = len; i; i--, p++) *p = (*p>>2)&0x39e7; + } + gp2x_text_out15(x, y, text); + } +} + +static int EmuScan16(unsigned int num, void *sdata) +{ + if (!(Pico.video.reg[1]&8)) num += 8; + DrawLineDest = (unsigned short *) gp2x_screen + 320*(num+1); + + return 0; +} + +static int EmuScan8(unsigned int num, void *sdata) +{ + if (!(Pico.video.reg[1]&8)) num += 8; + DrawLineDest = (unsigned char *) gp2x_screen + 320*(num+1); + + return 0; +} + +static int localPal[0x100]; +static void (*vidCpyM2)(void *dest, void *src) = NULL; + +static void blit(char *fps, char *notice) +{ + if (PicoOpt&0x10) { + // 8bit fast renderer + if (Pico.m.dirtyPal) { + Pico.m.dirtyPal = 0; + vidConvCpyRGB32(localPal, Pico.cram, 0x40); + // feed new palette to our device + gp2x_video_setpalette(localPal, 0x40); + } + vidCpyM2((unsigned char *)gp2x_screen+320*8, framebuff+328*8); + } else if (!(currentConfig.EmuOpt&0x80)) { + // 8bit accurate renderer + if (Pico.m.dirtyPal) { + Pico.m.dirtyPal = 0; + if(Pico.video.reg[0xC]&8) { // shadow/hilight mode + vidConvCpyRGB32(localPal, Pico.cram, 0x40); + vidConvCpyRGB32sh(localPal+0x40, Pico.cram, 0x40); + vidConvCpyRGB32hi(localPal+0x80, Pico.cram, 0x40); + blockcpy(localPal+0xc0, localPal+0x40, 0x40*4); + localPal[0xe0] = 0x00000000; // reserved pixels for OSD + localPal[0xf0] = 0x00ffffff; + gp2x_video_setpalette(localPal, 0x100); + } else if (rendstatus & 0x20) { // mid-frame palette changes + vidConvCpyRGB32(localPal, Pico.cram, 0x40); + vidConvCpyRGB32(localPal+0x40, HighPal, 0x40); + vidConvCpyRGB32(localPal+0x80, HighPal+0x40, 0x40); + gp2x_video_setpalette(localPal, 0xc0); + } else { + vidConvCpyRGB32(localPal, Pico.cram, 0x40); + gp2x_video_setpalette(localPal, 0x40); + } + } + } + + if (notice) osd_text(4, 232, notice); + if (currentConfig.EmuOpt & 2) + osd_text(osd_fps_x, 232, fps); + + //gp2x_video_wait_vsync(); + gp2x_video_flip(); + + if (!(PicoOpt&0x10)) { + if (!(Pico.video.reg[1]&8)) { + if (currentConfig.EmuOpt&0x80) { + DrawLineDest = (unsigned short *) gp2x_screen + 320*8; + } else { + DrawLineDest = (unsigned char *) gp2x_screen + 320*8; + } + } else { + DrawLineDest = gp2x_screen; + } + } +} + + +// clears whole screen or just the notice area (in all buffers) +static void clearArea(int full) +{ + if (PicoOpt&0x10) { + // 8bit fast renderer + if (full) gp2x_memset_all_buffers(0, 0x40, 320*240); + else gp2x_memset_all_buffers(320*232, 0x40, 320*8); + } else if (currentConfig.EmuOpt&0x80) { + // 16bit accurate renderer + if (full) gp2x_memset_all_buffers(0, 0, 320*240*2); + else gp2x_memset_all_buffers(320*232*2, 0, 320*8*2); + } else { + // 8bit accurate renderer + if (full) gp2x_memset_all_buffers(0, 0xe0, 320*240); + else gp2x_memset_all_buffers(320*232, 0xe0, 320*8); + } +} + + +static void vidResetMode(void) +{ + if (PicoOpt&0x10) { + localPal[0x40] = 0; + localPal[0x41] = 0x00ffffff; + gp2x_video_changemode(8); + gp2x_video_setpalette(localPal, 0x42); + gp2x_memset_all_buffers(0, 0x40, 320*240); + gp2x_video_flip(); + } else if (currentConfig.EmuOpt&0x80) { + gp2x_video_changemode(15); + PicoDrawSetColorFormat(1); + PicoScan = EmuScan16; + PicoScan(0, 0); + } else { + localPal[0xe0] = 0x00000000; // reserved pixels for OSD + localPal[0xf0] = 0x00ffffff; + gp2x_video_changemode(8); + gp2x_video_setpalette(localPal, 0x100); + gp2x_memset_all_buffers(0, 0xe0, 320*240); + gp2x_video_flip(); + PicoDrawSetColorFormat(2); + PicoScan = EmuScan8; + PicoScan(0, 0); + } + Pico.m.dirtyPal = 1; + // reset scaling + gp2x_video_RGB_setscaling((PicoOpt&0x100)&&!(Pico.video.reg[12]&1) ? 256 : 320, 240); +} + + +static int check_save_file(void) +{ + char saveFname[512]; + char ext[16]; + FILE *f; + + ext[0] = 0; + if(state_slot > 0 && state_slot < 10) sprintf(ext, ".%i", state_slot); + strcat(ext, ".mds"); + if(currentConfig.EmuOpt & 8) strcat(ext, ".gz"); + + romfname_ext(saveFname, ext); + if ((f = fopen(saveFname, "rb"))) { + fclose(f); + return 1; + } + return 0; +} + +static void RunEvents(unsigned int which) +{ + if(which & 0x1800) { // save or load (but not both) + int do_it = 1; + if (!(which & 0x1000) && (currentConfig.EmuOpt & 0x200) && check_save_file()) { + unsigned long keys; + blit("", "OVERWRITE SAVE? (Y=yes, X=no)"); + while( !((keys = gp2x_joystick_read(1)) & (GP2X_X|GP2X_Y)) ) + usleep(50*1024); + if (keys & GP2X_X) do_it = 0; + clearArea(0); + } + if (do_it) { + blit("", (which & 0x1000) ? "LOADING GAME" : "SAVING GAME"); + emu_SaveLoadGame(which & 0x1000, 0); + } + + reset_timing = 1; + } + if(which & 0x0400) { // switch renderer + if ( PicoOpt&0x10) { PicoOpt&=~0x10; currentConfig.EmuOpt |= 0x80; } + else if (!(currentConfig.EmuOpt&0x80)) PicoOpt|= 0x10; + else currentConfig.EmuOpt &= ~0x80; + + vidResetMode(); + + if (PicoOpt&0x10) { + strcpy(noticeMsg, " 8bit fast renderer"); + } else if (currentConfig.EmuOpt&0x80) { + strcpy(noticeMsg, "16bit accurate renderer"); + } else { + strcpy(noticeMsg, " 8bit accurate renderer"); + } + + gettimeofday(¬iceMsgTime, 0); + } + if(which & 0x0300) { + if(which&0x0200) { + state_slot -= 1; + if(state_slot < 0) state_slot = 9; + } else { + state_slot += 1; + if(state_slot > 9) state_slot = 0; + } + sprintf(noticeMsg, "SAVE SLOT %i [%s]", state_slot, check_save_file() ? "USED" : "FREE"); + gettimeofday(¬iceMsgTime, 0); + } + if(which & 0x0080) { + engineState = PGS_Menu; + } +} + + +static void updateKeys(void) +{ + unsigned long keys, allActions[2] = { 0, 0 }, events; + static unsigned long prevEvents = 0; + int joy, i; + + keys = gp2x_joystick_read(0); + if (keys & GP2X_SELECT) { + engineState = select_exits ? PGS_Quit : PGS_Menu; + // wait until select is released, so menu would not resume game + while (gp2x_joystick_read(1) & GP2X_SELECT) usleep(50*1000); + } + + keys &= CONFIGURABLE_KEYS; + + for (i = 0; i < 32; i++) + { + if (keys & (1 << i)) { + int pl, acts = currentConfig.KeyBinds[i]; + if (!acts) continue; + pl = (acts >> 16) & 1; + if (combo_keys & (1 << i)) { + int u = i+1, acts_c = acts & combo_acts; + // let's try to find the other one + if (acts_c) + for (; u < 32; u++) + if ( (currentConfig.KeyBinds[u] & acts_c) && (keys & (1 << u)) ) { + allActions[pl] |= acts_c; + keys &= ~((1 << i) | (1 << u)); + break; + } + // add non-combo actions if combo ones were not found + if (!acts_c || u == 32) + allActions[pl] |= acts & ~combo_acts; + } else { + allActions[pl] |= acts; + } + } + } + + // add joy inputs + if (num_of_joys > 0) + { + gp2x_usbjoy_update(); + for (joy = 0; joy < num_of_joys; joy++) { + int keys = gp2x_usbjoy_check2(joy); + for (i = 0; i < 32; i++) { + if (keys & (1 << i)) { + int acts = currentConfig.JoyBinds[joy][i]; + int pl = (acts >> 16) & 1; + allActions[pl] |= acts; + } + } + } + } + + if(movie_data) + { + int offs = frame_count*3 + 0x40; + if (offs+3 > movie_size) { + free(movie_data); + movie_data = 0; + strcpy(noticeMsg, "END OF MOVIE."); + printf("END OF MOVIE.\n"); + gettimeofday(¬iceMsgTime, 0); + } else { + // MXYZ SACB RLDU + PicoPad[0] = ~movie_data[offs] & 0x8f; // ! SCBA RLDU + if(!(movie_data[offs] & 0x10)) PicoPad[0] |= 0x40; // A + if(!(movie_data[offs] & 0x20)) PicoPad[0] |= 0x10; // B + if(!(movie_data[offs] & 0x40)) PicoPad[0] |= 0x20; // A + PicoPad[1] = ~movie_data[offs+1] & 0x8f; // ! SCBA RLDU + if(!(movie_data[offs+1] & 0x10)) PicoPad[1] |= 0x40; // A + if(!(movie_data[offs+1] & 0x20)) PicoPad[1] |= 0x10; // B + if(!(movie_data[offs+1] & 0x40)) PicoPad[1] |= 0x20; // A + PicoPad[0] |= (~movie_data[offs+2] & 0x0A) << 8; // ! MZYX + if(!(movie_data[offs+2] & 0x01)) PicoPad[0] |= 0x0400; // X + if(!(movie_data[offs+2] & 0x04)) PicoPad[0] |= 0x0100; // Z + PicoPad[1] |= (~movie_data[offs+2] & 0xA0) << 4; // ! MZYX + if(!(movie_data[offs+2] & 0x10)) PicoPad[1] |= 0x0400; // X + if(!(movie_data[offs+2] & 0x40)) PicoPad[1] |= 0x0100; // Z + if ((PicoPad[0] & 0x80) || (PicoPad[1] & 0x80)) + printf("%d: start\n", frame_count); + } + } + else + { + PicoPad[0] = (unsigned short) allActions[0]; + PicoPad[1] = (unsigned short) allActions[1]; + } + frame_count++; + + events = (allActions[0] | allActions[1]) >> 16; + + // volume is treated in special way and triggered every frame + if(events & 0x6000) { + int vol = currentConfig.volume; + if (events & 0x2000) { + if (vol < 90) vol++; + } else { + if (vol > 0) vol--; + } + gp2x_sound_volume(vol, vol); + sprintf(noticeMsg, "VOL: %02i", vol); + gettimeofday(¬iceMsgTime, 0); + currentConfig.volume = vol; + } + + events &= ~prevEvents; + if (events) RunEvents(events); + + prevEvents = (allActions[0] | allActions[1]) >> 16; +} + +static int snd_excess_add = 0, snd_excess_cnt = 0; // hack + +static void updateSound(void) +{ + int len = (PicoOpt&8)?PsndLen*2:PsndLen; + + snd_excess_cnt += snd_excess_add; + if (snd_excess_cnt >= 0x10000) { + snd_excess_cnt -= 0x10000; + if (PicoOpt&8) { + PsndOut[len] = PsndOut[len-2]; + PsndOut[len+1] = PsndOut[len-1]; + len+=2; + } else { + PsndOut[len] = PsndOut[len-1]; + len++; + } + } + + gp2x_sound_write(PsndOut, len<<1); +} + + +static void SkipFrame(int do_sound) +{ + void *sndbuff_tmp = 0; + if (PsndOut && !do_sound) { + sndbuff_tmp = PsndOut; + PsndOut = 0; + } + + PicoSkipFrame=1; + PicoFrame(); + PicoSkipFrame=0; + + if (sndbuff_tmp && !do_sound) { + PsndOut = sndbuff_tmp; + } +} + + +static void simpleWait(int thissec, int lim_time) +{ + struct timeval tval; + + spend_cycles(1024); + gettimeofday(&tval, 0); + if(thissec != tval.tv_sec) tval.tv_usec+=1000000; + + while(tval.tv_usec < lim_time) + { + spend_cycles(1024); + gettimeofday(&tval, 0); + if(thissec != tval.tv_sec) tval.tv_usec+=1000000; + } +} + + +void emu_Loop(void) +{ + static int gp2x_old_clock = 200; + static int PsndRate_old = 0, PicoOpt_old = 0, PsndLen_real = 0, pal_old = 0; + char fpsbuff[24]; // fps count c string + struct timeval tval; // timing + int thissec = 0, frames_done = 0, frames_shown = 0, oldmodes = 0; + int target_fps, target_frametime, lim_time, i; + char *notice = 0; + + printf("entered emu_Loop()\n"); + + if (gp2x_old_clock != currentConfig.CPUclock) { + printf("changing clock to %i...", currentConfig.CPUclock); fflush(stdout); + set_FCLK(currentConfig.CPUclock); + gp2x_old_clock = currentConfig.CPUclock; + printf(" done\n"); + } + + if (gp2x_old_gamma != currentConfig.gamma) { + set_gamma(currentConfig.gamma); + gp2x_old_gamma = currentConfig.gamma; + printf("updated gamma to %i\n", currentConfig.gamma); + } + + fpsbuff[0] = 0; + + // make sure we are in correct mode + vidResetMode(); + oldmodes = ((Pico.video.reg[12]&1)<<2) ^ 0xc; + find_combos(); + + // pal/ntsc might have changed, reset related stuff + target_fps = Pico.m.pal ? 50 : 60; + target_frametime = 1000000/target_fps; + reset_timing = 1; + + // prepare sound stuff + if(currentConfig.EmuOpt & 4) { + if(PsndRate != PsndRate_old || (PicoOpt&0x20b) != (PicoOpt_old&0x20b) || Pico.m.pal != pal_old || crashed_940) { + /* if 940 is turned off, we need it to be put back to sleep */ + if (!(PicoOpt&0x200) && ((PicoOpt^PicoOpt_old)&0x200)) { + Reset940(1); + Pause940(1); + } + sound_rerate(); + } + //excess_samples = PsndRate - PsndLen*target_fps; + snd_excess_cnt = 0; + snd_excess_add = ((PsndRate - PsndLen*target_fps)<<16) / target_fps; + printf("starting audio: %i len: %i (ex: %04x) stereo: %i, pal: %i\n", PsndRate, PsndLen, snd_excess_add, (PicoOpt&8)>>3, Pico.m.pal); + gp2x_start_sound(PsndRate, 16, (PicoOpt&8)>>3); + gp2x_sound_volume(currentConfig.volume, currentConfig.volume); + PicoWriteSound = updateSound; + PsndOut = calloc((PicoOpt&8) ? (PsndLen*4+4) : (PsndLen*2+2), 1); + PsndRate_old = PsndRate; + PsndLen_real = PsndLen; + PicoOpt_old = PicoOpt; + pal_old = Pico.m.pal; + } else { + PsndOut = 0; + } + + // loop? + while (engineState == PGS_Running) + { + int modes; + + gettimeofday(&tval, 0); + if(reset_timing) { + reset_timing = 0; + thissec = tval.tv_sec; + frames_shown = frames_done = tval.tv_usec/target_frametime; + } + + // show notice message? + if(noticeMsgTime.tv_sec) { + static int noticeMsgSum; + if((tval.tv_sec*1000000+tval.tv_usec) - (noticeMsgTime.tv_sec*1000000+noticeMsgTime.tv_usec) > 2000000) { // > 2.0 sec + noticeMsgTime.tv_sec = noticeMsgTime.tv_usec = 0; + clearArea(0); + notice = 0; + } else { + int sum = noticeMsg[0]+noticeMsg[1]+noticeMsg[2]; + if (sum != noticeMsgSum) { clearArea(0); noticeMsgSum = sum; } + notice = noticeMsg; + } + } + + // check for mode changes + modes = ((Pico.video.reg[12]&1)<<2)|(Pico.video.reg[1]&8); + if (modes != oldmodes) { + int scalex = 320; + osd_fps_x = OSD_FPS_X; + if (modes & 4) { + vidCpyM2 = vidCpyM2_40col; + } else { + if (PicoOpt & 0x100) { + vidCpyM2 = vidCpyM2_32col_nobord; + scalex = 256; + osd_fps_x = OSD_FPS_X - 64; + } else { + vidCpyM2 = vidCpyM2_32col; + } + } + gp2x_video_RGB_setscaling(scalex, 240); + oldmodes = modes; + clearArea(1); + } + + // second changed? + if(thissec != tval.tv_sec) { +#ifdef BENCHMARK + static int bench = 0, bench_fps = 0, bench_fps_s = 0, bfp = 0, bf[4]; + if(++bench == 10) { + bench = 0; + bench_fps_s = bench_fps; + bf[bfp++ & 3] = bench_fps; + bench_fps = 0; + } + bench_fps += frames_shown; + sprintf(fpsbuff, "%02i/%02i/%02i", frames_shown, bench_fps_s, (bf[0]+bf[1]+bf[2]+bf[3])>>2); +#else + if(currentConfig.EmuOpt & 2) + sprintf(fpsbuff, "%02i/%02i", frames_shown, frames_done); +#endif + thissec = tval.tv_sec; + + if(PsndOut == 0 && currentConfig.Frameskip >= 0) { + frames_done = frames_shown = 0; + } else { + // it is quite common for this implementation to leave 1 fame unfinished + // when second changes, but we don't want buffer to starve. + if(PsndOut && frames_done < target_fps && frames_done > target_fps-5) { + updateKeys(); + SkipFrame(1); frames_done++; + } + + frames_done -= target_fps; if (frames_done < 0) frames_done = 0; + frames_shown -= target_fps; if (frames_shown < 0) frames_shown = 0; + if (frames_shown > frames_done) frames_shown = frames_done; + } + } + + lim_time = (frames_done+1) * target_frametime; + if(currentConfig.Frameskip >= 0) { // frameskip enabled + for(i = 0; i < currentConfig.Frameskip; i++) { + updateKeys(); + SkipFrame(1); frames_done++; + if (PsndOut) { // do framelimitting if sound is enabled + gettimeofday(&tval, 0); + if(thissec != tval.tv_sec) tval.tv_usec+=1000000; + if(tval.tv_usec < lim_time) { // we are too fast + simpleWait(thissec, lim_time); + } + } + lim_time += target_frametime; + } + } else if(tval.tv_usec > lim_time) { // auto frameskip + // no time left for this frame - skip + updateKeys(); + SkipFrame(tval.tv_usec < lim_time+target_frametime); frames_done++; + continue; + } + + updateKeys(); + PicoFrame(); + + // check time + gettimeofday(&tval, 0); + if(thissec != tval.tv_sec) tval.tv_usec+=1000000; + + // sleep if we are still too fast + if(PsndOut != 0 || currentConfig.Frameskip < 0) + { + // usleep sleeps for ~20ms minimum, so it is not a solution here + gettimeofday(&tval, 0); + if(thissec != tval.tv_sec) tval.tv_usec+=1000000; + if(tval.tv_usec < lim_time) + { + // we are too fast + simpleWait(thissec, lim_time); + } + } + + blit(fpsbuff, notice); + + frames_done++; frames_shown++; + } + + // save SRAM + if((currentConfig.EmuOpt & 1) && SRam.changed) { + emu_SaveLoadGame(0, 1); + SRam.changed = 0; + } + + if (PsndOut != 0) { + free(PsndOut); + PsndOut = 0; + } +} + + +void emu_ResetGame(void) +{ + PicoReset(0); + reset_timing = 1; +} + + +size_t gzRead2(void *p, size_t _size, size_t _n, void *file) +{ + return gzread(file, p, _n); +} + + +size_t gzWrite2(void *p, size_t _size, size_t _n, void *file) +{ + return gzwrite(file, p, _n); +} + +typedef unsigned int (*STATE_SL_FUNC)(void *, unsigned int, unsigned int, void *); + +int emu_SaveLoadGame(int load, int sram) +{ + int ret = 0; + char saveFname[512]; + + // make save filename + romfname_ext(saveFname, ""); + if(sram) strcat(saveFname, ".srm"); + else { + if(state_slot > 0 && state_slot < 10) sprintf(saveFname, "%s.%i", saveFname, state_slot); + strcat(saveFname, ".mds"); + } + + printf("saveLoad (%i, %i): %s\n", load, sram, saveFname); + + if(sram) { + FILE *sramFile; + int sram_size = SRam.end-SRam.start+1; + if(SRam.reg_back & 4) sram_size=0x2000; + if(!SRam.data) return 0; // SRam forcefully disabled for this game + if(load) { + sramFile = fopen(saveFname, "rb"); + if(!sramFile) return -1; + fread(SRam.data, 1, sram_size, sramFile); + fclose(sramFile); + } else { + // sram save needs some special processing + // see if we have anything to save + for(; sram_size > 0; sram_size--) + if(SRam.data[sram_size-1]) break; + + if(sram_size) { + sramFile = fopen(saveFname, "wb"); + ret = fwrite(SRam.data, 1, sram_size, sramFile); + ret = (ret != sram_size) ? -1 : 0; + fclose(sramFile); + sync(); + } + } + return ret; + } else { + void *PmovFile = NULL; + // try gzip first + if(currentConfig.EmuOpt & 8) { + strcat(saveFname, ".gz"); + if( (PmovFile = gzopen(saveFname, load ? "rb" : "wb")) ) { + areaRead = gzRead2; + areaWrite = gzWrite2; + if(!load) gzsetparams(PmovFile, 9, Z_DEFAULT_STRATEGY); + } else + saveFname[strlen(saveFname)-3] = 0; + } + if(!PmovFile) { // gzip failed or was disabled + if( (PmovFile = fopen(saveFname, load ? "rb" : "wb")) ) { + areaRead = (STATE_SL_FUNC) fread; + areaWrite = (STATE_SL_FUNC) fwrite; + } + } + if(PmovFile) { + PmovState(load ? 6 : 5, PmovFile); + strcpy(noticeMsg, load ? "GAME LOADED " : "GAME SAVED "); + if(areaRead == gzRead2) + gzclose(PmovFile); + else fclose ((FILE *) PmovFile); + PmovFile = 0; + if (!load) sync(); + else Pico.m.dirtyPal=1; + } else { + strcpy(noticeMsg, load ? "LOAD FAILED " : "SAVE FAILED "); + ret = -1; + } + + gettimeofday(¬iceMsgTime, 0); + return ret; + } +} diff --git a/platform/gp2x/emu.h b/platform/gp2x/emu.h new file mode 100644 index 00000000..33b1ae72 --- /dev/null +++ b/platform/gp2x/emu.h @@ -0,0 +1,46 @@ +// (c) Copyright 2006 notaz, All rights reserved. +// Free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + + + +// engine states +enum TPicoGameState { + PGS_Paused = 1, + PGS_Running, + PGS_Quit, + PGS_KeyConfig, + PGS_ReloadRom, + PGS_Menu, +}; + +typedef struct { + char lastRomFile[512]; + int EmuOpt; // LSb->MSb: use_sram, show_fps, enable_sound, gzip_saves, + // squidgehack, save_cfg_on_exit, , 16_bit_mode + // craigix_ram, confirm_save + int PicoOpt; // used for config saving only, see Pico.h + int PsndRate; // ditto + int PicoRegion; // ditto + int Frameskip; + int CPUclock; + int KeyBinds[32]; + int volume; + int gamma; + int JoyBinds[4][32]; +} currentConfig_t; + +extern char romFileName[]; +extern int engineState; +extern currentConfig_t currentConfig; + + +int emu_ReloadRom(void); +void emu_Init(void); +void emu_Deinit(void); +int emu_SaveLoadGame(int load, int sram); +void emu_Loop(void); +void emu_ResetGame(void); +int emu_ReadConfig(int game); +int emu_WriteConfig(int game); diff --git a/platform/gp2x/gp2x.c b/platform/gp2x/gp2x.c new file mode 100644 index 00000000..84e5f7eb --- /dev/null +++ b/platform/gp2x/gp2x.c @@ -0,0 +1,311 @@ +/** + * All this is mostly based on rlyeh's minimal library. + * Copied here to review all his code and understand what's going on. +**/ + +/* + + GP2X minimal library v0.A by rlyeh, (c) 2005. emulnation.info@rlyeh (swap it!) + + Thanks to Squidge, Robster, snaff, Reesy and NK, for the help & previous work! :-) + + License + ======= + + Free for non-commercial projects (it would be nice receiving a mail from you). + Other cases, ask me first. + + GamePark Holdings is not allowed to use this library and/or use parts from it. + +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gp2x.h" +#include "usbjoy.h" + +volatile unsigned short *gp2x_memregs; +//static +volatile unsigned long *gp2x_memregl; +static void *gp2x_screens[4]; +static int screensel = 0; +//static +int memdev = 0; +static int sounddev = 0, mixerdev = 0; + +void *gp2x_screen; + +#define FRAMEBUFF_ADDR0 0x4000000-640*480 +#define FRAMEBUFF_ADDR1 0x4000000-640*480*2 +#define FRAMEBUFF_ADDR2 0x4000000-640*480*3 +#define FRAMEBUFF_ADDR3 0x4000000-640*480*4 + +static const int gp2x_screenaddrs[] = { FRAMEBUFF_ADDR0, FRAMEBUFF_ADDR1, FRAMEBUFF_ADDR2, FRAMEBUFF_ADDR3 }; + + +/* video stuff */ +void gp2x_video_flip(void) +{ + unsigned int address = gp2x_screenaddrs[screensel&3]; + + /* test */ +/* { + int i; char *p=gp2x_screen; + for (i=0; i < 240; i++) { memset(p+i*320, 0, 32); } + }*/ + + gp2x_memregs[0x290E>>1]=(unsigned short)(address); + gp2x_memregs[0x2910>>1]=(unsigned short)(address >> 16); + gp2x_memregs[0x2912>>1]=(unsigned short)(address); + gp2x_memregs[0x2914>>1]=(unsigned short)(address >> 16); + + // jump to other buffer: + gp2x_screen = gp2x_screens[++screensel&3]; +} + + +void gp2x_video_changemode(int bpp) +{ + gp2x_memregs[0x28DA>>1]=(((bpp+1)/8)<<9)|0xAB; /*8/15/16/24bpp...*/ + gp2x_memregs[0x290C>>1]=320*((bpp+1)/8); /*line width in bytes*/ + + gp2x_memset_all_buffers(0, 0, 640*480); + gp2x_video_flip(); +} + + +void gp2x_video_setpalette(int *pal, int len) +{ + unsigned short *g=(unsigned short *)pal; + volatile unsigned short *memreg = &gp2x_memregs[0x295A>>1]; + gp2x_memregs[0x2958>>1] = 0; + + len *= 2; + while(len--) *memreg=*g++; +} + + +// TV Compatible function // +void gp2x_video_RGB_setscaling(int W, int H) +{ + float escalaw, escalah; + int bpp = (gp2x_memregs[0x28DA>>1]>>9)&0x3; + + escalaw = 1024.0; // RGB Horiz LCD + escalah = 320.0; // RGB Vert LCD + + if(gp2x_memregs[0x2800>>1]&0x100) //TV-Out + { + escalaw=489.0; // RGB Horiz TV (PAL, NTSC) + if (gp2x_memregs[0x2818>>1] == 287) //PAL + escalah=274.0; // RGB Vert TV PAL + else if (gp2x_memregs[0x2818>>1] == 239) //NTSC + escalah=331.0; // RGB Vert TV NTSC + } + + // scale horizontal + gp2x_memregs[0x2906>>1]=(unsigned short)((float)escalaw *(W/320.0)); + // scale vertical + gp2x_memregl[0x2908>>2]=(unsigned long)((float)escalah *bpp *(H/240.0)); +} + + +/* LCD updates @ 80Hz? */ +void gp2x_video_wait_vsync(void) +{ + gp2x_memregs[0x2846>>1] = 0x20|2; //(gp2x_memregs[0x2846>>1] | 0x20) & ~2; + while(!(gp2x_memregs[0x2846>>1] & 2));// usleep(1); +} + + +void gp2x_memcpy_all_buffers(void *data, int offset, int len) +{ + memcpy((char *)gp2x_screens[0] + offset, data, len); + memcpy((char *)gp2x_screens[1] + offset, data, len); + memcpy((char *)gp2x_screens[2] + offset, data, len); + memcpy((char *)gp2x_screens[3] + offset, data, len); +} + + +void gp2x_memset_all_buffers(int offset, int byte, int len) +{ + memset((char *)gp2x_screens[0] + offset, byte, len); + memset((char *)gp2x_screens[1] + offset, byte, len); + memset((char *)gp2x_screens[2] + offset, byte, len); + memset((char *)gp2x_screens[3] + offset, byte, len); +} + + +unsigned long gp2x_joystick_read(int allow_usb_joy) +{ + int i; + unsigned long value=(gp2x_memregs[0x1198>>1] & 0x00FF); + if(value==0xFD) value=0xFA; + if(value==0xF7) value=0xEB; + if(value==0xDF) value=0xAF; + if(value==0x7F) value=0xBE; + value = ~((gp2x_memregs[0x1184>>1] & 0xFF00) | value | (gp2x_memregs[0x1186>>1] << 16)); + + if (allow_usb_joy && num_of_joys > 0) { + // check the usb joy as well.. + gp2x_usbjoy_update(); + for (i = 0; i < num_of_joys; i++) + value |= gp2x_usbjoy_check(i); + } + + return value; +} + +static int s_oldrate = 0, s_oldbits = 0, s_oldstereo = 0; + +void gp2x_start_sound(int rate, int bits, int stereo) +{ + int frag = 0, bsize, buffers; + + // if no settings change, we don't need to do anything + if (rate == s_oldrate && s_oldbits == bits && s_oldstereo == stereo) return; + + if (sounddev > 0) close(sounddev); + sounddev = open("/dev/dsp", O_WRONLY|O_ASYNC); + if (sounddev == -1) + printf("open(\"/dev/dsp\") failed with %i\n", errno); + + ioctl(sounddev, SNDCTL_DSP_SPEED, &rate); + ioctl(sounddev, SNDCTL_DSP_SETFMT, &bits); + ioctl(sounddev, SNDCTL_DSP_STEREO, &stereo); + // calculate buffer size + buffers = 16; + bsize = rate / 32; + if (rate > 22050) { bsize*=4; buffers*=2; } // 44k mode seems to be very demanding + while ((bsize>>=1)) frag++; + frag |= buffers<<16; // 16 buffers + ioctl(sounddev, SNDCTL_DSP_SETFRAGMENT, &frag); + printf("gp2x_set_sound: %i/%ibit/%s, %i buffers of %i bytes\n", + rate, bits, stereo?"stereo":"mono", frag>>16, 1<<(frag&0xffff)); + + s_oldrate = rate; s_oldbits = bits; s_oldstereo = stereo; + usleep(100000); +} + + +void gp2x_sound_write(void *buff, int len) +{ + write(sounddev, buff, len); +} + + +void gp2x_sound_volume(int l, int r) +{ + l=l<0?0:l; l=l>255?255:l; r=r<0?0:r; r=r>255?255:r; + l<<=8; l|=r; + ioctl(mixerdev, SOUND_MIXER_WRITE_PCM, &l); /*SOUND_MIXER_WRITE_VOLUME*/ +} + + +/* 940 */ +void Pause940(int yes) +{ + if(yes) + gp2x_memregs[0x0904>>1] &= 0xFFFE; + else + gp2x_memregs[0x0904>>1] |= 1; +} + + +void Reset940(int yes) +{ + gp2x_memregs[0x3B48>>1] = ((yes&1) << 7) | (0x03); /* bank=3 */ +} + + + +/* common */ +void gp2x_init(void) +{ + printf("entering init()\n"); fflush(stdout); + + memdev = open("/dev/mem", O_RDWR); + if (memdev == -1) + { + printf("open(\"/dev/mem\") failed with %i\n", errno); + exit(1); + } + + gp2x_memregs = mmap(0, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0xc0000000); + printf("memregs are @ %p\n", gp2x_memregs); + if(gp2x_memregs == MAP_FAILED) + { + printf("mmap(memregs) failed with %i\n", errno); + exit(1); + } + gp2x_memregl = (unsigned long *) gp2x_memregs; + + gp2x_screens[3] = mmap(0, 640*480*4, PROT_WRITE, MAP_SHARED, memdev, FRAMEBUFF_ADDR3); + if(gp2x_screens[3] == MAP_FAILED) + { + printf("mmap(gp2x_screen) failed with %i\n", errno); + exit(1); + } + printf("framebuffers point to %p\n", gp2x_screens[3]); + gp2x_screens[2] = (char *) gp2x_screens[3]+640*480; + gp2x_screens[1] = (char *) gp2x_screens[2]+640*480; + gp2x_screens[0] = (char *) gp2x_screens[1]+640*480; + + gp2x_screen = gp2x_screens[0]; + screensel = 0; + + // snd + mixerdev = open("/dev/mixer", O_RDWR); + if (mixerdev == -1) + printf("open(\"/dev/mixer\") failed with %i\n", errno); + + /* init usb joys -GnoStiC */ + gp2x_usbjoy_init(); + + printf("exitting init()\n"); fflush(stdout); +} + +char *ext_menu = 0, *ext_state = 0; + +void gp2x_deinit(void) +{ + Reset940(1); + Pause940(1); + + gp2x_video_changemode(15); + munmap(gp2x_screens[0], 640*480*4); + munmap((void *)gp2x_memregs, 0x10000); + close(memdev); + close(mixerdev); + if (sounddev > 0) close(sounddev); + + gp2x_usbjoy_deinit(); + + printf("all done, running "); + + // Zaq121's alternative frontend support from MAME + if(ext_menu && ext_state) { + printf("%s -state %s\n", ext_menu, ext_state); + execl(ext_menu, ext_menu, "-state", ext_state, NULL); + } else if(ext_menu) { + printf("%s\n", ext_menu); + execl(ext_menu, ext_menu, NULL); + } else { + printf("gp2xmenu\n"); + chdir("/usr/gp2x"); + execl("gp2xmenu", "gp2xmenu", NULL); + } +} + + diff --git a/platform/gp2x/gp2x.h b/platform/gp2x/gp2x.h new file mode 100644 index 00000000..113f674b --- /dev/null +++ b/platform/gp2x/gp2x.h @@ -0,0 +1,40 @@ + +#ifndef __GP2X_H__ +#define __GP2X_H__ + + +void gp2x_init(void); +void gp2x_deinit(void); + +/* video */ +void gp2x_video_flip(void); +void gp2x_video_changemode(int bpp); +void gp2x_video_setpalette(int *pal, int len); +void gp2x_video_RGB_setscaling(int W, int H); +void gp2x_video_wait_vsync(void); +void gp2x_memcpy_all_buffers(void *data, int offset, int len); +void gp2x_memset_all_buffers(int offset, int byte, int len); + +/* sound */ +void gp2x_start_sound(int rate, int bits, int stereo); +void gp2x_sound_write(void *buff, int len); +void gp2x_sound_volume(int l, int r); + +/* joy */ +unsigned long gp2x_joystick_read(int allow_usb_joy); + +/* 940 core */ +void Pause940(int yes); +void Reset940(int yes); + + +extern void *gp2x_screen; +extern int memdev; + + +enum { GP2X_UP=0x1, GP2X_LEFT=0x4, GP2X_DOWN=0x10, GP2X_RIGHT=0x40, + GP2X_START=1<<8, GP2X_SELECT=1<<9, GP2X_L=1<<10, GP2X_R=1<<11, + GP2X_A=1<<12, GP2X_B=1<<13, GP2X_X=1<<14, GP2X_Y=1<<15, + GP2X_VOL_UP=1<<23, GP2X_VOL_DOWN=1<<22, GP2X_PUSH=1<<27 }; + +#endif diff --git a/platform/gp2x/main.c b/platform/gp2x/main.c new file mode 100644 index 00000000..f21ebd78 --- /dev/null +++ b/platform/gp2x/main.c @@ -0,0 +1,143 @@ +// (c) Copyright 2006 notaz, All rights reserved. +// Free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + +#include +#include +#include +#include +#include + +#include "gp2x.h" +#include "menu.h" +#include "emu.h" +#include "version.h" + +#include "squidgehack.h" +#include "cpuctrl.h" + + +extern char *ext_menu, *ext_state; +extern int select_exits; +extern char *PicoConfigFile; +int mmuhack_status = 0; +char **g_argv; + +void parse_cmd_line(int argc, char *argv[]) +{ + int x, unrecognized = 0; + + for(x = 1; x < argc; x++) + { + if(argv[x][0] == '-') + { + if(strcasecmp(argv[x], "-menu") == 0) { + if(x+1 < argc) { ++x; ext_menu = argv[x]; } /* External Frontend: Program Name */ + } + else if(strcasecmp(argv[x], "-state") == 0) { + if(x+1 < argc) { ++x; ext_state = argv[x]; } /* External Frontend: Arguments */ + } + else if(strcasecmp(argv[x], "-config") == 0) { + if(x+1 < argc) { ++x; PicoConfigFile = argv[x]; } + } + else if(strcasecmp(argv[x], "-selectexit") == 0) { + select_exits = 1; + } + else { + unrecognized = 1; + break; + } + } else { + /* External Frontend: ROM Name */ + FILE *f; + strncpy(romFileName, argv[x], PATH_MAX); + romFileName[PATH_MAX-1] = 0; + f = fopen(romFileName, "rb"); + if (f) fclose(f); + else unrecognized = 1; + engineState = PGS_ReloadRom; + break; + } + } + + if (unrecognized) { + printf("\n\n\nPicoDrive v" VERSION " (c) notaz, 2006\n"); + printf("usage: %s [options] [romfile]\n", argv[0]); + printf( "options:\n" + "-menu launch a custom program on exit instead of default gp2xmenu\n" + "-state pass '-state param' to the menu program\n" + "-config use specified config file instead of default 'picoconfig.bin'\n" + " see currentConfig_t structure in emu.h for the file format\n" + "-selectexit pressing SELECT will exit the emu and start 'menu_path'\n"); + } +} + + +int main(int argc, char *argv[]) +{ + g_argv = argv; + + emu_ReadConfig(0); + gp2x_init(); + if (currentConfig.EmuOpt&0x10) { + int ret = mmuhack(); + printf("squidge hack code finished and returned %i\n", ret); fflush(stdout); + mmuhack_status = ret; + } + cpuctrl_init(); + Reset940(1); + Pause940(1); + if (currentConfig.EmuOpt&0x100) { + printf("setting RAM timings.. "); fflush(stdout); + // craigix: --trc 6 --tras 4 --twr 1 --tmrd 1 --trfc 1 --trp 2 --trcd 2 + set_RAM_Timings(6, 4, 1, 1, 1, 2, 2); + printf("done.\n"); fflush(stdout); + } + emu_Init(); + + engineState = PGS_Menu; + + if (argc > 1) + parse_cmd_line(argc, argv); + + for (;;) + { + switch (engineState) + { + case PGS_Menu: + menu_loop(); + break; + + case PGS_ReloadRom: + if (emu_ReloadRom()) + engineState = PGS_Running; + else { + printf("PGS_ReloadRom == 0\n"); + engineState = PGS_Menu; + } + break; + + case PGS_Running: + emu_Loop(); + break; + + case PGS_Quit: + goto endloop; + + default: + printf("engine got into unknown state (%i), exitting\n", engineState); + goto endloop; + } + } + + endloop: + + emu_Deinit(); + cpuctrl_deinit(); + gp2x_deinit(); + if(mmuhack_status) + mmuunhack(); + + return 0; +} diff --git a/platform/gp2x/menu.c b/platform/gp2x/menu.c new file mode 100644 index 00000000..6336126e --- /dev/null +++ b/platform/gp2x/menu.c @@ -0,0 +1,992 @@ +// (c) Copyright 2006 notaz, All rights reserved. +// Free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + +#include +#include +#include +#include +#include +#include + +#include "gp2x.h" +#include "emu.h" +#include "menu.h" +#include "usbjoy.h" +#include "version.h" + +#include "Pico/PicoInt.h" + +#ifndef _DIRENT_HAVE_D_TYPE +#error "need d_type for file browser +#endif + +extern char *actionNames[]; +extern char romFileName[PATH_MAX]; +extern char *rom_data; +extern int mmuhack_status; +extern int state_slot; + +static char *gp2xKeyNames[] = { + "UP", "???", "LEFT", "???", "DOWN", "???", "RIGHT", "???", + "START", "SELECT", "L", "R", "A", "B", "X", "Y", + "???", "???", "???", "???", "???", "???", "VOL DOWN", "VOL UP", + "???", "???", "???", "PUSH", "???", "???", "???", "???" +}; + +char menuErrorMsg[40] = {0, }; + + +static unsigned char fontdata8x8[] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x3C,0x42,0x99,0xBD,0xBD,0x99,0x42,0x3C,0x3C,0x42,0x81,0x81,0x81,0x81,0x42,0x3C, + 0xFE,0x82,0x8A,0xD2,0xA2,0x82,0xFE,0x00,0xFE,0x82,0x82,0x82,0x82,0x82,0xFE,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x64,0x74,0x7C,0x38,0x00,0x00, + 0x80,0xC0,0xF0,0xFC,0xF0,0xC0,0x80,0x00,0x01,0x03,0x0F,0x3F,0x0F,0x03,0x01,0x00, + 0x18,0x3C,0x7E,0x18,0x7E,0x3C,0x18,0x00,0xEE,0xEE,0xEE,0xCC,0x00,0xCC,0xCC,0x00, + 0x00,0x00,0x30,0x68,0x78,0x30,0x00,0x00,0x00,0x38,0x64,0x74,0x7C,0x38,0x00,0x00, + 0x3C,0x66,0x7A,0x7A,0x7E,0x7E,0x3C,0x00,0x0E,0x3E,0x3A,0x22,0x26,0x6E,0xE4,0x40, + 0x18,0x3C,0x7E,0x3C,0x3C,0x3C,0x3C,0x00,0x3C,0x3C,0x3C,0x3C,0x7E,0x3C,0x18,0x00, + 0x08,0x7C,0x7E,0x7E,0x7C,0x08,0x00,0x00,0x10,0x3E,0x7E,0x7E,0x3E,0x10,0x00,0x00, + 0x58,0x2A,0xDC,0xC8,0xDC,0x2A,0x58,0x00,0x24,0x66,0xFF,0xFF,0x66,0x24,0x00,0x00, + 0x00,0x10,0x10,0x38,0x38,0x7C,0xFE,0x00,0xFE,0x7C,0x38,0x38,0x10,0x10,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x1C,0x1C,0x18,0x00,0x18,0x18,0x00, + 0x6C,0x6C,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x7C,0x28,0x7C,0x28,0x00,0x00, + 0x10,0x38,0x60,0x38,0x0C,0x78,0x10,0x00,0x40,0xA4,0x48,0x10,0x24,0x4A,0x04,0x00, + 0x18,0x34,0x18,0x3A,0x6C,0x66,0x3A,0x00,0x18,0x18,0x20,0x00,0x00,0x00,0x00,0x00, + 0x30,0x60,0x60,0x60,0x60,0x60,0x30,0x00,0x0C,0x06,0x06,0x06,0x06,0x06,0x0C,0x00, + 0x10,0x54,0x38,0x7C,0x38,0x54,0x10,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00, + 0x00,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x04,0x08,0x10,0x20,0x40,0x00,0x00, + 0x38,0x4C,0xC6,0xC6,0xC6,0x64,0x38,0x00,0x18,0x38,0x18,0x18,0x18,0x18,0x7E,0x00, + 0x7C,0xC6,0x0E,0x3C,0x78,0xE0,0xFE,0x00,0x7E,0x0C,0x18,0x3C,0x06,0xC6,0x7C,0x00, + 0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x00,0xFC,0xC0,0xFC,0x06,0x06,0xC6,0x7C,0x00, + 0x3C,0x60,0xC0,0xFC,0xC6,0xC6,0x7C,0x00,0xFE,0xC6,0x0C,0x18,0x30,0x30,0x30,0x00, + 0x78,0xC4,0xE4,0x78,0x86,0x86,0x7C,0x00,0x7C,0xC6,0xC6,0x7E,0x06,0x0C,0x78,0x00, + 0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x18,0x18,0x30, + 0x1C,0x38,0x70,0xE0,0x70,0x38,0x1C,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x00, + 0x70,0x38,0x1C,0x0E,0x1C,0x38,0x70,0x00,0x7C,0xC6,0xC6,0x1C,0x18,0x00,0x18,0x00, + 0x3C,0x42,0x99,0xA1,0xA5,0x99,0x42,0x3C,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0x00, + 0xFC,0xC6,0xC6,0xFC,0xC6,0xC6,0xFC,0x00,0x3C,0x66,0xC0,0xC0,0xC0,0x66,0x3C,0x00, + 0xF8,0xCC,0xC6,0xC6,0xC6,0xCC,0xF8,0x00,0xFE,0xC0,0xC0,0xFC,0xC0,0xC0,0xFE,0x00, + 0xFE,0xC0,0xC0,0xFC,0xC0,0xC0,0xC0,0x00,0x3E,0x60,0xC0,0xCE,0xC6,0x66,0x3E,0x00, + 0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x7E,0x18,0x18,0x18,0x18,0x18,0x7E,0x00, + 0x06,0x06,0x06,0x06,0xC6,0xC6,0x7C,0x00,0xC6,0xCC,0xD8,0xF0,0xF8,0xDC,0xCE,0x00, + 0x60,0x60,0x60,0x60,0x60,0x60,0x7E,0x00,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0x00, + 0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00, + 0xFC,0xC6,0xC6,0xC6,0xFC,0xC0,0xC0,0x00,0x7C,0xC6,0xC6,0xC6,0xDE,0xCC,0x7A,0x00, + 0xFC,0xC6,0xC6,0xCE,0xF8,0xDC,0xCE,0x00,0x78,0xCC,0xC0,0x7C,0x06,0xC6,0x7C,0x00, + 0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00, + 0xC6,0xC6,0xC6,0xEE,0x7C,0x38,0x10,0x00,0xC6,0xC6,0xD6,0xFE,0xFE,0xEE,0xC6,0x00, + 0xC6,0xEE,0x3C,0x38,0x7C,0xEE,0xC6,0x00,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x00, + 0xFE,0x0E,0x1C,0x38,0x70,0xE0,0xFE,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00, + 0x60,0x60,0x30,0x18,0x0C,0x06,0x06,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00, + 0x18,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF, + 0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x06,0x3E,0x66,0x66,0x3C,0x00, + 0x60,0x7C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x3C,0x66,0x60,0x60,0x66,0x3C,0x00, + 0x06,0x3E,0x66,0x66,0x66,0x66,0x3E,0x00,0x00,0x3C,0x66,0x66,0x7E,0x60,0x3C,0x00, + 0x1C,0x30,0x78,0x30,0x30,0x30,0x30,0x00,0x00,0x3E,0x66,0x66,0x66,0x3E,0x06,0x3C, + 0x60,0x7C,0x76,0x66,0x66,0x66,0x66,0x00,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x00, + 0x0C,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x38,0x60,0x60,0x66,0x6C,0x78,0x6C,0x66,0x00, + 0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0xEC,0xFE,0xFE,0xFE,0xD6,0xC6,0x00, + 0x00,0x7C,0x76,0x66,0x66,0x66,0x66,0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x00, + 0x00,0x7C,0x66,0x66,0x66,0x7C,0x60,0x60,0x00,0x3E,0x66,0x66,0x66,0x3E,0x06,0x06, + 0x00,0x7E,0x70,0x60,0x60,0x60,0x60,0x00,0x00,0x3C,0x60,0x3C,0x06,0x66,0x3C,0x00, + 0x30,0x78,0x30,0x30,0x30,0x30,0x1C,0x00,0x00,0x66,0x66,0x66,0x66,0x6E,0x3E,0x00, + 0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0xC6,0xD6,0xFE,0xFE,0x7C,0x6C,0x00, + 0x00,0x66,0x3C,0x18,0x3C,0x66,0x66,0x00,0x00,0x66,0x66,0x66,0x66,0x3E,0x06,0x3C, + 0x00,0x7E,0x0C,0x18,0x30,0x60,0x7E,0x00,0x0E,0x18,0x0C,0x38,0x0C,0x18,0x0E,0x00, + 0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x00,0x70,0x18,0x30,0x1C,0x30,0x18,0x70,0x00, + 0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x10,0x28,0x10,0x54,0xAA,0x44,0x00,0x00, +}; + +static void gp2x_text(unsigned char *screen, int x, int y, char *text, int color) +{ + int i,l; + + screen = screen + x + y*320; + + for (i = 0; i < strlen(text); i++) + { + for (l=0;l<8;l++) + { + if(fontdata8x8[((text[i])*8)+l]&0x80) screen[l*320+0]=color; + if(fontdata8x8[((text[i])*8)+l]&0x40) screen[l*320+1]=color; + if(fontdata8x8[((text[i])*8)+l]&0x20) screen[l*320+2]=color; + if(fontdata8x8[((text[i])*8)+l]&0x10) screen[l*320+3]=color; + if(fontdata8x8[((text[i])*8)+l]&0x08) screen[l*320+4]=color; + if(fontdata8x8[((text[i])*8)+l]&0x04) screen[l*320+5]=color; + if(fontdata8x8[((text[i])*8)+l]&0x02) screen[l*320+6]=color; + if(fontdata8x8[((text[i])*8)+l]&0x01) screen[l*320+7]=color; + } + screen += 8; + } +} + +// draws white text to current bbp15 screen +void gp2x_text_out15(int x, int y, char *text) +{ + int i,l; + unsigned short *screen = gp2x_screen; + + screen = screen + x + y*320; + + for (i = 0; i < strlen(text); i++) + { + for (l=0;l<8;l++) + { + if(fontdata8x8[((text[i])*8)+l]&0x80) screen[l*320+0]=0xffff; + if(fontdata8x8[((text[i])*8)+l]&0x40) screen[l*320+1]=0xffff; + if(fontdata8x8[((text[i])*8)+l]&0x20) screen[l*320+2]=0xffff; + if(fontdata8x8[((text[i])*8)+l]&0x10) screen[l*320+3]=0xffff; + if(fontdata8x8[((text[i])*8)+l]&0x08) screen[l*320+4]=0xffff; + if(fontdata8x8[((text[i])*8)+l]&0x04) screen[l*320+5]=0xffff; + if(fontdata8x8[((text[i])*8)+l]&0x02) screen[l*320+6]=0xffff; + if(fontdata8x8[((text[i])*8)+l]&0x01) screen[l*320+7]=0xffff; + } + screen += 8; + } +} + + +void gp2x_text_out8(int x, int y, char *texto, ...) +{ + va_list args; + char buffer[512]; + + va_start(args,texto); + vsprintf(buffer,texto,args); + va_end(args); + + gp2x_text(gp2x_screen,x,y,buffer,1); +} + + +void gp2x_text_out8_2(int x, int y, char *texto, int color) +{ + gp2x_text(gp2x_screen, x, y, texto, color); +} + +void gp2x_text_out8_lim(int x, int y, char *texto, int max) +{ + char buffer[320/8+1]; + + strncpy(buffer, texto, 320/8); + if (max > 320/8) max = 320/8; + if (max < 0) max = 0; + buffer[max] = 0; + + gp2x_text(gp2x_screen,x,y,buffer,1); +} + + +static unsigned long inp_prev = 0; +static int inp_prevjoy = 0; + +static unsigned long wait_for_input(unsigned long interesting) +{ + unsigned long ret; + static int repeats = 0, wait = 300*1000; + int release = 0, i; + + if (repeats == 5 || repeats == 15 || repeats == 30) wait /= 2; + + for (i = 0; i < 6 && inp_prev == gp2x_joystick_read(1); i++) { + if(i == 0) repeats++; + usleep(wait/6); + } + + while ( !((ret = gp2x_joystick_read(1)) & interesting) ) { + usleep(50000); + release = 1; + } + + if (release || ret != inp_prev) { + repeats = 0; + wait = 300*1000; + } + inp_prev = ret; + inp_prevjoy = 0; + + // we don't need diagonals in menus + if ((ret&GP2X_UP) && (ret&GP2X_LEFT)) ret &= ~GP2X_LEFT; + if ((ret&GP2X_UP) && (ret&GP2X_RIGHT)) ret &= ~GP2X_RIGHT; + if ((ret&GP2X_DOWN) && (ret&GP2X_LEFT)) ret &= ~GP2X_LEFT; + if ((ret&GP2X_DOWN) && (ret&GP2X_RIGHT)) ret &= ~GP2X_RIGHT; + + return ret; +} + +static unsigned long input2_read(unsigned long interesting, int *joy) +{ + unsigned long ret; + int i; + + do + { + *joy = 0; + if ((ret = gp2x_joystick_read(0) & interesting)) break; + gp2x_usbjoy_update(); + for (i = 0; i < num_of_joys; i++) { + ret = gp2x_usbjoy_check2(i); + if (ret) { *joy = i + 1; break; } + } + if (ret) break; + } + while(0); + + return ret; +} + +// similar to wait_for_input(), but returns joy num +static unsigned long wait_for_input_usbjoy(unsigned long interesting, int *joy) +{ + unsigned long ret; + const int wait = 300*1000; + int i; + + if (inp_prevjoy == 0) inp_prev &= interesting; + for (i = 0; i < 6; i++) { + ret = input2_read(interesting, joy); + if (*joy != inp_prevjoy || ret != inp_prev) break; + usleep(wait/6); + } + + while ( !(ret = input2_read(interesting, joy)) ) { + usleep(50000); + } + + inp_prev = ret; + inp_prevjoy = *joy; + + return ret; +} + + + +// -------------- ROM selector -------------- + +static void draw_dirlist(char *curdir, struct dirent **namelist, int n, int sel) +{ + int start, i, pos; + + start = 12 - sel; + n--; // exclude current dir (".") + + memset(gp2x_screen, 0, 320*240); + + if(start - 2 >= 0) + gp2x_text_out8_lim(14, (start - 2)*10, curdir, 38); + for (i = 0; i < n; i++) { + pos = start + i; + if (pos < 0) continue; + if (pos > 23) break; + if (namelist[i+1]->d_type == DT_DIR) { + gp2x_text_out8_lim(14, pos*10, "/", 1); + gp2x_text_out8_lim(14+8, pos*10, namelist[i+1]->d_name, 37); + } else { + gp2x_text_out8_lim(14, pos*10, namelist[i+1]->d_name, 38); + } + } + gp2x_text_out8(5, 120, ">"); + gp2x_video_flip(); +} + +static int scandir_cmp(const void *p1, const void *p2) +{ + struct dirent **d1 = (struct dirent **)p1, **d2 = (struct dirent **)p2; + if ((*d1)->d_type == (*d2)->d_type) return alphasort(d1, d2); + if ((*d1)->d_type == DT_DIR) return -1; // put before + if ((*d2)->d_type == DT_DIR) return 1; + return alphasort(d1, d2); +} + + +static char *romsel_loop(char *curr_path) +{ + struct dirent **namelist; + DIR *dir; + int n, sel = 0; + unsigned long inp = 0; + char *ret = NULL, *fname = NULL; + + // is this a dir or a full path? + if ((dir = opendir(curr_path))) { + closedir(dir); + } else { + char *p; + for (p = curr_path + strlen(curr_path) - 1; p > curr_path && *p != '/'; p--); + *p = 0; + fname = p+1; + } + + n = scandir(curr_path, &namelist, 0, scandir_cmp); + if (n < 0) { + // try root + n = scandir(curr_path, &namelist, 0, scandir_cmp); + if (n < 0) { + // oops, we failed + printf("dir: "); printf(curr_path); printf("\n"); + perror("scandir"); + return NULL; + } + } + + // try to find sel + if (fname != NULL) { + int i; + for (i = 1; i < n; i++) { + if (strcmp(namelist[i]->d_name, fname) == 0) { + sel = i - 1; + break; + } + } + } + + for (;;) + { + draw_dirlist(curr_path, namelist, n, sel); + inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_B|GP2X_X); + if(inp & GP2X_UP ) { sel--; if (sel < 0) sel = n-2; } + if(inp & GP2X_DOWN) { sel++; if (sel > n-2) sel = 0; } + if(inp & GP2X_LEFT) { sel-=10; if (sel < 0) sel = 0; } + if(inp & GP2X_RIGHT) { sel+=10; if (sel > n-2) sel = n-2; } + if(inp & GP2X_B) { // enter dir/select + again: + if (namelist[sel+1]->d_type == DT_REG) { + strcpy(romFileName, curr_path); + strcat(romFileName, "/"); + strcat(romFileName, namelist[sel+1]->d_name); + ret = romFileName; + break; + } else if (namelist[sel+1]->d_type == DT_DIR) { + int newlen = strlen(curr_path) + strlen(namelist[sel+1]->d_name) + 2; + char *p, *newdir = malloc(newlen); + if (strcmp(namelist[sel+1]->d_name, "..") == 0) { + char *start = curr_path; + p = start + strlen(start) - 1; + while (*p == '/' && p > start) p--; + while (*p != '/' && p > start) p--; + if (p <= start) strcpy(newdir, "/"); + else { strncpy(newdir, start, p-start); newdir[p-start] = 0; } + } else { + strcpy(newdir, curr_path); + p = newdir + strlen(newdir) - 1; + while (*p == '/' && p >= newdir) *p-- = 0; + strcat(newdir, "/"); + strcat(newdir, namelist[sel+1]->d_name); + } + ret = romsel_loop(newdir); + free(newdir); + break; + } else { + // unknown file type, happens on NTFS mounts. Try to guess. + FILE *tstf; int tmp; + strcpy(romFileName, curr_path); + strcat(romFileName, "/"); + strcat(romFileName, namelist[sel+1]->d_name); + tstf = fopen(romFileName, "rb"); + if (tstf != NULL) + { + if (fread(&tmp, 1, 1, tstf) > 0 || ferror(tstf) == 0) + namelist[sel+1]->d_type = DT_REG; + else namelist[sel+1]->d_type = DT_DIR; + fclose(tstf); + goto again; + } + } + } + if(inp & GP2X_X) break; // cancel + } + + if (n > 0) { + while(n--) free(namelist[n]); + free(namelist); + } + + return ret; +} + +// -------------- key config -------------- + +static char *usb_joy_key_name(int joy, int num) +{ + static char name[16]; + switch (num) + { + case 0: sprintf(name, "Joy%i UP", joy); break; + case 1: sprintf(name, "Joy%i DOWN", joy); break; + case 2: sprintf(name, "Joy%i LEFT", joy); break; + case 3: sprintf(name, "Joy%i RIGHT", joy); break; + default:sprintf(name, "Joy%i b%i", joy, num-3); break; + } + return name; +} + +static void draw_key_config(int curr_act, int is_p2) +{ + char strkeys[32*5]; + int joy, i; + + strkeys[0] = 0; + for (i = 0; i < 32; i++) + { + if (currentConfig.KeyBinds[i] & (1 << curr_act)) + { + if (curr_act < 16 && (currentConfig.KeyBinds[i] & (1 << 16)) != (is_p2 << 16)) continue; + if (strkeys[0]) { strcat(strkeys, " + "); strcat(strkeys, gp2xKeyNames[i]); break; } + else strcpy(strkeys, gp2xKeyNames[i]); + } + } + for (joy = 0; joy < num_of_joys; joy++) + { + for (i = 0; i < 32; i++) + { + if (currentConfig.JoyBinds[joy][i] & (1 << curr_act)) + { + if (curr_act < 16 && (currentConfig.JoyBinds[joy][i] & (1 << 16)) != (is_p2 << 16)) continue; + if (strkeys[0]) { + strcat(strkeys, ", "); strcat(strkeys, usb_joy_key_name(joy + 1, i)); + break; + } + else strcpy(strkeys, usb_joy_key_name(joy + 1, i)); + } + } + } + + memset(gp2x_screen, 0, 320*240); + gp2x_text_out8(60, 40, "Action: %s", actionNames[curr_act]); + gp2x_text_out8(60, 60, "Keys: %s", strkeys); + + gp2x_text_out8(30, 180, "Use SELECT to change action"); + gp2x_text_out8(30, 190, "Press a key to bind/unbind"); + gp2x_text_out8(30, 200, "Select \"Done\" action and"); + gp2x_text_out8(30, 210, " press any key to finish"); + gp2x_video_flip(); +} + +static void key_config_loop(int is_p2) +{ + int curr_act = 0, joy = 0, i; + unsigned long inp = 0; + + for (;;) + { + draw_key_config(curr_act, is_p2); + inp = wait_for_input_usbjoy(CONFIGURABLE_KEYS, &joy); + // printf("got %08lX from joy %i\n", inp, joy); + if (joy == 0) { + if (inp & GP2X_SELECT) { + curr_act++; + while (!actionNames[curr_act] && curr_act < 32) curr_act++; + if (curr_act > 31) curr_act = 0; + } + inp &= CONFIGURABLE_KEYS; + inp &= ~GP2X_SELECT; + } + if (curr_act == 31 && inp) break; + if (joy == 0) { + for (i = 0; i < 32; i++) + if (inp & (1 << i)) { + currentConfig.KeyBinds[i] ^= (1 << curr_act); + if (is_p2) currentConfig.KeyBinds[i] |= (1 << 16); // player 2 flag + else currentConfig.KeyBinds[i] &= ~(1 << 16); + } + } else { + for (i = 0; i < 32; i++) + if (inp & (1 << i)) { + currentConfig.JoyBinds[joy-1][i] ^= (1 << curr_act); + if (is_p2) currentConfig.JoyBinds[joy-1][i] |= (1 << 16); + else currentConfig.JoyBinds[joy-1][i] &= ~(1 << 16); + } + } + } +} + +static void draw_kc_sel(int menu_sel) +{ + int tl_x = 25+40, tl_y = 60, y, i; + char joyname[36]; + + y = tl_y; + memset(gp2x_screen, 0, 320*240); + gp2x_text_out8(tl_x, y, "Player 1"); + gp2x_text_out8(tl_x, (y+=10), "Player 2"); + gp2x_text_out8(tl_x, (y+=10), "Done"); + + // draw cursor + gp2x_text_out8(tl_x - 16, tl_y + menu_sel*10, ">"); + + tl_x = 25; + gp2x_text_out8(tl_x, (y=110), "USB joys detected:"); + if (num_of_joys > 0) { + for (i = 0; i < num_of_joys; i++) { + strncpy(joyname, joy_name(joys[i]), 33); joyname[33] = 0; + gp2x_text_out8(tl_x, (y+=10), "%i: %s", i+1, joyname); + } + } else { + gp2x_text_out8(tl_x, (y+=10), "none"); + } + + + gp2x_video_flip(); +} + +static void kc_sel_loop(void) +{ + int menu_sel = 2, menu_sel_max = 2; + unsigned long inp = 0; + + for(;;) + { + draw_kc_sel(menu_sel); + inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_B|GP2X_X); + if(inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; } + if(inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; } + if(inp & GP2X_B) { + switch (menu_sel) { + case 0: key_config_loop(0); return; + case 1: key_config_loop(1); return; + default: return; + } + } + if(inp & GP2X_X) return; + } +} + + + + +// --------- advanced options ---------- + +// order must match that of currentConfig_t +struct { + int EmuOpt; + int PicoOpt; + int PsndRate; + int PicoRegion; + int Frameskip; + int CPUclock; +} tmp_opts; +int tmp_gamma; + +static void draw_amenu_options(int menu_sel) +{ + int tl_x = 25, tl_y = 60, y; + char *mms = mmuhack_status ? "active) " : "inactive)"; + + y = tl_y; + memset(gp2x_screen, 0, 320*240); + gp2x_text_out8(tl_x, y, "Scale 32 column mode %s", (tmp_opts.PicoOpt&0x100)?"ON":"OFF"); // 0 + gp2x_text_out8(tl_x, (y+=10), "Gamma correction %i.%02i", tmp_gamma / 100, tmp_gamma%100); // 1 + gp2x_text_out8(tl_x, (y+=10), "Emulate Z80 %s", (tmp_opts.PicoOpt&0x004)?"ON":"OFF"); // 2 + gp2x_text_out8(tl_x, (y+=10), "Emulate YM2612 (FM) %s", (tmp_opts.PicoOpt&0x001)?"ON":"OFF"); // 3 + gp2x_text_out8(tl_x, (y+=10), "Emulate SN76496 (PSG) %s", (tmp_opts.PicoOpt&0x002)?"ON":"OFF"); // 4 + gp2x_text_out8(tl_x, (y+=10), "gzip savestates %s", (tmp_opts.EmuOpt &0x008)?"ON":"OFF"); // 5 + gp2x_text_out8(tl_x, (y+=10), "Don't save config on exit %s", (tmp_opts.EmuOpt &0x020)?"ON":"OFF"); // 6 + gp2x_text_out8(tl_x, (y+=10), "needs restart:"); + gp2x_text_out8(tl_x, (y+=10), "craigix's RAM timings %s", (tmp_opts.EmuOpt &0x100)?"ON":"OFF"); // 8 + gp2x_text_out8(tl_x, (y+=10), "squidgehack (now %s %s", mms, (tmp_opts.EmuOpt &0x010)?"ON":"OFF"); // 9 + gp2x_text_out8(tl_x, (y+=10), "Done"); + + // draw cursor + gp2x_text_out8(tl_x - 16, tl_y + menu_sel*10, ">"); + + gp2x_video_flip(); +} + +static void amenu_loop_options(void) +{ + int menu_sel = 0, menu_sel_max = 11; + unsigned long inp = 0; + + for(;;) + { + draw_amenu_options(menu_sel); + inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_B|GP2X_X|GP2X_A); + if(inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; } + if(inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; } + if((inp& GP2X_B)||(inp&GP2X_LEFT)||(inp&GP2X_RIGHT)) { // toggleable options + switch (menu_sel) { + case 0: tmp_opts.PicoOpt^=0x100; break; + case 2: tmp_opts.PicoOpt^=0x004; break; + case 3: tmp_opts.PicoOpt^=0x001; break; + case 4: tmp_opts.PicoOpt^=0x002; break; + case 5: tmp_opts.EmuOpt ^=0x008; break; + case 6: tmp_opts.EmuOpt ^=0x020; break; + case 8: tmp_opts.EmuOpt ^=0x100; break; + case 9: tmp_opts.EmuOpt ^=0x010; break; + case 10: return; + } + } + if(inp & (GP2X_X|GP2X_A)) return; + if(inp & (GP2X_LEFT|GP2X_RIGHT)) { // multi choise + switch (menu_sel) { + case 1: + while ((inp = gp2x_joystick_read(1)) & (GP2X_LEFT|GP2X_RIGHT)) { + tmp_gamma += (inp & GP2X_LEFT) ? -1 : 1; + if (tmp_gamma < 1) tmp_gamma = 1; + if (tmp_gamma > 300) tmp_gamma = 300; + draw_amenu_options(menu_sel); + usleep(18*1000); + } + break; + } + } + } +} + +// -------------- options -------------- + +static char *region_name(unsigned int code) +{ + char *names[] = { "Auto", "Japan NTSC", "Japan PAL", "USA", "Europe" }; + int i = 0; + code <<= 1; + while((code >>=1)) i++; + if (i > 4) return "unknown"; + return names[i]; +} + +static void draw_menu_options(int menu_sel) +{ + int tl_x = 25, tl_y = 40, y; + char monostereo[8], strframeskip[8], *strrend; + + strcpy(monostereo, (tmp_opts.PicoOpt&0x08)?"stereo":"mono"); + if (tmp_opts.Frameskip < 0) + strcpy(strframeskip, "Auto"); + else sprintf(strframeskip, "%i", tmp_opts.Frameskip); + if (tmp_opts.PicoOpt&0x10) { + strrend = " 8bit fast"; + } else if (tmp_opts.EmuOpt&0x80) { + strrend = "16bit accurate"; + } else { + strrend = " 8bit accurate"; + } + + y = tl_y; + memset(gp2x_screen, 0, 320*240); + gp2x_text_out8(tl_x, y, "Renderer: %s", strrend); // 0 + gp2x_text_out8(tl_x, (y+=10), "Accurate timing (slower) %s", (tmp_opts.PicoOpt&0x040)?"ON":"OFF"); // 1 + gp2x_text_out8(tl_x, (y+=10), "Accurate sprites (slower) %s", (tmp_opts.PicoOpt&0x080)?"ON":"OFF"); // 2 + gp2x_text_out8(tl_x, (y+=10), "Show FPS %s", (tmp_opts.EmuOpt &0x002)?"ON":"OFF"); // 3 + gp2x_text_out8(tl_x, (y+=10), "Frameskip %s", strframeskip); + gp2x_text_out8(tl_x, (y+=10), "Enable sound %s", (tmp_opts.EmuOpt &0x004)?"ON":"OFF"); // 5 + gp2x_text_out8(tl_x, (y+=10), "Sound Quality: %5iHz %s", tmp_opts.PsndRate, monostereo); + gp2x_text_out8(tl_x, (y+=10), "Use ARM940 core for sound %s", (tmp_opts.PicoOpt&0x200)?"ON":"OFF"); // 7 + gp2x_text_out8(tl_x, (y+=10), "6 button pad %s", (tmp_opts.PicoOpt&0x020)?"ON":"OFF"); // 8 + gp2x_text_out8(tl_x, (y+=10), "Genesis Region: %s", region_name(tmp_opts.PicoRegion)); + gp2x_text_out8(tl_x, (y+=10), "Use SRAM savestates %s", (tmp_opts.EmuOpt &0x001)?"ON":"OFF"); // 10 + gp2x_text_out8(tl_x, (y+=10), "Confirm save overwrites %s", (tmp_opts.EmuOpt &0x200)?"ON":"OFF"); // 11 + gp2x_text_out8(tl_x, (y+=10), "Save slot %i", state_slot); // 12 + gp2x_text_out8(tl_x, (y+=10), "GP2X CPU clocks %iMhz", tmp_opts.CPUclock); + gp2x_text_out8(tl_x, (y+=10), "[advanced options]"); + gp2x_text_out8(tl_x, (y+=10), "Save cfg as default"); + if (rom_data) + gp2x_text_out8(tl_x, (y+=10), "Save cfg for current game only"); + + // draw cursor + gp2x_text_out8(tl_x - 16, tl_y + menu_sel*10, ">"); + + gp2x_video_flip(); +} + +static int sndrate_prevnext(int rate, int dir) +{ + int i, rates[] = { 8000, 11025, 16000, 22050, 44100 }; + + for (i = 0; i < 5; i++) + if (rates[i] == rate) break; + + i += dir ? 1 : -1; + if (i > 4) return dir ? 44100 : 22050; + if (i < 0) return dir ? 11025 : 8000; + return rates[i]; +} + +static void menu_options_save(void) +{ + memcpy(¤tConfig.EmuOpt, &tmp_opts.EmuOpt, sizeof(tmp_opts)); + currentConfig.gamma = tmp_gamma; + PicoOpt = currentConfig.PicoOpt; + PsndRate = currentConfig.PsndRate; + PicoRegionOverride = currentConfig.PicoRegion; + if (PicoOpt & 0x20) { + actionNames[ 8] = "Z"; actionNames[ 9] = "Y"; + actionNames[10] = "X"; actionNames[11] = "MODE"; + } else { + actionNames[8] = actionNames[9] = actionNames[10] = actionNames[11] = 0; + } +} + +static void menu_loop_options(void) +{ + int menu_sel = 0, menu_sel_max = 15; + unsigned long inp = 0; + + if (rom_data) menu_sel_max++; + memcpy(&tmp_opts.EmuOpt, ¤tConfig.EmuOpt, sizeof(tmp_opts)); + tmp_gamma = currentConfig.gamma; + tmp_opts.PicoOpt = PicoOpt; + tmp_opts.PsndRate = PsndRate; + tmp_opts.PicoRegion = PicoRegionOverride; + + for(;;) + { + draw_menu_options(menu_sel); + inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_B|GP2X_X|GP2X_A); + if(inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; } + if(inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; } + if((inp& GP2X_B)||(inp&GP2X_LEFT)||(inp&GP2X_RIGHT)) { // toggleable options + switch (menu_sel) { + case 1: tmp_opts.PicoOpt^=0x040; break; + case 2: tmp_opts.PicoOpt^=0x080; break; + case 3: tmp_opts.EmuOpt ^=0x002; break; + case 5: tmp_opts.EmuOpt ^=0x004; break; + case 7: tmp_opts.PicoOpt^=0x200; break; + case 8: tmp_opts.PicoOpt^=0x020; break; + case 10: tmp_opts.EmuOpt ^=0x001; break; + case 11: tmp_opts.EmuOpt ^=0x200; break; + case 14: amenu_loop_options(); break; + case 15: // done (save) + menu_options_save(); + emu_WriteConfig(0); + return; + case 16: // done (save for current game) + menu_options_save(); + emu_WriteConfig(1); + return; + } + } + if(inp & GP2X_X) return; // done (no save) + if(inp & GP2X_A) { + menu_options_save(); + return; // done (save) + } + if(inp & (GP2X_LEFT|GP2X_RIGHT)) { // multi choise + switch (menu_sel) { + case 0: + if (inp & GP2X_LEFT) { + if ( tmp_opts.PicoOpt&0x10) tmp_opts.PicoOpt&= ~0x10; + else if (!(tmp_opts.EmuOpt &0x80))tmp_opts.EmuOpt |= 0x80; + else if ( tmp_opts.EmuOpt &0x80) break; + } else { + if ( tmp_opts.PicoOpt&0x10) break; + else if (!(tmp_opts.EmuOpt &0x80))tmp_opts.PicoOpt|= 0x10; + else if ( tmp_opts.EmuOpt &0x80) tmp_opts.EmuOpt &= ~0x80; + } + break; + case 4: + tmp_opts.Frameskip += (inp & GP2X_LEFT) ? -1 : 1; + if (tmp_opts.Frameskip < 0) tmp_opts.Frameskip = -1; + if (tmp_opts.Frameskip > 32) tmp_opts.Frameskip = 32; + break; + case 6: + if ((inp & GP2X_RIGHT) && tmp_opts.PsndRate == 44100 && !(tmp_opts.PicoOpt&0x08)) { + tmp_opts.PsndRate = 8000; tmp_opts.PicoOpt|= 0x08; + } else if ((inp & GP2X_LEFT) && tmp_opts.PsndRate == 8000 && (tmp_opts.PicoOpt&0x08)) { + tmp_opts.PsndRate = 44100; tmp_opts.PicoOpt&=~0x08; + } else tmp_opts.PsndRate = sndrate_prevnext(tmp_opts.PsndRate, inp & GP2X_RIGHT); + break; + case 9: + if (inp & GP2X_RIGHT) { + if (tmp_opts.PicoRegion) tmp_opts.PicoRegion<<=1; else tmp_opts.PicoRegion=1; + if (tmp_opts.PicoRegion > 8) tmp_opts.PicoRegion = 8; + } else tmp_opts.PicoRegion>>=1; + break; + case 12: + if (inp & GP2X_RIGHT) { + state_slot++; if (state_slot > 9) state_slot = 0; + } else {state_slot--; if (state_slot < 0) state_slot = 9; + } + break; + case 13: + while ((inp = gp2x_joystick_read(1)) & (GP2X_LEFT|GP2X_RIGHT)) { + tmp_opts.CPUclock += (inp & GP2X_LEFT) ? -1 : 1; + if (tmp_opts.CPUclock < 1) tmp_opts.CPUclock = 1; + draw_menu_options(menu_sel); + usleep(50*1000); + } + break; + } + } + } +} + +// -------------- credits -------------- + +static void draw_menu_credits(void) +{ + int tl_x = 15, tl_y = 70, y; + memset(gp2x_screen, 0, 320*240); + + gp2x_text_out8(tl_x, 20, "PicoDrive v" VERSION " (c) notaz, 2006"); + y = tl_y; + gp2x_text_out8(tl_x, y, "Credits:"); + gp2x_text_out8(tl_x, (y+=10), "Dave: Cyclone 68000 core,"); + gp2x_text_out8(tl_x, (y+=10), " base code of PicoDrive"); + gp2x_text_out8(tl_x, (y+=10), "Reesy & FluBBa: DrZ80 core"); + gp2x_text_out8(tl_x, (y+=10), "MAME devs: YM2612 and SN76496 cores"); + gp2x_text_out8(tl_x, (y+=10), "Charles MacDonald: Genesis hw docs"); + gp2x_text_out8(tl_x, (y+=10), "Stephane Dallongeville:"); + gp2x_text_out8(tl_x, (y+=10), " opensource Gens"); + gp2x_text_out8(tl_x, (y+=10), "Haze: Genesis hw info"); + gp2x_text_out8(tl_x, (y+=10), "rlyeh and others: minimal SDK"); + gp2x_text_out8(tl_x, (y+=10), "Squidge: squidgehack"); + gp2x_text_out8(tl_x, (y+=10), "Dzz: ARM940 sample"); + gp2x_text_out8(tl_x, (y+=10), "GnoStiC / Puck2099: USB joystick"); + gp2x_text_out8(tl_x, (y+=10), "craigix: GP2X hardware"); + + gp2x_video_flip(); +} + + +// -------------- root menu -------------- + +static void draw_menu_root(int menu_sel) +{ + int tl_x = 70, tl_y = 70, y; + memset(gp2x_screen, 0, 320*240); + + gp2x_text_out8(tl_x, 20, "PicoDrive v" VERSION); + + y = tl_y; + if (rom_data) { + gp2x_text_out8(tl_x, y, "Resume game"); + gp2x_text_out8(tl_x, (y+=10), "Save State"); + gp2x_text_out8(tl_x, (y+=10), "Load State"); + gp2x_text_out8(tl_x, (y+=10), "Reset game"); + } else { + y += 30; + } + gp2x_text_out8(tl_x, (y+=10), "Load new ROM"); + gp2x_text_out8(tl_x, (y+=10), "Change options"); + gp2x_text_out8(tl_x, (y+=10), "Configure controls"); + gp2x_text_out8(tl_x, (y+=10), "Credits"); + gp2x_text_out8(tl_x, (y+=10), "Exit"); + + // draw cursor + gp2x_text_out8(tl_x - 16, tl_y + menu_sel*10, ">"); + // error + if (menuErrorMsg[0]) gp2x_text_out8(5, 226, menuErrorMsg); + gp2x_video_flip(); +} + + +static void menu_loop_root(void) +{ + int menu_sel = 4, menu_sel_max = 8, menu_sel_min = 4; + unsigned long inp = 0; + char curr_path[PATH_MAX], *selfname; + FILE *tstf; + + if ( (tstf = fopen(currentConfig.lastRomFile, "rb")) ) + { + fclose(tstf); + strcpy(curr_path, currentConfig.lastRomFile); + } + else + { + getcwd(curr_path, PATH_MAX); + } + + if (rom_data) menu_sel = menu_sel_min = 0; + + for(;;) + { + draw_menu_root(menu_sel); + inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_B|GP2X_X|GP2X_SELECT); + if(inp & GP2X_UP ) { menu_sel--; if (menu_sel < menu_sel_min) menu_sel = menu_sel_max; } + if(inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = menu_sel_min; } + if(inp &(GP2X_SELECT|GP2X_X)){ + if (rom_data) { + while (gp2x_joystick_read(1) & (GP2X_SELECT|GP2X_X)) usleep(50*1000); // wait until select is released + engineState = PGS_Running; + break; + } + } + if(inp & GP2X_B ) { + switch (menu_sel) { + case 0: // resume game + if (rom_data) { engineState = PGS_Running; return; } + break; + case 1: // save state + if (rom_data) { + if(emu_SaveLoadGame(0, 0)) { + strcpy(menuErrorMsg, "save failed"); + continue; + } + engineState = PGS_Running; + return; + } + break; + case 2: // load state + if (rom_data) { + if(emu_SaveLoadGame(1, 0)) { + strcpy(menuErrorMsg, "load failed"); + continue; + } + engineState = PGS_Running; + return; + } + break; + case 3: // reset game + if (rom_data) { + emu_ResetGame(); + engineState = PGS_Running; + return; + } + break; + case 4: // select rom + selfname = romsel_loop(curr_path); + if (selfname) { + printf("selected file: %s\n", selfname); + strncpy(currentConfig.lastRomFile, selfname, sizeof(currentConfig.lastRomFile)-1); + currentConfig.lastRomFile[sizeof(currentConfig.lastRomFile)-1] = 0; + engineState = PGS_ReloadRom; + } + return; + case 5: // options + menu_loop_options(); + break; + case 6: // controls + kc_sel_loop(); + break; + case 7: // credits + draw_menu_credits(); + usleep(500*1000); + inp = wait_for_input(GP2X_B|GP2X_X); + break; + case 8: // exit + engineState = PGS_Quit; + return; + } + } + menuErrorMsg[0] = 0; // clear error msg + } +} + + +void menu_loop(void) +{ + int pal[2]; + + // switch to 8bpp + gp2x_video_changemode(8); + gp2x_video_RGB_setscaling(320, 240); + // set pal + pal[0] = 0; + pal[1] = 0x00ffffff; + gp2x_video_setpalette(pal, 2); + + menu_loop_root(); + + menuErrorMsg[0] = 0; +} diff --git a/platform/gp2x/menu.h b/platform/gp2x/menu.h new file mode 100644 index 00000000..197500e2 --- /dev/null +++ b/platform/gp2x/menu.h @@ -0,0 +1,16 @@ +// (c) Copyright 2006 notaz, All rights reserved. +// Free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + +extern char menuErrorMsg[40]; + +void gp2x_text_out8 (int x, int y, char *texto, ...); +void gp2x_text_out15 (int x, int y, char *text); +void gp2x_text_out8_2(int x, int y, char *texto, int color); +void menu_loop(void); + +#define CONFIGURABLE_KEYS \ + (GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_A|GP2X_B|GP2X_X|GP2X_Y| \ + GP2X_START|GP2X_SELECT|GP2X_L|GP2X_R|GP2X_PUSH|GP2X_VOL_UP|GP2X_VOL_DOWN) + diff --git a/platform/gp2x/mmuhack.c b/platform/gp2x/mmuhack.c new file mode 100644 index 00000000..c0c21896 --- /dev/null +++ b/platform/gp2x/mmuhack.c @@ -0,0 +1,104 @@ +#include +#include +#include +#include +#include +#include + +#define MMUHACK_MINOR 225 +#define DEVICE_NAME "mmuhack" + +#if __GNUC__ == 3 +#include +static const char __module_kernel_version_gcc3[] __attribute__((__used__)) __attribute__((section(".modinfo"))) = +"kernel_version=" UTS_RELEASE; +#endif + +static ssize_t mmuhack_open(struct inode *inode, struct file *filp) +{ + unsigned int *pgtable; + unsigned int *cpt; + int i, j; + int ttb; + int ret = -EFAULT; + + // get the pointer to the translation table base... + asm volatile( + "stmdb sp!, {r0}\n\t" + "mrc p15, 0, r0, c2, c0, 0\n\t" + "mov %0, r0\n\t" + "ldmia sp!, {r0}\n\t": "=r"(ttb) + ); + + pgtable = __va(ttb); + + for (i = 0; i < 4096; i ++) if ( (pgtable[i] & 3) == 1 ) { + cpt = __va(pgtable[i] & 0xfffffc00); + + for (j = 0; j < 256; j ++) {/* + if ( (cpt[j] & 0xfe00000f) == 0x02000002 ) { + // set C and B bits in upper 32MB memory area... + printk("Set C&B bits %08x\n",cpt[j]); + cpt[j] |= 0xFFC; + ret = 0; + } + */ + if (((cpt[j] & 0xff000000) == 0x02000000) && ((cpt[j] & 12)==0) ) + { + //printk("Set C&B bits %08x\n",cpt[j]); + cpt[j] |= 0xFFC; + } + //if ((a>=0x31 && a<=0x36) && ((cpt[i] & 12)==0)) + if (((cpt[j] & 0xff000000) == 0x03000000) && ((cpt[j] & 12)==0)) + { + //printk("Set C&B bits %08x\n",cpt[j]); + //printf("SDL c and b bits not set, overwriting\n"); + cpt[j] |= 0xFFC; + } + } + } + + // drain the write buffer and flush the tlb caches... + asm volatile( + "stmdb sp!, {r0}\n\t" + "mov r0, #0\n\t" + "mcr 15, 0, r0, cr7, cr10, 4\n\t" + "mcr 15, 0, r0, cr8, cr7, 0\n\t" + "ldmia sp!, {r0}\n\t" + ); + + if (ret == 0) + printk("MMU hack applied.\n"); + + return 0; +} + +static struct file_operations mmuhack_fops = { + owner: THIS_MODULE, + open: mmuhack_open, +}; + + +static struct miscdevice mmuhack = { + MMUHACK_MINOR, DEVICE_NAME, &mmuhack_fops +}; + +static int __init mmuhack_init(void) +{ + misc_register(&mmuhack); +/* + printk("MMSP2 MMU Hack module.\n"); +*/ + return 0; +} + +static void __exit mmuhack_exit(void) +{ + misc_deregister(&mmuhack); +/* + printk(KERN_ALERT "MMU Hack module removed.\n"); +*/ +} + +module_init(mmuhack_init); +module_exit(mmuhack_exit); diff --git a/platform/gp2x/mmuhack.txt b/platform/gp2x/mmuhack.txt new file mode 100644 index 00000000..207e09c4 --- /dev/null +++ b/platform/gp2x/mmuhack.txt @@ -0,0 +1,4 @@ +Squidge's MMU Hack modularized. +Original code by Squidge. +Module by Annonymous? +Slightly modified by me to suit my need. diff --git a/platform/gp2x/port_config.h b/platform/gp2x/port_config.h new file mode 100644 index 00000000..239df01f --- /dev/null +++ b/platform/gp2x/port_config.h @@ -0,0 +1,18 @@ +// port specific settings + +#ifndef PORT_CONFIG_H +#define PORT_CONFIG_H + +#define CPU_CALL + +// draw2.c +#define START_ROW 0 // which row of tiles to start rendering at? +#define END_ROW 28 // ..end + +// pico.c +#define CAN_HANDLE_240_LINES 1 + +//#define dprintf(f,...) printf(f"\n",##__VA_ARGS__) +#define dprintf(x...) + +#endif //PORT_CONFIG_H diff --git a/platform/gp2x/port_config.s b/platform/gp2x/port_config.s new file mode 100644 index 00000000..094ea3c7 --- /dev/null +++ b/platform/gp2x/port_config.s @@ -0,0 +1,8 @@ +@ .equiv START_ROW, 1 +@ .equiv END_ROW, 27 +@ one row means 8 pixels. If above example was used, (27-1)*8=208 lines would be rendered. +.equiv START_ROW, 0 +.equiv END_ROW, 28 + +@ this should be set to one only for GP2X port +.equiv EXTERNAL_YM2612, 1 diff --git a/platform/gp2x/squidgehack.c b/platform/gp2x/squidgehack.c new file mode 100644 index 00000000..f831bd4f --- /dev/null +++ b/platform/gp2x/squidgehack.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include +#include +#include + +extern char **g_argv; + +/* Call this MMU Hack kernel module after doing mmap, and before doing memset*/ +int mmuhack(void) +{ + char kocmd[1024]; + int i, mmufd = open("/dev/mmuhack", O_RDWR); + + if(mmufd < 0) { + strcpy(kocmd, "/sbin/insmod "); + strncpy(kocmd+13, g_argv[0], 1023-13); + kocmd[1023] = 0; + for (i = strlen(kocmd); i > 0; i--) + if (kocmd[i] == '/') { kocmd[i] = 0; break; } + strcat(kocmd, "/mmuhack.o"); + + printf("Installing NK's kernel module for Squidge MMU Hack (%s)...\n", kocmd); + system(kocmd); + mmufd = open("/dev/mmuhack", O_RDWR); + } + if(mmufd < 0) return 0; + + close(mmufd); + return 1; +} + + +/* Unload MMU Hack kernel module after closing all memory devices*/ +int mmuunhack(void) +{ + int ret; + printf("Removing NK's kernel module for Squidge MMU Hack... "); fflush(stdout); + ret = system("/sbin/rmmod mmuhack"); + printf("done (%i)\n", ret); + + return ret; +} diff --git a/platform/gp2x/squidgehack.h b/platform/gp2x/squidgehack.h new file mode 100644 index 00000000..a83c737a --- /dev/null +++ b/platform/gp2x/squidgehack.h @@ -0,0 +1,7 @@ +#ifndef __MMUHACK__ +#define __MMUHACK__ + +extern int mmuhack(void); +extern int mmuunhack(void); + +#endif /* __MMUHACK__ */ diff --git a/platform/gp2x/test.c b/platform/gp2x/test.c new file mode 100644 index 00000000..c0d28cb8 --- /dev/null +++ b/platform/gp2x/test.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include "gp2x.h" + +void spend_cycles(int c); + +int main(void) +{ + struct timeval tval; // timing + int thissec = 0, frames_done = 0; + + gp2x_init(); + + for (;;) + { + gettimeofday(&tval, 0); + + if(thissec != tval.tv_sec) + { + thissec = tval.tv_sec; + + printf("frames_done: %i\n", frames_done); + frames_done = 0; + } + + + //gp2x_video_wait_vsync(); + //usleep(1); // sleeps a minimum of ~20ms + //gp2x_video_flip(); // can be called ~430000 times/sec + spend_cycles(1000); + frames_done++; + } + +} + diff --git a/platform/gp2x/uClibc/README b/platform/gp2x/uClibc/README new file mode 100644 index 00000000..2c69a54a --- /dev/null +++ b/platform/gp2x/uClibc/README @@ -0,0 +1,16 @@ +The routines included in this math library are derived from the +math library for Apple's MacOS X/Darwin math library, which was +itself swiped from FreeBSD. The original copyright information +is as follows: + + Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + + Developed at SunPro, a Sun Microsystems, Inc. business. + Permission to use, copy, modify, and distribute this + software is freely granted, provided that this notice + is preserved. + +It has been ported to work with uClibc and generally behave +by Erik Andersen + 22 May, 2001 + diff --git a/platform/gp2x/uClibc/e_log.c b/platform/gp2x/uClibc/e_log.c new file mode 100644 index 00000000..0464014c --- /dev/null +++ b/platform/gp2x/uClibc/e_log.c @@ -0,0 +1,147 @@ +/* @(#)e_log.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#if defined(LIBM_SCCS) && !defined(lint) +static char rcsid[] = "$NetBSD: e_log.c,v 1.8 1995/05/10 20:45:49 jtc Exp $"; +#endif + +/* __ieee754_log(x) + * Return the logrithm of x + * + * Method : + * 1. Argument Reduction: find k and f such that + * x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * 2. Approximation of log(1+f). + * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) + * = 2s + 2/3 s**3 + 2/5 s**5 + ....., + * = 2s + s*R + * We use a special Reme algorithm on [0,0.1716] to generate + * a polynomial of degree 14 to approximate R The maximum error + * of this polynomial approximation is bounded by 2**-58.45. In + * other words, + * 2 4 6 8 10 12 14 + * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s + * (the values of Lg1 to Lg7 are listed in the program) + * and + * | 2 14 | -58.45 + * | Lg1*s +...+Lg7*s - R(z) | <= 2 + * | | + * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. + * In order to guarantee error in log below 1ulp, we compute log + * by + * log(1+f) = f - s*(f - R) (if f is not too large) + * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) + * + * 3. Finally, log(x) = k*ln2 + log(1+f). + * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) + * Here ln2 is split into two floating point number: + * ln2_hi + ln2_lo, + * where n*ln2_hi is always exact for |n| < 2000. + * + * Special cases: + * log(x) is NaN with signal if x < 0 (including -INF) ; + * log(+INF) is +INF; log(0) is -INF with signal; + * log(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "math.h" +#include "math_private.h" + +#ifdef __STDC__ +static const double +#else +static double +#endif +ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */ +ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */ +two54 = 1.80143985094819840000e+16, /* 43500000 00000000 */ +Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ +Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ +Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ +Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ +Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ +Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ +Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +#ifdef __STDC__ +static const double zero = 0.0; +#else +static double zero = 0.0; +#endif + +#ifdef __STDC__ + double __ieee754_log(double x) +#else + double __ieee754_log(x) + double x; +#endif +{ + double hfsq,f,s,z,R,w,t1,t2,dk; + int32_t k,hx,i,j; + u_int32_t lx; + + EXTRACT_WORDS(hx,lx,x); + + k=0; + if (hx < 0x00100000) { /* x < 2**-1022 */ + if (((hx&0x7fffffff)|lx)==0) + return -two54/zero; /* log(+-0)=-inf */ + if (hx<0) return (x-x)/zero; /* log(-#) = NaN */ + k -= 54; x *= two54; /* subnormal number, scale up x */ + GET_HIGH_WORD(hx,x); + } + if (hx >= 0x7ff00000) return x+x; + k += (hx>>20)-1023; + hx &= 0x000fffff; + i = (hx+0x95f64)&0x100000; + SET_HIGH_WORD(x,hx|(i^0x3ff00000)); /* normalize x or x/2 */ + k += (i>>20); + f = x-1.0; + if((0x000fffff&(2+hx))<3) { /* |f| < 2**-20 */ + if(f==zero) {if(k==0) return zero; else {dk=(double)k; + return dk*ln2_hi+dk*ln2_lo;} + } + R = f*f*(0.5-0.33333333333333333*f); + if(k==0) return f-R; else {dk=(double)k; + return dk*ln2_hi-((R-dk*ln2_lo)-f);} + } + s = f/(2.0+f); + dk = (double)k; + z = s*s; + i = hx-0x6147a; + w = z*z; + j = 0x6b851-hx; + t1= w*(Lg2+w*(Lg4+w*Lg6)); + t2= z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); + i |= j; + R = t2+t1; + if(i>0) { + hfsq=0.5*f*f; + if(k==0) return f-(hfsq-s*(hfsq+R)); else + return dk*ln2_hi-((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f); + } else { + if(k==0) return f-s*(f-R); else + return dk*ln2_hi-((s*(f-R)-dk*ln2_lo)-f); + } +} diff --git a/platform/gp2x/uClibc/e_pow.c b/platform/gp2x/uClibc/e_pow.c new file mode 100644 index 00000000..b970775c --- /dev/null +++ b/platform/gp2x/uClibc/e_pow.c @@ -0,0 +1,308 @@ +/* @(#)e_pow.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#if defined(LIBM_SCCS) && !defined(lint) +static char rcsid[] = "$NetBSD: e_pow.c,v 1.9 1995/05/12 04:57:32 jtc Exp $"; +#endif + +/* __ieee754_pow(x,y) return x**y + * + * n + * Method: Let x = 2 * (1+f) + * 1. Compute and return log2(x) in two pieces: + * log2(x) = w1 + w2, + * where w1 has 53-24 = 29 bit trailing zeros. + * 2. Perform y*log2(x) = n+y' by simulating muti-precision + * arithmetic, where |y'|<=0.5. + * 3. Return x**y = 2**n*exp(y'*log2) + * + * Special cases: + * 1. (anything) ** 0 is 1 + * 2. (anything) ** 1 is itself + * 3. (anything) ** NAN is NAN + * 4. NAN ** (anything except 0) is NAN + * 5. +-(|x| > 1) ** +INF is +INF + * 6. +-(|x| > 1) ** -INF is +0 + * 7. +-(|x| < 1) ** +INF is +0 + * 8. +-(|x| < 1) ** -INF is +INF + * 9. +-1 ** +-INF is NAN + * 10. +0 ** (+anything except 0, NAN) is +0 + * 11. -0 ** (+anything except 0, NAN, odd integer) is +0 + * 12. +0 ** (-anything except 0, NAN) is +INF + * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF + * 14. -0 ** (odd integer) = -( +0 ** (odd integer) ) + * 15. +INF ** (+anything except 0,NAN) is +INF + * 16. +INF ** (-anything except 0,NAN) is +0 + * 17. -INF ** (anything) = -0 ** (-anything) + * 18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) + * 19. (-anything except 0 and inf) ** (non-integer) is NAN + * + * Accuracy: + * pow(x,y) returns x**y nearly rounded. In particular + * pow(integer,integer) + * always returns the correct integer provided it is + * representable. + * + * Constants : + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "math.h" +#include "math_private.h" + +#ifdef __STDC__ +static const double +#else +static double +#endif +bp[] = {1.0, 1.5,}, +dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */ +dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */ +zero = 0.0, +one = 1.0, +two = 2.0, +two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */ +huge = 1.0e300, +tiny = 1.0e-300, + /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ +L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */ +L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */ +L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */ +L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */ +L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */ +L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */ +P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ +P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ +P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ +P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ +P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */ +lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */ +lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */ +lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */ +ovt = 8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */ +cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */ +cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */ +cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/ +ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */ +ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/ +ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/ + +#ifdef __STDC__ + double __ieee754_pow(double x, double y) +#else + double __ieee754_pow(x,y) + double x, y; +#endif +{ + double z,ax,z_h,z_l,p_h,p_l; + double y1,t1,t2,r,s,t,u,v,w; + int32_t i,j,k,yisint,n; + int32_t hx,hy,ix,iy; + u_int32_t lx,ly; + + EXTRACT_WORDS(hx,lx,x); + EXTRACT_WORDS(hy,ly,y); + ix = hx&0x7fffffff; iy = hy&0x7fffffff; + + /* y==zero: x**0 = 1 */ + if((iy|ly)==0) return one; + + /* +-NaN return x+y */ + if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) || + iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0))) + return x+y; + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if(hx<0) { + if(iy>=0x43400000) yisint = 2; /* even integer y */ + else if(iy>=0x3ff00000) { + k = (iy>>20)-0x3ff; /* exponent */ + if(k>20) { + j = ly>>(52-k); + if((j<<(52-k))==ly) yisint = 2-(j&1); + } else if(ly==0) { + j = iy>>(20-k); + if((j<<(20-k))==iy) yisint = 2-(j&1); + } + } + } + + /* special value of y */ + if(ly==0) { + if (iy==0x7ff00000) { /* y is +-inf */ + if(((ix-0x3ff00000)|lx)==0) + return y - y; /* inf**+-1 is NaN */ + else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */ + return (hy>=0)? y: zero; + else /* (|x|<1)**-,+inf = inf,0 */ + return (hy<0)?-y: zero; + } + if(iy==0x3ff00000) { /* y is +-1 */ + if(hy<0) return one/x; else return x; + } + if(hy==0x40000000) return x*x; /* y is 2 */ + if(hy==0x3fe00000) { /* y is 0.5 */ + if(hx>=0) /* x >= +0 */ + return __ieee754_sqrt(x); + } + } + + ax = fabs(x); + /* special value of x */ + if(lx==0) { + if(ix==0x7ff00000||ix==0||ix==0x3ff00000){ + z = ax; /*x is +-0,+-inf,+-1*/ + if(hy<0) z = one/z; /* z = (1/|x|) */ + if(hx<0) { + if(((ix-0x3ff00000)|yisint)==0) { + z = (z-z)/(z-z); /* (-1)**non-int is NaN */ + } else if(yisint==1) + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + return z; + } + } + + /* (x<0)**(non-int) is NaN */ + if(((((u_int32_t)hx>>31)-1)|yisint)==0) return (x-x)/(x-x); + + /* |y| is huge */ + if(iy>0x41e00000) { /* if |y| > 2**31 */ + if(iy>0x43f00000){ /* if |y| > 2**64, must o/uflow */ + if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny; + if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny; + } + /* over/underflow if x is not close to one */ + if(ix<0x3fefffff) return (hy<0)? huge*huge:tiny*tiny; + if(ix>0x3ff00000) return (hy>0)? huge*huge:tiny*tiny; + /* now |1-x| is tiny <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = x-1; /* t has 20 trailing zeros */ + w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25)); + u = ivln2_h*t; /* ivln2_h has 21 sig. bits */ + v = t*ivln2_l-w*ivln2; + t1 = u+v; + SET_LOW_WORD(t1,0); + t2 = v-(t1-u); + } else { + double s2,s_h,s_l,t_h,t_l; + n = 0; + /* take care subnormal number */ + if(ix<0x00100000) + {ax *= two53; n -= 53; GET_HIGH_WORD(ix,ax); } + n += ((ix)>>20)-0x3ff; + j = ix&0x000fffff; + /* determine interval */ + ix = j|0x3ff00000; /* normalize ix */ + if(j<=0x3988E) k=0; /* |x|>1)|0x20000000)+0x00080000+(k<<18)); + t_l = ax - (t_h-bp[k]); + s_l = v*((u-s_h*t_h)-s_h*t_l); + /* compute log(ax) */ + s2 = s*s; + r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6))))); + r += s_l*(s_h+s); + s2 = s_h*s_h; + t_h = 3.0+s2+r; + SET_LOW_WORD(t_h,0); + t_l = r-((t_h-3.0)-s2); + /* u+v = s*(1+...) */ + u = s_h*t_h; + v = s_l*t_h+t_l*s; + /* 2/(3log2)*(s+...) */ + p_h = u+v; + SET_LOW_WORD(p_h,0); + p_l = v-(p_h-u); + z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = cp_l*p_h+p_l*cp+dp_l[k]; + /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = (double)n; + t1 = (((z_h+z_l)+dp_h[k])+t); + SET_LOW_WORD(t1,0); + t2 = z_l-(((t1-t)-dp_h[k])-z_h); + } + + s = one; /* s (sign of result -ve**odd) = -1 else = 1 */ + if(((((u_int32_t)hx>>31)-1)|(yisint-1))==0) + s = -one;/* (-ve)**(odd int) */ + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + y1 = y; + SET_LOW_WORD(y1,0); + p_l = (y-y1)*t1+y*t2; + p_h = y1*t1; + z = p_l+p_h; + EXTRACT_WORDS(j,i,z); + if (j>=0x40900000) { /* z >= 1024 */ + if(((j-0x40900000)|i)!=0) /* if z > 1024 */ + return s*huge*huge; /* overflow */ + else { + if(p_l+ovt>z-p_h) return s*huge*huge; /* overflow */ + } + } else if((j&0x7fffffff)>=0x4090cc00 ) { /* z <= -1075 */ + if(((j-0xc090cc00)|i)!=0) /* z < -1075 */ + return s*tiny*tiny; /* underflow */ + else { + if(p_l<=z-p_h) return s*tiny*tiny; /* underflow */ + } + } + /* + * compute 2**(p_h+p_l) + */ + i = j&0x7fffffff; + k = (i>>20)-0x3ff; + n = 0; + if(i>0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */ + n = j+(0x00100000>>(k+1)); + k = ((n&0x7fffffff)>>20)-0x3ff; /* new k for n */ + t = zero; + SET_HIGH_WORD(t,n&~(0x000fffff>>k)); + n = ((n&0x000fffff)|0x00100000)>>(20-k); + if(j<0) n = -n; + p_h -= t; + } + t = p_l+p_h; + SET_LOW_WORD(t,0); + u = t*lg2_h; + v = (p_l-(t-p_h))*lg2+t*lg2_l; + z = u+v; + w = v-(z-u); + t = z*z; + t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); + r = (z*t1)/(t1-two)-(w+z*w); + z = one-(r-z); + GET_HIGH_WORD(j,z); + j += (n<<20); + if((j>>20)<=0) z = scalbn(z,n); /* subnormal output */ + else SET_HIGH_WORD(z,j); + return s*z; +} diff --git a/platform/gp2x/uClibc/e_rem_pio2.c b/platform/gp2x/uClibc/e_rem_pio2.c new file mode 100644 index 00000000..3dd7f7b4 --- /dev/null +++ b/platform/gp2x/uClibc/e_rem_pio2.c @@ -0,0 +1,183 @@ +/* @(#)e_rem_pio2.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#if defined(LIBM_SCCS) && !defined(lint) +static char rcsid[] = "$NetBSD: e_rem_pio2.c,v 1.8 1995/05/10 20:46:02 jtc Exp $"; +#endif + +/* __ieee754_rem_pio2(x,y) + * + * return the remainder of x rem pi/2 in y[0]+y[1] + * use __kernel_rem_pio2() + */ + +#include "math.h" +#include "math_private.h" + +/* + * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi + */ +#ifdef __STDC__ +static const int32_t two_over_pi[] = { +#else +static int32_t two_over_pi[] = { +#endif +0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, +0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, +0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, +0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, +0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, +0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, +0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, +0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, +0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, +0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, +0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, +}; + +#ifdef __STDC__ +static const int32_t npio2_hw[] = { +#else +static int32_t npio2_hw[] = { +#endif +0x3FF921FB, 0x400921FB, 0x4012D97C, 0x401921FB, 0x401F6A7A, 0x4022D97C, +0x4025FDBB, 0x402921FB, 0x402C463A, 0x402F6A7A, 0x4031475C, 0x4032D97C, +0x40346B9C, 0x4035FDBB, 0x40378FDB, 0x403921FB, 0x403AB41B, 0x403C463A, +0x403DD85A, 0x403F6A7A, 0x40407E4C, 0x4041475C, 0x4042106C, 0x4042D97C, +0x4043A28C, 0x40446B9C, 0x404534AC, 0x4045FDBB, 0x4046C6CB, 0x40478FDB, +0x404858EB, 0x404921FB, +}; + +/* + * invpio2: 53 bits of 2/pi + * pio2_1: first 33 bit of pi/2 + * pio2_1t: pi/2 - pio2_1 + * pio2_2: second 33 bit of pi/2 + * pio2_2t: pi/2 - (pio2_1+pio2_2) + * pio2_3: third 33 bit of pi/2 + * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3) + */ + +#ifdef __STDC__ +static const double +#else +static double +#endif +zero = 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ +half = 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */ +two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */ +invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ +pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */ +pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */ +pio2_2 = 6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */ +pio2_2t = 2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */ +pio2_3 = 2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */ +pio2_3t = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ + +#ifdef __STDC__ + int32_t __ieee754_rem_pio2(double x, double *y) +#else + int32_t __ieee754_rem_pio2(x,y) + double x,y[]; +#endif +{ + double z=0.0,w,t,r,fn; + double tx[3]; + int32_t e0,i,j,nx,n,ix,hx; + u_int32_t low; + + GET_HIGH_WORD(hx,x); /* high word of x */ + ix = hx&0x7fffffff; + if(ix<=0x3fe921fb) /* |x| ~<= pi/4 , no need for reduction */ + {y[0] = x; y[1] = 0; return 0;} + if(ix<0x4002d97c) { /* |x| < 3pi/4, special case with n=+-1 */ + if(hx>0) { + z = x - pio2_1; + if(ix!=0x3ff921fb) { /* 33+53 bit pi is good enough */ + y[0] = z - pio2_1t; + y[1] = (z-y[0])-pio2_1t; + } else { /* near pi/2, use 33+33+53 bit pi */ + z -= pio2_2; + y[0] = z - pio2_2t; + y[1] = (z-y[0])-pio2_2t; + } + return 1; + } else { /* negative x */ + z = x + pio2_1; + if(ix!=0x3ff921fb) { /* 33+53 bit pi is good enough */ + y[0] = z + pio2_1t; + y[1] = (z-y[0])+pio2_1t; + } else { /* near pi/2, use 33+33+53 bit pi */ + z += pio2_2; + y[0] = z + pio2_2t; + y[1] = (z-y[0])+pio2_2t; + } + return -1; + } + } + if(ix<=0x413921fb) { /* |x| ~<= 2^19*(pi/2), medium size */ + t = fabs(x); + n = (int32_t) (t*invpio2+half); + fn = (double)n; + r = t-fn*pio2_1; + w = fn*pio2_1t; /* 1st round good to 85 bit */ + if(n<32&&ix!=npio2_hw[n-1]) { + y[0] = r-w; /* quick check no cancellation */ + } else { + u_int32_t high; + j = ix>>20; + y[0] = r-w; + GET_HIGH_WORD(high,y[0]); + i = j-((high>>20)&0x7ff); + if(i>16) { /* 2nd iteration needed, good to 118 */ + t = r; + w = fn*pio2_2; + r = t-w; + w = fn*pio2_2t-((t-r)-w); + y[0] = r-w; + GET_HIGH_WORD(high,y[0]); + i = j-((high>>20)&0x7ff); + if(i>49) { /* 3rd iteration need, 151 bits acc */ + t = r; /* will cover all possible cases */ + w = fn*pio2_3; + r = t-w; + w = fn*pio2_3t-((t-r)-w); + y[0] = r-w; + } + } + } + y[1] = (r-y[0])-w; + if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;} + else return n; + } + /* + * all other (large) arguments + */ + if(ix>=0x7ff00000) { /* x is inf or NaN */ + y[0]=y[1]=x-x; return 0; + } + /* set z = scalbn(|x|,ilogb(x)-23) */ + GET_LOW_WORD(low,x); + SET_LOW_WORD(z,low); + e0 = (ix>>20)-1046; /* e0 = ilogb(z)-23; */ + SET_HIGH_WORD(z, ix - ((int32_t)(e0<<20))); + for(i=0;i<2;i++) { + tx[i] = (double)((int32_t)(z)); + z = (z-tx[i])*two24; + } + tx[2] = z; + nx = 3; + while(tx[nx-1]==zero) nx--; /* skip zero term */ + n = __kernel_rem_pio2(tx,y,e0,nx,2,two_over_pi); + if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;} + return n; +} diff --git a/platform/gp2x/uClibc/e_sqrt.c b/platform/gp2x/uClibc/e_sqrt.c new file mode 100644 index 00000000..fae52c84 --- /dev/null +++ b/platform/gp2x/uClibc/e_sqrt.c @@ -0,0 +1,453 @@ +/* @(#)e_sqrt.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#if defined(LIBM_SCCS) && !defined(lint) +static char rcsid[] = "$NetBSD: e_sqrt.c,v 1.8 1995/05/10 20:46:17 jtc Exp $"; +#endif + +/* __ieee754_sqrt(x) + * Return correctly rounded sqrt. + * ------------------------------------------ + * | Use the hardware sqrt if you have one | + * ------------------------------------------ + * Method: + * Bit by bit method using integer arithmetic. (Slow, but portable) + * 1. Normalization + * Scale x to y in [1,4) with even powers of 2: + * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then + * sqrt(x) = 2^k * sqrt(y) + * 2. Bit by bit computation + * Let q = sqrt(y) truncated to i bit after binary point (q = 1), + * i 0 + * i+1 2 + * s = 2*q , and y = 2 * ( y - q ). (1) + * i i i i + * + * To compute q from q , one checks whether + * i+1 i + * + * -(i+1) 2 + * (q + 2 ) <= y. (2) + * i + * -(i+1) + * If (2) is false, then q = q ; otherwise q = q + 2 . + * i+1 i i+1 i + * + * With some algebric manipulation, it is not difficult to see + * that (2) is equivalent to + * -(i+1) + * s + 2 <= y (3) + * i i + * + * The advantage of (3) is that s and y can be computed by + * i i + * the following recurrence formula: + * if (3) is false + * + * s = s , y = y ; (4) + * i+1 i i+1 i + * + * otherwise, + * -i -(i+1) + * s = s + 2 , y = y - s - 2 (5) + * i+1 i i+1 i i + * + * One may easily use induction to prove (4) and (5). + * Note. Since the left hand side of (3) contain only i+2 bits, + * it does not necessary to do a full (53-bit) comparison + * in (3). + * 3. Final rounding + * After generating the 53 bits result, we compute one more bit. + * Together with the remainder, we can decide whether the + * result is exact, bigger than 1/2ulp, or less than 1/2ulp + * (it will never equal to 1/2ulp). + * The rounding mode can be detected by checking whether + * huge + tiny is equal to huge, and whether huge - tiny is + * equal to huge for some floating point number "huge" and "tiny". + * + * Special cases: + * sqrt(+-0) = +-0 ... exact + * sqrt(inf) = inf + * sqrt(-ve) = NaN ... with invalid signal + * sqrt(NaN) = NaN ... with invalid signal for signaling NaN + * + * Other methods : see the appended file at the end of the program below. + *--------------- + */ + +#include "math.h" +#include "math_private.h" + +#ifdef __STDC__ +static const double one = 1.0, tiny=1.0e-300; +#else +static double one = 1.0, tiny=1.0e-300; +#endif + +#ifdef __STDC__ + double __ieee754_sqrt(double x) +#else + double __ieee754_sqrt(x) + double x; +#endif +{ + double z; + int32_t sign = (int)0x80000000; + int32_t ix0,s0,q,m,t,i; + u_int32_t r,t1,s1,ix1,q1; + + EXTRACT_WORDS(ix0,ix1,x); + + /* take care of Inf and NaN */ + if((ix0&0x7ff00000)==0x7ff00000) { + return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf + sqrt(-inf)=sNaN */ + } + /* take care of zero */ + if(ix0<=0) { + if(((ix0&(~sign))|ix1)==0) return x;/* sqrt(+-0) = +-0 */ + else if(ix0<0) + return (x-x)/(x-x); /* sqrt(-ve) = sNaN */ + } + /* normalize x */ + m = (ix0>>20); + if(m==0) { /* subnormal x */ + while(ix0==0) { + m -= 21; + ix0 |= (ix1>>11); ix1 <<= 21; + } + for(i=0;(ix0&0x00100000)==0;i++) ix0<<=1; + m -= i-1; + ix0 |= (ix1>>(32-i)); + ix1 <<= i; + } + m -= 1023; /* unbias exponent */ + ix0 = (ix0&0x000fffff)|0x00100000; + if(m&1){ /* odd m, double x to make it even */ + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + } + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */ + r = 0x00200000; /* r = moving bit from right to left */ + + while(r!=0) { + t = s0+r; + if(t<=ix0) { + s0 = t+r; + ix0 -= t; + q += r; + } + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + r>>=1; + } + + r = sign; + while(r!=0) { + t1 = s1+r; + t = s0; + if((t>31); + ix1 += ix1; + r>>=1; + } + + /* use floating add to find out rounding direction */ + if((ix0|ix1)!=0) { + z = one-tiny; /* trigger inexact flag */ + if (z>=one) { + z = one+tiny; + if (q1==(u_int32_t)0xffffffff) { q1=0; q += 1;} + else if (z>one) { + if (q1==(u_int32_t)0xfffffffe) q+=1; + q1+=2; + } else + q1 += (q1&1); + } + } + ix0 = (q>>1)+0x3fe00000; + ix1 = q1>>1; + if ((q&1)==1) ix1 |= sign; + ix0 += (m <<20); + INSERT_WORDS(z,ix0,ix1); + return z; +} + +/* +Other methods (use floating-point arithmetic) +------------- +(This is a copy of a drafted paper by Prof W. Kahan +and K.C. Ng, written in May, 1986) + + Two algorithms are given here to implement sqrt(x) + (IEEE double precision arithmetic) in software. + Both supply sqrt(x) correctly rounded. The first algorithm (in + Section A) uses newton iterations and involves four divisions. + The second one uses reciproot iterations to avoid division, but + requires more multiplications. Both algorithms need the ability + to chop results of arithmetic operations instead of round them, + and the INEXACT flag to indicate when an arithmetic operation + is executed exactly with no roundoff error, all part of the + standard (IEEE 754-1985). The ability to perform shift, add, + subtract and logical AND operations upon 32-bit words is needed + too, though not part of the standard. + +A. sqrt(x) by Newton Iteration + + (1) Initial approximation + + Let x0 and x1 be the leading and the trailing 32-bit words of + a floating point number x (in IEEE double format) respectively + + 1 11 52 ...widths + ------------------------------------------------------ + x: |s| e | f | + ------------------------------------------------------ + msb lsb msb lsb ...order + + + ------------------------ ------------------------ + x0: |s| e | f1 | x1: | f2 | + ------------------------ ------------------------ + + By performing shifts and subtracts on x0 and x1 (both regarded + as integers), we obtain an 8-bit approximation of sqrt(x) as + follows. + + k := (x0>>1) + 0x1ff80000; + y0 := k - T1[31&(k>>15)]. ... y ~ sqrt(x) to 8 bits + Here k is a 32-bit integer and T1[] is an integer array containing + correction terms. Now magically the floating value of y (y's + leading 32-bit word is y0, the value of its trailing word is 0) + approximates sqrt(x) to almost 8-bit. + + Value of T1: + static int T1[32]= { + 0, 1024, 3062, 5746, 9193, 13348, 18162, 23592, + 29598, 36145, 43202, 50740, 58733, 67158, 75992, 85215, + 83599, 71378, 60428, 50647, 41945, 34246, 27478, 21581, + 16499, 12183, 8588, 5674, 3403, 1742, 661, 130,}; + + (2) Iterative refinement + + Apply Heron's rule three times to y, we have y approximates + sqrt(x) to within 1 ulp (Unit in the Last Place): + + y := (y+x/y)/2 ... almost 17 sig. bits + y := (y+x/y)/2 ... almost 35 sig. bits + y := y-(y-x/y)/2 ... within 1 ulp + + + Remark 1. + Another way to improve y to within 1 ulp is: + + y := (y+x/y) ... almost 17 sig. bits to 2*sqrt(x) + y := y - 0x00100006 ... almost 18 sig. bits to sqrt(x) + + 2 + (x-y )*y + y := y + 2* ---------- ...within 1 ulp + 2 + 3y + x + + + This formula has one division fewer than the one above; however, + it requires more multiplications and additions. Also x must be + scaled in advance to avoid spurious overflow in evaluating the + expression 3y*y+x. Hence it is not recommended uless division + is slow. If division is very slow, then one should use the + reciproot algorithm given in section B. + + (3) Final adjustment + + By twiddling y's last bit it is possible to force y to be + correctly rounded according to the prevailing rounding mode + as follows. Let r and i be copies of the rounding mode and + inexact flag before entering the square root program. Also we + use the expression y+-ulp for the next representable floating + numbers (up and down) of y. Note that y+-ulp = either fixed + point y+-1, or multiply y by nextafter(1,+-inf) in chopped + mode. + + I := FALSE; ... reset INEXACT flag I + R := RZ; ... set rounding mode to round-toward-zero + z := x/y; ... chopped quotient, possibly inexact + If(not I) then { ... if the quotient is exact + if(z=y) { + I := i; ... restore inexact flag + R := r; ... restore rounded mode + return sqrt(x):=y. + } else { + z := z - ulp; ... special rounding + } + } + i := TRUE; ... sqrt(x) is inexact + If (r=RN) then z=z+ulp ... rounded-to-nearest + If (r=RP) then { ... round-toward-+inf + y = y+ulp; z=z+ulp; + } + y := y+z; ... chopped sum + y0:=y0-0x00100000; ... y := y/2 is correctly rounded. + I := i; ... restore inexact flag + R := r; ... restore rounded mode + return sqrt(x):=y. + + (4) Special cases + + Square root of +inf, +-0, or NaN is itself; + Square root of a negative number is NaN with invalid signal. + + +B. sqrt(x) by Reciproot Iteration + + (1) Initial approximation + + Let x0 and x1 be the leading and the trailing 32-bit words of + a floating point number x (in IEEE double format) respectively + (see section A). By performing shifs and subtracts on x0 and y0, + we obtain a 7.8-bit approximation of 1/sqrt(x) as follows. + + k := 0x5fe80000 - (x0>>1); + y0:= k - T2[63&(k>>14)]. ... y ~ 1/sqrt(x) to 7.8 bits + + Here k is a 32-bit integer and T2[] is an integer array + containing correction terms. Now magically the floating + value of y (y's leading 32-bit word is y0, the value of + its trailing word y1 is set to zero) approximates 1/sqrt(x) + to almost 7.8-bit. + + Value of T2: + static int T2[64]= { + 0x1500, 0x2ef8, 0x4d67, 0x6b02, 0x87be, 0xa395, 0xbe7a, 0xd866, + 0xf14a, 0x1091b,0x11fcd,0x13552,0x14999,0x15c98,0x16e34,0x17e5f, + 0x18d03,0x19a01,0x1a545,0x1ae8a,0x1b5c4,0x1bb01,0x1bfde,0x1c28d, + 0x1c2de,0x1c0db,0x1ba73,0x1b11c,0x1a4b5,0x1953d,0x18266,0x16be0, + 0x1683e,0x179d8,0x18a4d,0x19992,0x1a789,0x1b445,0x1bf61,0x1c989, + 0x1d16d,0x1d77b,0x1dddf,0x1e2ad,0x1e5bf,0x1e6e8,0x1e654,0x1e3cd, + 0x1df2a,0x1d635,0x1cb16,0x1be2c,0x1ae4e,0x19bde,0x1868e,0x16e2e, + 0x1527f,0x1334a,0x11051,0xe951, 0xbe01, 0x8e0d, 0x5924, 0x1edd,}; + + (2) Iterative refinement + + Apply Reciproot iteration three times to y and multiply the + result by x to get an approximation z that matches sqrt(x) + to about 1 ulp. To be exact, we will have + -1ulp < sqrt(x)-z<1.0625ulp. + + ... set rounding mode to Round-to-nearest + y := y*(1.5-0.5*x*y*y) ... almost 15 sig. bits to 1/sqrt(x) + y := y*((1.5-2^-30)+0.5*x*y*y)... about 29 sig. bits to 1/sqrt(x) + ... special arrangement for better accuracy + z := x*y ... 29 bits to sqrt(x), with z*y<1 + z := z + 0.5*z*(1-z*y) ... about 1 ulp to sqrt(x) + + Remark 2. The constant 1.5-2^-30 is chosen to bias the error so that + (a) the term z*y in the final iteration is always less than 1; + (b) the error in the final result is biased upward so that + -1 ulp < sqrt(x) - z < 1.0625 ulp + instead of |sqrt(x)-z|<1.03125ulp. + + (3) Final adjustment + + By twiddling y's last bit it is possible to force y to be + correctly rounded according to the prevailing rounding mode + as follows. Let r and i be copies of the rounding mode and + inexact flag before entering the square root program. Also we + use the expression y+-ulp for the next representable floating + numbers (up and down) of y. Note that y+-ulp = either fixed + point y+-1, or multiply y by nextafter(1,+-inf) in chopped + mode. + + R := RZ; ... set rounding mode to round-toward-zero + switch(r) { + case RN: ... round-to-nearest + if(x<= z*(z-ulp)...chopped) z = z - ulp; else + if(x<= z*(z+ulp)...chopped) z = z; else z = z+ulp; + break; + case RZ:case RM: ... round-to-zero or round-to--inf + R:=RP; ... reset rounding mod to round-to-+inf + if(x=(z+ulp)*(z+ulp) ...rounded up) z = z+ulp; + break; + case RP: ... round-to-+inf + if(x>(z+ulp)*(z+ulp)...chopped) z = z+2*ulp; else + if(x>z*z ...chopped) z = z+ulp; + break; + } + + Remark 3. The above comparisons can be done in fixed point. For + example, to compare x and w=z*z chopped, it suffices to compare + x1 and w1 (the trailing parts of x and w), regarding them as + two's complement integers. + + ...Is z an exact square root? + To determine whether z is an exact square root of x, let z1 be the + trailing part of z, and also let x0 and x1 be the leading and + trailing parts of x. + + If ((z1&0x03ffffff)!=0) ... not exact if trailing 26 bits of z!=0 + I := 1; ... Raise Inexact flag: z is not exact + else { + j := 1 - [(x0>>20)&1] ... j = logb(x) mod 2 + k := z1 >> 26; ... get z's 25-th and 26-th + fraction bits + I := i or (k&j) or ((k&(j+j+1))!=(x1&3)); + } + R:= r ... restore rounded mode + return sqrt(x):=z. + + If multiplication is cheaper then the foregoing red tape, the + Inexact flag can be evaluated by + + I := i; + I := (z*z!=x) or I. + + Note that z*z can overwrite I; this value must be sensed if it is + True. + + Remark 4. If z*z = x exactly, then bit 25 to bit 0 of z1 must be + zero. + + -------------------- + z1: | f2 | + -------------------- + bit 31 bit 0 + + Further more, bit 27 and 26 of z1, bit 0 and 1 of x1, and the odd + or even of logb(x) have the following relations: + + ------------------------------------------------- + bit 27,26 of z1 bit 1,0 of x1 logb(x) + ------------------------------------------------- + 00 00 odd and even + 01 01 even + 10 10 odd + 10 00 even + 11 01 even + ------------------------------------------------- + + (4) Special cases (see (4) of Section A). + + */ + diff --git a/platform/gp2x/uClibc/k_cos.c b/platform/gp2x/uClibc/k_cos.c new file mode 100644 index 00000000..03c208aa --- /dev/null +++ b/platform/gp2x/uClibc/k_cos.c @@ -0,0 +1,96 @@ +/* @(#)k_cos.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#if defined(LIBM_SCCS) && !defined(lint) +static char rcsid[] = "$NetBSD: k_cos.c,v 1.8 1995/05/10 20:46:22 jtc Exp $"; +#endif + +/* + * __kernel_cos( x, y ) + * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * + * Algorithm + * 1. Since cos(-x) = cos(x), we need only to consider positive x. + * 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. + * 3. cos(x) is approximated by a polynomial of degree 14 on + * [0,pi/4] + * 4 14 + * cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x + * where the remez error is + * + * | 2 4 6 8 10 12 14 | -58 + * |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 + * | | + * + * 4 6 8 10 12 14 + * 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then + * cos(x) = 1 - x*x/2 + r + * since cos(x+y) ~ cos(x) - sin(x)*y + * ~ cos(x) - x*y, + * a correction term is necessary in cos(x) and hence + * cos(x+y) = 1 - (x*x/2 - (r - x*y)) + * For better accuracy when x > 0.3, let qx = |x|/4 with + * the last 32 bits mask off, and if x > 0.78125, let qx = 0.28125. + * Then + * cos(x+y) = (1-qx) - ((x*x/2-qx) - (r-x*y)). + * Note that 1-qx and (x*x/2-qx) is EXACT here, and the + * magnitude of the latter is at least a quarter of x*x/2, + * thus, reducing the rounding error in the subtraction. + */ + +#include "math.h" +#include "math_private.h" + +#ifdef __STDC__ +static const double +#else +static double +#endif +one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ +C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */ +C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */ +C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */ +C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */ +C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */ +C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ + +#ifdef __STDC__ + double __kernel_cos(double x, double y) +#else + double __kernel_cos(x, y) + double x,y; +#endif +{ + double a,hz,z,r,qx; + int32_t ix; + GET_HIGH_WORD(ix,x); + ix &= 0x7fffffff; /* ix = |x|'s high word*/ + if(ix<0x3e400000) { /* if x < 2**27 */ + if(((int)x)==0) return one; /* generate inexact */ + } + z = x*x; + r = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6))))); + if(ix < 0x3FD33333) /* if |x| < 0.3 */ + return one - (0.5*z - (z*r - x*y)); + else { + if(ix > 0x3fe90000) { /* x > 0.78125 */ + qx = 0.28125; + } else { + INSERT_WORDS(qx,ix-0x00200000,0); /* x/4 */ + } + hz = 0.5*z-qx; + a = one-qx; + return a - (hz - (z*r-x*y)); + } +} diff --git a/platform/gp2x/uClibc/k_rem_pio2.c b/platform/gp2x/uClibc/k_rem_pio2.c new file mode 100644 index 00000000..9113d876 --- /dev/null +++ b/platform/gp2x/uClibc/k_rem_pio2.c @@ -0,0 +1,320 @@ +/* @(#)k_rem_pio2.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#if defined(LIBM_SCCS) && !defined(lint) +static char rcsid[] = "$NetBSD: k_rem_pio2.c,v 1.7 1995/05/10 20:46:25 jtc Exp $"; +#endif + +/* + * __kernel_rem_pio2(x,y,e0,nx,prec,ipio2) + * double x[],y[]; int e0,nx,prec; int ipio2[]; + * + * __kernel_rem_pio2 return the last three digits of N with + * y = x - N*pi/2 + * so that |y| < pi/2. + * + * The method is to compute the integer (mod 8) and fraction parts of + * (2/pi)*x without doing the full multiplication. In general we + * skip the part of the product that are known to be a huge integer ( + * more accurately, = 0 mod 8 ). Thus the number of operations are + * independent of the exponent of the input. + * + * (2/pi) is represented by an array of 24-bit integers in ipio2[]. + * + * Input parameters: + * x[] The input value (must be positive) is broken into nx + * pieces of 24-bit integers in double precision format. + * x[i] will be the i-th 24 bit of x. The scaled exponent + * of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 + * match x's up to 24 bits. + * + * Example of breaking a double positive z into x[0]+x[1]+x[2]: + * e0 = ilogb(z)-23 + * z = scalbn(z,-e0) + * for i = 0,1,2 + * x[i] = floor(z) + * z = (z-x[i])*2**24 + * + * + * y[] ouput result in an array of double precision numbers. + * The dimension of y[] is: + * 24-bit precision 1 + * 53-bit precision 2 + * 64-bit precision 2 + * 113-bit precision 3 + * The actual value is the sum of them. Thus for 113-bit + * precison, one may have to do something like: + * + * long double t,w,r_head, r_tail; + * t = (long double)y[2] + (long double)y[1]; + * w = (long double)y[0]; + * r_head = t+w; + * r_tail = w - (r_head - t); + * + * e0 The exponent of x[0] + * + * nx dimension of x[] + * + * prec an integer indicating the precision: + * 0 24 bits (single) + * 1 53 bits (double) + * 2 64 bits (extended) + * 3 113 bits (quad) + * + * ipio2[] + * integer array, contains the (24*i)-th to (24*i+23)-th + * bit of 2/pi after binary point. The corresponding + * floating value is + * + * ipio2[i] * 2^(-24(i+1)). + * + * External function: + * double scalbn(), floor(); + * + * + * Here is the description of some local variables: + * + * jk jk+1 is the initial number of terms of ipio2[] needed + * in the computation. The recommended value is 2,3,4, + * 6 for single, double, extended,and quad. + * + * jz local integer variable indicating the number of + * terms of ipio2[] used. + * + * jx nx - 1 + * + * jv index for pointing to the suitable ipio2[] for the + * computation. In general, we want + * ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 + * is an integer. Thus + * e0-3-24*jv >= 0 or (e0-3)/24 >= jv + * Hence jv = max(0,(e0-3)/24). + * + * jp jp+1 is the number of terms in PIo2[] needed, jp = jk. + * + * q[] double array with integral value, representing the + * 24-bits chunk of the product of x and 2/pi. + * + * q0 the corresponding exponent of q[0]. Note that the + * exponent for q[i] would be q0-24*i. + * + * PIo2[] double precision array, obtained by cutting pi/2 + * into 24 bits chunks. + * + * f[] ipio2[] in floating point + * + * iq[] integer array by breaking up q[] in 24-bits chunk. + * + * fq[] final product of x*(2/pi) in fq[0],..,fq[jk] + * + * ih integer. If >0 it indicates q[] is >= 0.5, hence + * it also indicates the *sign* of the result. + * + */ + + +/* + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "math.h" +#include "math_private.h" + +#ifdef __STDC__ +static const int init_jk[] = {2,3,4,6}; /* initial value for jk */ +#else +static int init_jk[] = {2,3,4,6}; +#endif + +#ifdef __STDC__ +static const double PIo2[] = { +#else +static double PIo2[] = { +#endif + 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ + 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ + 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ + 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ + 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ + 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ + 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ + 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ +}; + +#ifdef __STDC__ +static const double +#else +static double +#endif +zero = 0.0, +one = 1.0, +two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */ +twon24 = 5.96046447753906250000e-08; /* 0x3E700000, 0x00000000 */ + +#ifdef __STDC__ + int __kernel_rem_pio2(double *x, double *y, int e0, int nx, int prec, const int32_t *ipio2) +#else + int __kernel_rem_pio2(x,y,e0,nx,prec,ipio2) + double x[], y[]; int e0,nx,prec; int32_t ipio2[]; +#endif +{ + int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih; + double z,fw,f[20],fq[20],q[20]; + + /* initialize jk*/ + jk = init_jk[prec]; + jp = jk; + + /* determine jx,jv,q0, note that 3>q0 */ + jx = nx-1; + jv = (e0-3)/24; if(jv<0) jv=0; + q0 = e0-24*(jv+1); + + /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ + j = jv-jx; m = jx+jk; + for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (double) ipio2[j]; + + /* compute q[0],q[1],...q[jk] */ + for (i=0;i<=jk;i++) { + for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw; + } + + jz = jk; +recompute: + /* distill q[] into iq[] reversingly */ + for(i=0,j=jz,z=q[jz];j>0;i++,j--) { + fw = (double)((int32_t)(twon24* z)); + iq[i] = (int32_t)(z-two24*fw); + z = q[j-1]+fw; + } + + /* compute n */ + z = scalbn(z,q0); /* actual value of z */ + z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */ + n = (int32_t) z; + z -= (double)n; + ih = 0; + if(q0>0) { /* need iq[jz-1] to determine n */ + i = (iq[jz-1]>>(24-q0)); n += i; + iq[jz-1] -= i<<(24-q0); + ih = iq[jz-1]>>(23-q0); + } + else if(q0==0) ih = iq[jz-1]>>23; + else if(z>=0.5) ih=2; + + if(ih>0) { /* q > 0.5 */ + n += 1; carry = 0; + for(i=0;i0) { /* rare case: chance is 1 in 12 */ + switch(q0) { + case 1: + iq[jz-1] &= 0x7fffff; break; + case 2: + iq[jz-1] &= 0x3fffff; break; + } + } + if(ih==2) { + z = one - z; + if(carry!=0) z -= scalbn(one,q0); + } + } + + /* check if recomputation is needed */ + if(z==zero) { + j = 0; + for (i=jz-1;i>=jk;i--) j |= iq[i]; + if(j==0) { /* need recomputation */ + for(k=1;iq[jk-k]==0;k++); /* k = no. of terms needed */ + + for(i=jz+1;i<=jz+k;i++) { /* add q[jz+1] to q[jz+k] */ + f[jx+i] = (double) ipio2[jv+i]; + for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; + q[i] = fw; + } + jz += k; + goto recompute; + } + } + + /* chop off zero terms */ + if(z==0.0) { + jz -= 1; q0 -= 24; + while(iq[jz]==0) { jz--; q0-=24;} + } else { /* break z into 24-bit if necessary */ + z = scalbn(z,-q0); + if(z>=two24) { + fw = (double)((int32_t)(twon24*z)); + iq[jz] = (int32_t)(z-two24*fw); + jz += 1; q0 += 24; + iq[jz] = (int32_t) fw; + } else iq[jz] = (int32_t) z ; + } + + /* convert integer "bit" chunk to floating-point value */ + fw = scalbn(one,q0); + for(i=jz;i>=0;i--) { + q[i] = fw*(double)iq[i]; fw*=twon24; + } + + /* compute PIo2[0,...,jp]*q[jz,...,0] */ + for(i=jz;i>=0;i--) { + for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k]; + fq[jz-i] = fw; + } + + /* compress fq[] into y[] */ + switch(prec) { + case 0: + fw = 0.0; + for (i=jz;i>=0;i--) fw += fq[i]; + y[0] = (ih==0)? fw: -fw; + break; + case 1: + case 2: + fw = 0.0; + for (i=jz;i>=0;i--) fw += fq[i]; + y[0] = (ih==0)? fw: -fw; + fw = fq[0]-fw; + for (i=1;i<=jz;i++) fw += fq[i]; + y[1] = (ih==0)? fw: -fw; + break; + case 3: /* painful */ + for (i=jz;i>0;i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (i=jz;i>1;i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (fw=0.0,i=jz;i>=2;i--) fw += fq[i]; + if(ih==0) { + y[0] = fq[0]; y[1] = fq[1]; y[2] = fw; + } else { + y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw; + } + } + return n&7; +} diff --git a/platform/gp2x/uClibc/k_sin.c b/platform/gp2x/uClibc/k_sin.c new file mode 100644 index 00000000..5bfc1d68 --- /dev/null +++ b/platform/gp2x/uClibc/k_sin.c @@ -0,0 +1,79 @@ +/* @(#)k_sin.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#if defined(LIBM_SCCS) && !defined(lint) +static char rcsid[] = "$NetBSD: k_sin.c,v 1.8 1995/05/10 20:46:31 jtc Exp $"; +#endif + +/* __kernel_sin( x, y, iy) + * kernel sin function on [-pi/4, pi/4], pi/4 ~ 0.7854 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * Input iy indicates whether y is 0. (if iy=0, y assume to be 0). + * + * Algorithm + * 1. Since sin(-x) = -sin(x), we need only to consider positive x. + * 2. if x < 2^-27 (hx<0x3e400000 0), return x with inexact if x!=0. + * 3. sin(x) is approximated by a polynomial of degree 13 on + * [0,pi/4] + * 3 13 + * sin(x) ~ x + S1*x + ... + S6*x + * where + * + * |sin(x) 2 4 6 8 10 12 | -58 + * |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 + * | x | + * + * 4. sin(x+y) = sin(x) + sin'(x')*y + * ~ sin(x) + (1-x*x/2)*y + * For better accuracy, let + * 3 2 2 2 2 + * r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) + * then 3 2 + * sin(x) = x + (S1*x + (x *(r-y/2)+y)) + */ + +#include "math.h" +#include "math_private.h" + +#ifdef __STDC__ +static const double +#else +static double +#endif +half = 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */ +S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */ +S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */ +S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */ +S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */ +S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */ +S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ + +#ifdef __STDC__ + double __kernel_sin(double x, double y, int iy) +#else + double __kernel_sin(x, y, iy) + double x,y; int iy; /* iy=0 if y is zero */ +#endif +{ + double z,r,v; + int32_t ix; + GET_HIGH_WORD(ix,x); + ix &= 0x7fffffff; /* high word of x */ + if(ix<0x3e400000) /* |x| < 2**-27 */ + {if((int)x==0) return x;} /* generate inexact */ + z = x*x; + v = z*x; + r = S2+z*(S3+z*(S4+z*(S5+z*S6))); + if(iy==0) return x+v*(S1+z*r); + else return x-((z*(half*y-v*r)-y)-v*S1); +} diff --git a/platform/gp2x/uClibc/math.h b/platform/gp2x/uClibc/math.h new file mode 100644 index 00000000..b82fa0f0 --- /dev/null +++ b/platform/gp2x/uClibc/math.h @@ -0,0 +1,15 @@ +#include + +int __kernel_rem_pio2(double *x, double *y, int e0, int nx, int prec, const int32_t *ipio2); +double __kernel_sin(double x, double y, int iy); +double __kernel_cos(double x, double y); + +double __ieee754_pow(double x, double y); +double __ieee754_sqrt(double x); +double __ieee754_log(double x); +int32_t __ieee754_rem_pio2(double x, double *y); + +double fabs(double x); +double scalbn(double x, int n); +double copysign(double x, double y); +double floor(double x); diff --git a/platform/gp2x/uClibc/math_private.h b/platform/gp2x/uClibc/math_private.h new file mode 100644 index 00000000..134b3352 --- /dev/null +++ b/platform/gp2x/uClibc/math_private.h @@ -0,0 +1,129 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * from: @(#)fdlibm.h 5.1 93/09/24 + * $Id: math_private.h,v 1.3 2004/02/09 07:10:38 andersen Exp $ + */ + +#ifndef _MATH_PRIVATE_H_ +#define _MATH_PRIVATE_H_ + +#include +#include + +/* The original fdlibm code used statements like: + n0 = ((*(int*)&one)>>29)^1; * index of high word * + ix0 = *(n0+(int*)&x); * high word of x * + ix1 = *((1-n0)+(int*)&x); * low word of x * + to dig two 32 bit words out of the 64 bit IEEE floating point + value. That is non-ANSI, and, moreover, the gcc instruction + scheduler gets it wrong. We instead use the following macros. + Unlike the original code, we determine the endianness at compile + time, not at run time; I don't see much benefit to selecting + endianness at run time. */ + +/* A union which permits us to convert between a double and two 32 bit + ints. */ + +/* + * Math on arm is special: + * For FPA, float words are always big-endian. + * For VFP, floats words follow the memory system mode. + */ + +#if (__BYTE_ORDER == __BIG_ENDIAN) || \ + (!defined(__VFP_FP__) && (defined(__arm__) || defined(__thumb__))) + +typedef union +{ + double value; + struct + { + u_int32_t msw; + u_int32_t lsw; + } parts; +} ieee_double_shape_type; + +#else + +typedef union +{ + double value; + struct + { + u_int32_t lsw; + u_int32_t msw; + } parts; +} ieee_double_shape_type; + +#endif + +/* Get two 32 bit ints from a double. */ + +#define EXTRACT_WORDS(ix0,ix1,d) \ +do { \ + ieee_double_shape_type ew_u; \ + ew_u.value = (d); \ + (ix0) = ew_u.parts.msw; \ + (ix1) = ew_u.parts.lsw; \ +} while (0) + +/* Get the more significant 32 bit int from a double. */ + +#define GET_HIGH_WORD(i,d) \ +do { \ + ieee_double_shape_type gh_u; \ + gh_u.value = (d); \ + (i) = gh_u.parts.msw; \ +} while (0) + +/* Get the less significant 32 bit int from a double. */ + +#define GET_LOW_WORD(i,d) \ +do { \ + ieee_double_shape_type gl_u; \ + gl_u.value = (d); \ + (i) = gl_u.parts.lsw; \ +} while (0) + +/* Set a double from two 32 bit ints. */ + +#define INSERT_WORDS(d,ix0,ix1) \ +do { \ + ieee_double_shape_type iw_u; \ + iw_u.parts.msw = (ix0); \ + iw_u.parts.lsw = (ix1); \ + (d) = iw_u.value; \ +} while (0) + +/* Set the more significant 32 bits of a double from an int. */ + +#define SET_HIGH_WORD(d,v) \ +do { \ + ieee_double_shape_type sh_u; \ + sh_u.value = (d); \ + sh_u.parts.msw = (v); \ + (d) = sh_u.value; \ +} while (0) + +/* Set the less significant 32 bits of a double from an int. */ + +#define SET_LOW_WORD(d,v) \ +do { \ + ieee_double_shape_type sl_u; \ + sl_u.value = (d); \ + sl_u.parts.lsw = (v); \ + (d) = sl_u.value; \ +} while (0) + + +#endif /* _MATH_PRIVATE_H_ */ diff --git a/platform/gp2x/uClibc/memset.s b/platform/gp2x/uClibc/memset.s new file mode 100644 index 00000000..0923014c --- /dev/null +++ b/platform/gp2x/uClibc/memset.s @@ -0,0 +1,72 @@ +/* Copyright (C) 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Philip Blundell + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +@ #include + + .text + .global memset + .type memset,%function + .align 4 + +memset: + mov a4, a1 + cmp a3, $8 @ at least 8 bytes to do? + blt 2f + orr a2, a2, a2, lsl $8 + orr a2, a2, a2, lsl $16 +1: + tst a4, $3 @ aligned yet? + strneb a2, [a4], $1 + subne a3, a3, $1 + bne 1b + mov ip, a2 +1: + cmp a3, $8 @ 8 bytes still to do? + blt 2f + stmia a4!, {a2, ip} + sub a3, a3, $8 + cmp a3, $8 @ 8 bytes still to do? + blt 2f + stmia a4!, {a2, ip} + sub a3, a3, $8 + cmp a3, $8 @ 8 bytes still to do? + blt 2f + stmia a4!, {a2, ip} + sub a3, a3, $8 + cmp a3, $8 @ 8 bytes still to do? + stmgeia a4!, {a2, ip} + subge a3, a3, $8 + bge 1b +2: + movs a3, a3 @ anything left? + moveq pc, lr @ nope + rsb a3, a3, $7 + add pc, pc, a3, lsl $2 + mov r0, r0 + strb a2, [a4], $1 + strb a2, [a4], $1 + strb a2, [a4], $1 + strb a2, [a4], $1 + strb a2, [a4], $1 + strb a2, [a4], $1 + strb a2, [a4], $1 + mov pc, lr + +.size memset,.-memset; + diff --git a/platform/gp2x/uClibc/s_copysign.c b/platform/gp2x/uClibc/s_copysign.c new file mode 100644 index 00000000..e276f733 --- /dev/null +++ b/platform/gp2x/uClibc/s_copysign.c @@ -0,0 +1,39 @@ +/* @(#)s_copysign.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#if defined(LIBM_SCCS) && !defined(lint) +static char rcsid[] = "$NetBSD: s_copysign.c,v 1.8 1995/05/10 20:46:57 jtc Exp $"; +#endif + +/* + * copysign(double x, double y) + * copysign(x,y) returns a value with the magnitude of x and + * with the sign bit of y. + */ + +#include "math.h" +#include "math_private.h" + +#ifdef __STDC__ + double copysign(double x, double y) +#else + double copysign(x,y) + double x,y; +#endif +{ + u_int32_t hx,hy; + GET_HIGH_WORD(hx,x); + GET_HIGH_WORD(hy,y); + SET_HIGH_WORD(x,(hx&0x7fffffff)|(hy&0x80000000)); + return x; +} + diff --git a/platform/gp2x/uClibc/s_fabs.c b/platform/gp2x/uClibc/s_fabs.c new file mode 100644 index 00000000..b9aacc28 --- /dev/null +++ b/platform/gp2x/uClibc/s_fabs.c @@ -0,0 +1,35 @@ +/* @(#)s_fabs.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#if defined(LIBM_SCCS) && !defined(lint) +static char rcsid[] = "$NetBSD: s_fabs.c,v 1.7 1995/05/10 20:47:13 jtc Exp $"; +#endif + +/* + * fabs(x) returns the absolute value of x. + */ + +#include "math.h" +#include "math_private.h" + +#ifdef __STDC__ + double fabs(double x) +#else + double fabs(x) + double x; +#endif +{ + u_int32_t high; + GET_HIGH_WORD(high,x); + SET_HIGH_WORD(x,high&0x7fffffff); + return x; +} diff --git a/platform/gp2x/uClibc/s_floor.c b/platform/gp2x/uClibc/s_floor.c new file mode 100644 index 00000000..d7e5307e --- /dev/null +++ b/platform/gp2x/uClibc/s_floor.c @@ -0,0 +1,81 @@ +/* @(#)s_floor.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#if defined(LIBM_SCCS) && !defined(lint) +static char rcsid[] = "$NetBSD: s_floor.c,v 1.8 1995/05/10 20:47:20 jtc Exp $"; +#endif + +/* + * floor(x) + * Return x rounded toward -inf to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to floor(x). + */ + +#include "math.h" +#include "math_private.h" + +#ifdef __STDC__ +static const double huge = 1.0e300; +#else +static double huge = 1.0e300; +#endif + +#ifdef __STDC__ + double floor(double x) +#else + double floor(x) + double x; +#endif +{ + int32_t i0,i1,j0; + u_int32_t i,j; + EXTRACT_WORDS(i0,i1,x); + j0 = ((i0>>20)&0x7ff)-0x3ff; + if(j0<20) { + if(j0<0) { /* raise inexact if x != 0 */ + if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */ + if(i0>=0) {i0=i1=0;} + else if(((i0&0x7fffffff)|i1)!=0) + { i0=0xbff00000;i1=0;} + } + } else { + i = (0x000fffff)>>j0; + if(((i0&i)|i1)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + if(i0<0) i0 += (0x00100000)>>j0; + i0 &= (~i); i1=0; + } + } + } else if (j0>51) { + if(j0==0x400) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } else { + i = ((u_int32_t)(0xffffffff))>>(j0-20); + if((i1&i)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + if(i0<0) { + if(j0==20) i0+=1; + else { + j = i1+(1<<(52-j0)); + if(j>20; /* extract exponent */ + if (k==0) { /* 0 or subnormal x */ + if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */ + x *= two54; + GET_HIGH_WORD(hx,x); + k = ((hx&0x7ff00000)>>20) - 54; + if (n< -50000) return tiny*x; /*underflow*/ + } + if (k==0x7ff) return x+x; /* NaN or Inf */ + k = k+n; + if (k > 0x7fe) return huge*copysign(huge,x); /* overflow */ + if (k > 0) /* normal result */ + {SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20)); return x;} + if (k <= -54) { + if (n > 50000) /* in case integer overflow in n+k */ + return huge*copysign(huge,x); /*overflow*/ + else return tiny*copysign(tiny,x); /*underflow*/ + } + k += 54; /* subnormal result */ + SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20)); + return x*twom54; +} diff --git a/platform/gp2x/uClibc/s_sin.c b/platform/gp2x/uClibc/s_sin.c new file mode 100644 index 00000000..bcdb7e4e --- /dev/null +++ b/platform/gp2x/uClibc/s_sin.c @@ -0,0 +1,82 @@ +/* @(#)s_sin.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#if defined(LIBM_SCCS) && !defined(lint) +static char rcsid[] = "$NetBSD: s_sin.c,v 1.7 1995/05/10 20:48:15 jtc Exp $"; +#endif + +/* sin(x) + * Return sine function of x. + * + * kernel function: + * __kernel_sin ... sine function on [-pi/4,pi/4] + * __kernel_cos ... cose function on [-pi/4,pi/4] + * __ieee754_rem_pio2 ... argument reduction routine + * + * Method. + * Let S,C and T denote the sin, cos and tan respectively on + * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + * in [-pi/4 , +pi/4], and let n = k mod 4. + * We have + * + * n sin(x) cos(x) tan(x) + * ---------------------------------------------------------- + * 0 S C T + * 1 C -S -1/T + * 2 -S -C T + * 3 -C S -1/T + * ---------------------------------------------------------- + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * trig(+-INF) is NaN, with signals; + * trig(NaN) is that NaN; + * + * Accuracy: + * TRIG(x) returns trig(x) nearly rounded + */ + +#include "math.h" +#include "math_private.h" + +#ifdef __STDC__ + double sin(double x) +#else + double sin(x) + double x; +#endif +{ + double y[2],z=0.0; + int32_t n, ix; + + /* High word of x. */ + GET_HIGH_WORD(ix,x); + + /* |x| ~< pi/4 */ + ix &= 0x7fffffff; + if(ix <= 0x3fe921fb) return __kernel_sin(x,z,0); + + /* sin(Inf or NaN) is NaN */ + else if (ix>=0x7ff00000) return x-x; + + /* argument reduction needed */ + else { + n = __ieee754_rem_pio2(x,y); + switch(n&3) { + case 0: return __kernel_sin(y[0],y[1],1); + case 1: return __kernel_cos(y[0],y[1]); + case 2: return -__kernel_sin(y[0],y[1],1); + default: + return -__kernel_cos(y[0],y[1]); + } + } +} diff --git a/platform/gp2x/uClibc/wrappers.c b/platform/gp2x/uClibc/wrappers.c new file mode 100644 index 00000000..cc4e269e --- /dev/null +++ b/platform/gp2x/uClibc/wrappers.c @@ -0,0 +1,12 @@ +#include "math.h" + +double pow(double x, double y) +{ + return __ieee754_pow(x, y); +} + + +double log(double x) +{ + return __ieee754_log(x); +} diff --git a/platform/gp2x/usbjoy.c b/platform/gp2x/usbjoy.c new file mode 100644 index 00000000..569f6151 --- /dev/null +++ b/platform/gp2x/usbjoy.c @@ -0,0 +1,424 @@ +/* Title: USB Joystick library + Version 0.2 + Written by Puck2099 (puck2099@gmail.com), (c) 2006. + + + If you use this library or a part of it, please, let it know. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include /* For the definition of NULL */ +#include // For Device open +#include +#include +#include +#include // For Device read + +#include +#include /* For the definition of PATH_MAX */ +#include + +#include "usbjoy.h" + + +/* + Function: joy_open + + Opens a USB joystick and fills its information. + + Parameters: + + joynumber - Joystick's identifier (0 reserved for GP2X's builtin Joystick). + + Returns: + + Filled usbjoy structure. + +*/ +struct usbjoy *joy_open(int joynumber) +{ + int fd; + char path [128]; + struct usbjoy * joy = NULL; + struct js_event event; + static char insmod_done = 0; + + // notaz: on my system I get unresolved input_* symbols, so have to 'insmod input' too + // also we should insmod only once, not on every joy_open() call. + if (!insmod_done) { + system ("insmod input"); + system ("insmod joydev"); // Loads joydev module + insmod_done = 1; + } + + if (joynumber == 0) { + } + else if (joynumber > 0) { + sprintf (path, "/dev/input/js%d", joynumber-1); + fd = open(path, O_RDONLY, 0); + if (fd > 0) { + joy = (struct usbjoy *) malloc(sizeof(*joy)); + if (joy == NULL) { close(fd); return NULL; } + memset(joy, 0, sizeof(*joy)); + + // Set the joystick to non-blocking read mode + fcntl(fd, F_SETFL, O_NONBLOCK); + + // notaz: maybe we should flush init events now. + // My pad returns axis as active when I plug it in, which is kind of annoying. + while (read(fd, &event, sizeof(event)) > 0); + + // Joystick's file descriptor + joy->fd = fd; + + // Joystick's name + ioctl(joy->fd, JSIOCGNAME(128*sizeof(char)), joy->name); + + // Joystick's device + strcpy(joy->device, path); + + // Joystick's buttons + ioctl(joy->fd, JSIOCGBUTTONS, &joy->numbuttons); + + // Joystick's axes + ioctl(joy->fd, JSIOCGAXES, &joy->numaxes); + + // Joystick's type (derived from name) + if (strncasecmp(joy->name, "logitech", strlen("logitech")) == 0) + joy->type = JOY_TYPE_LOGITECH; + else joy->type = JOY_TYPE_GENERIC; + } else { + // printf ("ERROR: No Joystick found\n"); + } + } + return joy; +} + +/* + Function: joy_name + + Returns Joystick's name. + + Parameters: + + joy - Selected joystick. + + Returns: + + Joystick's name or NULL if struct is empty. +*/ +char * joy_name (struct usbjoy * joy) { + if (joy != NULL) return joy->name; + else return NULL; +} + + +/* + Function: joy_device + + Returns Joystick's device. + + Parameters: + + joy - Selected joystick. + + Returns: + + Joystick's device or NULL if struct is empty. +*/ +char * joy_device (struct usbjoy * joy) { + if (joy != NULL) return joy->device; + else return NULL; +} + + +/* + Function: joy_buttons + + Returns Joystick's buttons number. + + Parameters: + + joy - Selected joystick. + + Returns: + + Joystick's buttons or 0 if struct is empty. +*/ +int joy_buttons (struct usbjoy * joy) { + if (joy != NULL) return joy->numbuttons; + else return 0; +} + + +/* + Function: joy_axes + + Returns Joystick's axes number. + + Parameters: + + joy - Selected joystick. + + Returns: + + Joystick's axes or 0 if struct is empty. +*/ +int joy_axes (struct usbjoy * joy) { + if (joy != NULL) return joy->numaxes; + else return 0; +} + + +/* + Function: joy_update + + Updates Joystick's internal information ( and fields). + + Parameters: + + joy - Selected joystick. + + Returns: + + 0 - No events registered (no need to update). + 1 - Events registered (a button or axe has been pushed). + -1 - Error: struct is empty. +*/ +int joy_update (struct usbjoy * joy) { + struct js_event events[0xff]; + int i, len; + int event = 0; + if (joy != NULL) { + if ((len=read(joy->fd, events, (sizeof events))) >0) { + len /= sizeof(events[0]); + for ( i=0; istateaxes[JOYLEFT] = joy->stateaxes[JOYRIGHT] = 0; + else if (events[i].value < 0) joy->stateaxes[JOYLEFT] = 1; + else joy->stateaxes[JOYRIGHT] = 1; + } + else if (events[i].number == 1) { + if (events[i].value == 0) joy->stateaxes[JOYUP] = joy->stateaxes[JOYDOWN] = 0; + else if (events[i].value < 0) joy->stateaxes[JOYUP] = 1; + else joy->stateaxes[JOYDOWN] = 1; + } + event = 1; + break; + case JS_EVENT_BUTTON: + joy->statebuttons[events[i].number] = events[i].value; + event = 1; + break; + default: + break; + } + } + } + } + else { + event = -1; + } + return event; +} + + +/* + Function: joy_getbutton + + Returns Joystick's button information. + + Parameters: + + button - Button which value you want to know (from 0 to 31). + joy - Selected joystick. + + Returns: + + 0 - Button NOT pushed. + 1 - Button pushed. + -1 - Error: struct is empty. +*/ +int joy_getbutton (int button, struct usbjoy * joy) { + if (joy != NULL) { + if (button < joy_buttons(joy)) return joy->statebuttons[button]; + else return 0; + } + else return -1; +} + + +/* + Function: joy_getaxe + + Returns Joystick's axes information. + + Parameters: + + axe - Axe which value you want to know (see ). + joy - Selected joystick. + + Returns: + + 0 - Direction NOT pushed. + 1 - Direction pushed. + -1 - Error: struct is empty. +*/ +int joy_getaxe (int axe, struct usbjoy * joy) { + if (joy != NULL) { + if (axe < 4) return joy->stateaxes[axe]; + else return 0; + } + else return -1; +} + + +/* + Function: joy_close + + Closes selected joystick's file descriptor and detroys it's fields. + + Parameters: + + joy - Selected joystick. + + Returns: + + 0 - Joystick successfully closed. + -1 - Error: struct is empty. +*/ +int joy_close (struct usbjoy * joy) { + if (joy != NULL) { + close (joy->fd); + free (joy); + return 0; + } + else return -1; +} + + +/*********************************************************************/ +/* GP2X USB Joystick Handling -GnoStiC */ +/*********************************************************************/ + +#include "gp2x.h" + +int num_of_joys = 0; +struct usbjoy *joys[4]; + +void gp2x_usbjoy_init (void) { + /* Open available joysticks -GnoStiC */ + int i, n = 0; + + printf("\n"); + for (i = 0; i < 4; i++) { + joys[n] = joy_open(i+1); + if (joys[n] && joy_buttons(joys[n]) > 0) { + printf ("+-Joystick %d: \"%s\", buttons = %i\n", i+1, joy_name(joys[n]), joy_buttons(joys[n])); + n++; + } + } + num_of_joys = n; + + printf("Found %d Joystick(s)\n",num_of_joys); +} + +void gp2x_usbjoy_update (void) { + /* Update Joystick Event Cache */ + int q, foo; + for (q=0; q < num_of_joys; q++) { + foo = joy_update (joys[q]); + } +} + +int gp2x_usbjoy_check (int joyno) { + /* Check Joystick */ + int q, joyExKey = 0; + struct usbjoy *joy = joys[joyno]; + + if (joy != NULL) { + if (joy_getaxe(JOYUP, joy)) { joyExKey |= GP2X_UP; } + if (joy_getaxe(JOYDOWN, joy)) { joyExKey |= GP2X_DOWN; } + if (joy_getaxe(JOYLEFT, joy)) { joyExKey |= GP2X_LEFT; } + if (joy_getaxe(JOYRIGHT, joy)) { joyExKey |= GP2X_RIGHT; } + + /* loop through joy buttons to check if they are pushed */ + for (q=0; qtype == JOY_TYPE_LOGITECH) { + switch (q) { + case 0: joyExKey |= GP2X_A; break; + case 1: joyExKey |= GP2X_X; break; + case 2: joyExKey |= GP2X_B; break; + case 3: joyExKey |= GP2X_Y; break; + } + } else { + switch (q) { + case 0: joyExKey |= GP2X_Y; break; + case 1: joyExKey |= GP2X_B; break; + case 2: joyExKey |= GP2X_X; break; + case 3: joyExKey |= GP2X_A; break; + } + } + + switch (q) { + case 4: joyExKey |= GP2X_L; break; + case 5: joyExKey |= GP2X_R; break; + case 6: joyExKey |= GP2X_L; break; /* left shoulder button 2 */ + case 7: joyExKey |= GP2X_R; break; /* right shoulder button 2 */ + case 8: joyExKey |= GP2X_SELECT;break; + case 9: joyExKey |= GP2X_START; break; + case 10: joyExKey |= GP2X_PUSH; break; + case 11: joyExKey |= GP2X_PUSH; break; + } + } + } + } + return joyExKey; +} + +int gp2x_usbjoy_check2 (int joyno) { + /* Check Joystick, don't map to gp2x joy */ + int q, to, joyExKey = 0; + struct usbjoy *joy = joys[joyno]; + + if (joy != NULL) { + if (joy_getaxe(JOYUP, joy)) { joyExKey |= 1 << 0; } + if (joy_getaxe(JOYDOWN, joy)) { joyExKey |= 1 << 1; } + if (joy_getaxe(JOYLEFT, joy)) { joyExKey |= 1 << 2; } + if (joy_getaxe(JOYRIGHT, joy)) { joyExKey |= 1 << 3; } + + /* loop through joy buttons to check if they are pushed */ + to = joy->numbuttons; + if (to > 32-4) to = 32-4; + for (q=0; q < to; q++) + if (joy->statebuttons[q]) joyExKey |= 1 << (q+4); + } + return joyExKey; +} + + + +void gp2x_usbjoy_deinit (void) { + int i; + for (i=0; i + + If you use this library or a part of it, please, let it know. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef USBJOY_H +#define USBJOY_H + +/* notaz: my Logitech has different button layout, and I want it to match gptx's */ +typedef enum { + JOY_TYPE_GENERIC, + JOY_TYPE_LOGITECH +} joy_type; + +/* + Enumeration: Axes values + This enumeration contains shortcuts to the values used on axes. + + Constants: + JOYUP - Joystick Up + JOYDOWN - Joystick Down + JOYLEFT - Joystick Left + JOYRIGHT - Joystick Right + + See also: + +*/ +#define JOYUP (0) +#define JOYDOWN (1) +#define JOYLEFT (2) +#define JOYRIGHT (3) + + +/* + Struct: usbjoy + + Contains all Joystick needed information. + + Fields: + fd - File descriptor used. + name - Joystick's name. + device - /dev/input/jsX device. + numbuttons - Joystick's buttons. + numaxes - Joystick's axes. + numhats - Joystick's hats. + statebuttons - Current state of each button. + stateaxes - Current state of each direction. +*/ +struct usbjoy { + int fd; + char name [128]; + char device [128]; + int numbuttons; + int numaxes; + int numhats; + int statebuttons[32]; + int stateaxes[4]; + joy_type type; +}; + + +/* + Function: joy_open + + Opens a USB joystick and fills its information. + + Parameters: + + joynumber - Joystick's identifier (0 reserved for GP2X's builtin Joystick). + + Returns: + + Filled usbjoy structure. +*/ +struct usbjoy * joy_open (int joynumber); + + +/* + Function: joy_name + + Returns Joystick's name. + + Parameters: + + joy - Selected joystick. + + Returns: + + Joystick's name or NULL if struct is empty. +*/ +char * joy_name (struct usbjoy * joy); + + +/* + Function: joy_device + + Returns Joystick's device. + + Parameters: + + joy - Selected joystick. + + Returns: + + Joystick's device or NULL if struct is empty. +*/ +char * joy_device (struct usbjoy * joy); + +/* + Function: joy_buttons + + Returns Joystick's buttons number. + + Parameters: + + joy - Selected joystick. + + Returns: + + Joystick's buttons or 0 if struct is empty. +*/ +int joy_buttons (struct usbjoy * joy); + +/* + Function: joy_axes + + Returns Joystick's axes number. + + Parameters: + + joy - Selected joystick. + + Returns: + + Joystick's axes or 0 if struct is empty. +*/ +int joy_axes (struct usbjoy * joy); + + +/* + Function: joy_update + + Updates Joystick's internal information ( and fields). + + Parameters: + + joy - Selected joystick. + + Returns: + + 0 - No events registered (no need to update). + 1 - Events registered (a button or axe has been pushed). + -1 - Error: struct is empty. +*/ +int joy_update (struct usbjoy * joy); + + +/* + Function: joy_getbutton + + Returns Joystick's button information. + + Parameters: + + button - Button which value you want to know (from 0 to 31). + joy - Selected joystick. + + Returns: + + 0 - Button NOT pushed. + 1 - Button pushed. + -1 - Error: struct is empty. +*/ +int joy_getbutton (int button, struct usbjoy * joy); + + +/* + Function: joy_getaxe + + Returns Joystick's axes information. + + Parameters: + + axe - Axe which value you want to know (see ). + joy - Selected joystick. + + Returns: + + 0 - Direction NOT pushed. + 1 - Direction pushed. + -1 - Error: struct is empty. +*/ +int joy_getaxe (int axe, struct usbjoy * joy); + +/* + Function: joy_close + + Closes selected joystick's file descriptor and detroys it's fields. + + Parameters: + + joy - Selected joystick. + + Returns: + + 0 - Joystick successfully closed. + -1 - Error: struct is empty. +*/ +int joy_close (struct usbjoy * joy); + + + +/* gp2x stuff */ +extern int num_of_joys; +extern struct usbjoy *joys[4]; + +void gp2x_usbjoy_update(void); +void gp2x_usbjoy_init(void); +int gp2x_usbjoy_check(int joyno); +int gp2x_usbjoy_check2(int joyno); +void gp2x_usbjoy_deinit(void); + + +#endif // USBJOY_H diff --git a/platform/gp2x/version.h b/platform/gp2x/version.h new file mode 100644 index 00000000..1331a8aa --- /dev/null +++ b/platform/gp2x/version.h @@ -0,0 +1,2 @@ +#define VERSION "0.964" + diff --git a/platform/linux/940ctl_ym2612.c b/platform/linux/940ctl_ym2612.c new file mode 100644 index 00000000..97029140 --- /dev/null +++ b/platform/linux/940ctl_ym2612.c @@ -0,0 +1,112 @@ +/* faked 940 code just uses local copy of ym2612 */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../Pico/sound/ym2612.h" +#include "../gp2x/gp2x.h" +#include "../gp2x/emu.h" +#include "../gp2x/menu.h" + + +static YM2612 ym2612; + +YM2612 *ym2612_940 = &ym2612; +int mix_buffer_[44100/50*2]; /* this is where the YM2612 samples will be mixed to */ +int *mix_buffer = mix_buffer_; + + +/***********************************************************/ + +#define MAXOUT (+32767) +#define MINOUT (-32768) + +/* limitter */ +#define Limit(val, max,min) { \ + if ( val > max ) val = max; \ + else if ( val < min ) val = min; \ +} + + +int YM2612Write_940(unsigned int a, unsigned int v) +{ + YM2612Write_(a, v); + + return 0; // cause the engine to do updates once per frame only +} + +UINT8 YM2612Read_940(void) +{ + return YM2612Read_(); +} + + +int YM2612PicoTick_940(int n) +{ + YM2612PicoTick_(n); + + return 0; +} + + +void YM2612PicoStateLoad_940(void) +{ + int i; + + YM2612PicoStateLoad_(); + + for(i = 0; i < 0x100; i++) { + YM2612Write_(0, i); + YM2612Write_(1, ym2612.REGS[i]); + } + for(i = 0; i < 0x100; i++) { + YM2612Write_(2, i); + YM2612Write_(3, ym2612.REGS[i|0x100]); + } +} + + +void YM2612Init_940(int baseclock, int rate) +{ + YM2612Init_(baseclock, rate); +} + + +void YM2612ResetChip_940(void) +{ + YM2612ResetChip_(); +} + + +void YM2612UpdateOne_940(short *buffer, int length, int stereo) +{ + int i; + + YM2612UpdateOne_(buffer, length, stereo); + + /* mix data */ + if (stereo) { + int *mb = mix_buffer; + for (i = length; i > 0; i--) { + int l, r; + l = r = *buffer; + l += *mb++, r += *mb++; + Limit( l, MAXOUT, MINOUT ); + Limit( r, MAXOUT, MINOUT ); + *buffer++ = l; *buffer++ = r; + } + } else { + for (i = 0; i < length; i++) { + int l = mix_buffer[i]; + l += buffer[i]; + Limit( l, MAXOUT, MINOUT ); + buffer[i] = l; + } + } +} + diff --git a/platform/linux/Makefile b/platform/linux/Makefile new file mode 100644 index 00000000..fc6b200e --- /dev/null +++ b/platform/linux/Makefile @@ -0,0 +1,91 @@ + +# settings +dprint = 1 +# profile = 1 + + +DEFINC = -I../.. -I. -D__GP2X__ -D_UNZIP_SUPPORT # -DBENCHMARK +GCC = gcc +STRIP = strip +AS = gcc + +ifeq "$(profile)" "1" +COPT_COMMON = -s -O3 -ftracer -fstrength-reduce -Wall -funroll-loops -fomit-frame-pointer -fstrict-aliasing -ffast-math -fprofile-generate # -static +COPT = $(COPT_COMMON) # -mtune=arm920t +else +COPT = -ggdb -Wall -fno-strict-aliasing # -pg -O3 -ftracer -fstrength-reduce -funroll-loops -fomit-frame-pointer -ffast-math +COPT_COMMON = $(COPT) +endif + +# gtk +COPT += `pkg-config --cflags gtk+-2.0` +LDFLAGS += `pkg-config --libs gtk+-2.0` +COPT += `pkg-config --cflags gthread-2.0` +LDFLAGS += `pkg-config --libs gthread-2.0` + +# frontend +OBJS += ../gp2x/main.o ../gp2x/menu.o ../gp2x/emu.o ../gp2x/usbjoy.o blit.o gp2x.o 940ctl_ym2612.o +# Pico +OBJS += ../../Pico/Area.o ../../Pico/Cart.o ../../Pico/Utils.o ../../Pico/Memory.o ../../Pico/Misc.o \ + ../../Pico/Pico.o ../../Pico/Sek.o ../../Pico/VideoPort.o ../../Pico/Draw2.o ../../Pico/Draw.o +# Pico - CD +OBJS += ../../Pico/cd/Pico.o ../../Pico/cd/Memory.o ../../Pico/cd/Sek.o ../../Pico/cd/LC89510.o \ + ../../Pico/cd/cd_sys.o +# Pico - sound +OBJS += ../../Pico/sound/sound.o ../../Pico/sound/sn76496.o ../../Pico/sound/ym2612.o +# zlib +OBJS += ../../zlib/gzio.o ../../zlib/inffast.o ../../zlib/inflate.o ../../zlib/inftrees.o ../../zlib/trees.o \ + ../../zlib/deflate.o ../../zlib/crc32.o ../../zlib/adler32.o ../../zlib/zutil.o ../../zlib/compress.o +# unzip +OBJS += ../../unzip/unzip.o +# CPU cores +DEFINC += -DEMU_M68K +OBJS += ../../cpu/musashi/m68kcpu.o ../../cpu/musashi/m68kopac.o ../../cpu/musashi/m68kopdm.o \ + ../../cpu/musashi/m68kopnz.o ../../cpu/musashi/m68kops.o +# mz80 +DEFINC += -D_USE_MZ80 +OBJS += ../../cpu/mz80/mz80.o + +# faked asm +#DEFINC += -D_ASM_DRAW_C +#DEFINC += -D_ASM_MEMORY_C +#DEFINC += -D_ASM_YM2612_C +OBJS += fakedasm.o + + +all: PicoDrive +clean: tidy + @$(RM) PicoDrive +tidy: + @$(RM) $(OBJS) + @make -C ../../cpu/mz80/ clean + +PicoDrive : $(OBJS) + @echo $@ + @$(GCC) $(COPT) $(OBJS) $(LDFLAGS) -lm -o $@ + + +../../cpu/mz80/mz80.o : ../../cpu/mz80/mz80.asm + @echo $@ + @nasm -f elf $< -o $@ + +../../cpu/mz80/mz80.asm : + @make -C ../../cpu/mz80/ + +.c.o: + @echo $< + @$(GCC) $(COPT) $(DEFINC) -c $< -o $@ +.s.o: + @echo $< + @$(GCC) $(COPT) $(DEFINC) -c $< -o $@ + + +../../Pico/sound/ym2612.o : ../../Pico/sound/ym2612.c + @echo $@ + @$(GCC) $(COPT_COMMON) $(DEFINC) -DEXTERNAL_YM2612 -c $< -o $@ # -mtune=arm940t + +# faked asm +../../Pico/Draw.o : ../../Pico/Draw.c + @echo $< + @$(GCC) $(COPT) $(DEFINC) -D_ASM_DRAW_C -c $< -o $@ + diff --git a/platform/linux/README b/platform/linux/README new file mode 100644 index 00000000..fa36b28d --- /dev/null +++ b/platform/linux/README @@ -0,0 +1,4 @@ +This port tries to emulate gp2x environment on a standard linux box for testing +(i.e. to be able to use things like valgrind and efence, gcc runtime +optimizations, etc.). + diff --git a/platform/linux/blit.c b/platform/linux/blit.c new file mode 100644 index 00000000..a4981d9f --- /dev/null +++ b/platform/linux/blit.c @@ -0,0 +1,81 @@ + +// Convert 0000bbb0 ggg0rrr0 0000bbb0 ggg0rrr0 +// to 00000000 rrr00000 ggg00000 bbb00000 ... + +void vidConvCpyRGB32 (void *to, void *from, int pixels) +{ + unsigned short *ps = from; + unsigned int *pd = to; + + for (; pixels; pixels--, ps++, pd++) + { + *pd = ((*ps<<20)&0xe00000) | ((*ps<<8)&0xe000) | ((*ps>>4)&0xe0); + *pd |= *pd >> 3; + } +} + +void vidConvCpyRGB32sh(void *to, void *from, int pixels) +{ + unsigned short *ps = from; + unsigned int *pd = to; + + for (; pixels; pixels--, ps++, pd++) + { + *pd = ((*ps<<20)&0xe00000) | ((*ps<<8)&0xe000) | ((*ps>>4)&0xe0); + *pd >>= 1; + *pd |= *pd >> 3; + } +} + +void vidConvCpyRGB32hi(void *to, void *from, int pixels) +{ + unsigned short *ps = from; + unsigned int *pd = to; + + for (; pixels; pixels--, ps++, pd++) + { + *pd = ((*ps<<20)&0xe00000) | ((*ps<<8)&0xe000) | ((*ps>>4)&0xe0); + continue; + *pd += 0x00404040; + if (*pd & 0x01000000) *pd |= 0x00e00000; + if (*pd & 0x00010000) *pd |= 0x0000e000; + if (*pd & 0x00000100) *pd |= 0x000000e0; + *pd &= 0x00e0e0e0; + *pd |= *pd >> 3; + } +} + +void vidCpyM2_40col(void *dest, void *src) +{ + unsigned char *pd = dest, *ps = src; + int i, u; + + for (i = 0; i < 224; i++) + { + ps += 8; + for (u = 0; u < 320; u++) + *pd++ = *ps++; + } +} + +void vidCpyM2_32col(void *dest, void *src) +{ + unsigned char *pd = dest, *ps = src; + int i, u; + + for (i = 0; i < 224; i++) + { + ps += 8; + pd += 32; + for (u = 0; u < 256; u++) + *pd++ = *ps++; + ps += 64; + pd += 32; + } +} + +void vidCpyM2_32col_nobord(void *dest, void *src) +{ + vidCpyM2_32col(dest, src); +} + diff --git a/platform/linux/fakedasm.c b/platform/linux/fakedasm.c new file mode 100644 index 00000000..d0e357c8 --- /dev/null +++ b/platform/linux/fakedasm.c @@ -0,0 +1,667 @@ +// This is part of Pico Library + +// (c) Copyright 2004 Dave, All rights reserved. +// (c) Copyright 2006 notaz, All rights reserved. +// Free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + + +#include "../../Pico/PicoInt.h" +#undef blockcpy + +extern unsigned short DefOutBuff[320*2]; +extern unsigned char HighCol[8+320+8]; +extern char HighSprZ[320+8+8]; // Z-buffer for accurate sprites and shadow/hilight mode + // (if bit 7 == 0, sh caused by tile; if bit 6 == 0 pixel must be shadowed, else hilighted, if bit5 == 1) +// lsb->msb: moved sprites, all window tiles don't use same priority, accurate sprites (copied from PicoOpt), interlace +// dirty sprites, sonic mode +extern int rendstatus; +extern int Scanline; // Scanline + + +struct TileStrip +{ + int nametab; // Position in VRAM of name table (for this tile line) + int line; // Line number in pixels 0x000-0x3ff within the virtual tilemap + int hscroll; // Horizontal scroll value in pixels for the line + int xmask; // X-Mask (0x1f - 0x7f) for horizontal wraparound in the tilemap + int *hc; // cache for high tile codes and their positions + int cells; // cells (tiles) to draw (32 col mode doesn't need to update whole 320) +}; + +// utility +void *blockcpy(void *dst, const void *src, size_t n) +{ + return memcpy(dst, src, n); +} + +void blockcpy_or(void *dst, void *src, size_t n, int pat) +{ + unsigned char *pd = dst, *ps = src; + for (; n; n--) + *pd++ = (unsigned char) (*ps++ | pat); +} + + +static int TileNorm(int sx,int addr,int pal) +{ + unsigned char *pd = HighCol+sx; + unsigned int pack=0; unsigned int t=0; + + pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + if (pack) + { + t=pack&0x0000f000; if (t) pd[0]=(unsigned char)(pal|(t>>12)); + t=pack&0x00000f00; if (t) pd[1]=(unsigned char)(pal|(t>> 8)); + t=pack&0x000000f0; if (t) pd[2]=(unsigned char)(pal|(t>> 4)); + t=pack&0x0000000f; if (t) pd[3]=(unsigned char)(pal|(t )); + t=pack&0xf0000000; if (t) pd[4]=(unsigned char)(pal|(t>>28)); + t=pack&0x0f000000; if (t) pd[5]=(unsigned char)(pal|(t>>24)); + t=pack&0x00f00000; if (t) pd[6]=(unsigned char)(pal|(t>>20)); + t=pack&0x000f0000; if (t) pd[7]=(unsigned char)(pal|(t>>16)); + return 0; + } + + return 1; // Tile blank +} + +static int TileFlip(int sx,int addr,int pal) +{ + unsigned char *pd = HighCol+sx; + unsigned int pack=0; unsigned int t=0; + + pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + if (pack) + { + t=pack&0x000f0000; if (t) pd[0]=(unsigned char)(pal|(t>>16)); + t=pack&0x00f00000; if (t) pd[1]=(unsigned char)(pal|(t>>20)); + t=pack&0x0f000000; if (t) pd[2]=(unsigned char)(pal|(t>>24)); + t=pack&0xf0000000; if (t) pd[3]=(unsigned char)(pal|(t>>28)); + t=pack&0x0000000f; if (t) pd[4]=(unsigned char)(pal|(t )); + t=pack&0x000000f0; if (t) pd[5]=(unsigned char)(pal|(t>> 4)); + t=pack&0x00000f00; if (t) pd[6]=(unsigned char)(pal|(t>> 8)); + t=pack&0x0000f000; if (t) pd[7]=(unsigned char)(pal|(t>>12)); + return 0; + } + return 1; // Tile blank +} + + +// tile renderers for hacky operator sprite support +#define sh_pix(x) \ + if(!t); \ + else if(t==0xe) pd[x]=(unsigned char)((pd[x]&0x3f)|0x80); /* hilight */ \ + else if(t==0xf) pd[x]=(unsigned char)((pd[x]&0x3f)|0xc0); /* shadow */ \ + else pd[x]=(unsigned char)(pal|t); + +static int TileNormSH(int sx,int addr,int pal) +{ + unsigned int pack=0; unsigned int t=0; + unsigned char *pd = HighCol+sx; + + pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + if (pack) + { + t=(pack&0x0000f000)>>12; sh_pix(0); + t=(pack&0x00000f00)>> 8; sh_pix(1); + t=(pack&0x000000f0)>> 4; sh_pix(2); + t=(pack&0x0000000f) ; sh_pix(3); + t=(pack&0xf0000000)>>28; sh_pix(4); + t=(pack&0x0f000000)>>24; sh_pix(5); + t=(pack&0x00f00000)>>20; sh_pix(6); + t=(pack&0x000f0000)>>16; sh_pix(7); + return 0; + } + + return 1; // Tile blank +} + +static int TileFlipSH(int sx,int addr,int pal) +{ + unsigned int pack=0; unsigned int t=0; + unsigned char *pd = HighCol+sx; + + pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels + if (pack) + { + t=(pack&0x000f0000)>>16; sh_pix(0); + t=(pack&0x00f00000)>>20; sh_pix(1); + t=(pack&0x0f000000)>>24; sh_pix(2); + t=(pack&0xf0000000)>>28; sh_pix(3); + t=(pack&0x0000000f) ; sh_pix(4); + t=(pack&0x000000f0)>> 4; sh_pix(5); + t=(pack&0x00000f00)>> 8; sh_pix(6); + t=(pack&0x0000f000)>>12; sh_pix(7); + return 0; + } + return 1; // Tile blank +} + + +// -------------------------------------------- + +static void DrawStrip(struct TileStrip *ts, int sh) +{ + int tilex=0,dx=0,ty=0,code=0,addr=0,cells; + int oldcode=-1,blank=-1; // The tile we know is blank + int pal=0; + + // Draw tiles across screen: + tilex=(-ts->hscroll)>>3; + ty=(ts->line&7)<<1; // Y-Offset into tile + dx=((ts->hscroll-1)&7)+1; + cells = ts->cells; + if(dx != 8) cells++; // have hscroll, need to draw 1 cell more + + for (; cells; dx+=8,tilex++,cells--) + { + int zero=0; + + code=Pico.vram[ts->nametab+(tilex&ts->xmask)]; + if (code==blank) continue; + if (code>>15) { // high priority tile + int cval = code | (dx<<16) | (ty<<25); + if(code&0x1000) cval^=7<<26; + *ts->hc++ = cval; // cache it + continue; + } + + if (code!=oldcode) { + oldcode = code; + // Get tile address/2: + addr=(code&0x7ff)<<4; + addr+=ty; + if (code&0x1000) addr^=0xe; // Y-flip + +// pal=Pico.cram+((code>>9)&0x30); + pal=((code>>9)&0x30)|(sh<<6); + } + + if (code&0x0800) zero=TileFlip(dx,addr,pal); + else zero=TileNorm(dx,addr,pal); + + if (zero) blank=code; // We know this tile is blank now + } + + // terminate the cache list + *ts->hc = 0; +} + +static void DrawStripVSRam(struct TileStrip *ts, int plane) +{ + int tilex=0,dx=0,ty=0,code=0,addr=0,cell=0,nametabadd=0; + int oldcode=-1,blank=-1; // The tile we know is blank + int pal=0,scan=Scanline; + + // Draw tiles across screen: + tilex=(-ts->hscroll)>>3; + dx=((ts->hscroll-1)&7)+1; + if(dx != 8) { + int vscroll, line; + cell--; // have hscroll, start with negative cell + // also calculate intial VS stuff + vscroll=Pico.vsram[plane]; + + // Find the line in the name table + line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask .. + nametabadd=(line>>3)<<(ts->line>>24); // .. and shift[width] + ty=(line&7)<<1; // Y-Offset into tile + } + + for (; cell < ts->cells; dx+=8,tilex++,cell++) + { + int zero=0; + + if((cell&1)==0) { + int line,vscroll; + vscroll=Pico.vsram[plane+(cell&~1)]; + + // Find the line in the name table + line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask .. + nametabadd=(line>>3)<<(ts->line>>24); // .. and shift[width] + ty=(line&7)<<1; // Y-Offset into tile + } + + code=Pico.vram[ts->nametab+nametabadd+(tilex&ts->xmask)]; + if (code==blank) continue; + if (code>>15) { // high priority tile + int cval = code | (dx<<16) | (ty<<25); + if(code&0x1000) cval^=7<<26; + *ts->hc++ = cval; // cache it + continue; + } + + if (code!=oldcode) { + oldcode = code; + // Get tile address/2: + addr=(code&0x7ff)<<4; + if (code&0x1000) addr+=14-ty; else addr+=ty; // Y-flip + +// pal=Pico.cram+((code>>9)&0x30); + pal=((code>>9)&0x30); + } + + if (code&0x0800) zero=TileFlip(dx,addr,pal); + else zero=TileNorm(dx,addr,pal); + + if (zero) blank=code; // We know this tile is blank now + } + + // terminate the cache list + *ts->hc = 0; +} + +static void DrawStripInterlace(struct TileStrip *ts) +{ + int tilex=0,dx=0,ty=0,code=0,addr=0,cells; + int oldcode=-1,blank=-1; // The tile we know is blank + int pal=0; + + // Draw tiles across screen: + tilex=(-ts->hscroll)>>3; + ty=(ts->line&15)<<1; // Y-Offset into tile + dx=((ts->hscroll-1)&7)+1; + cells = ts->cells; + if(dx != 8) cells++; // have hscroll, need to draw 1 cell more + + for (; cells; dx+=8,tilex++,cells--) + { + int zero=0; + + code=Pico.vram[ts->nametab+(tilex&ts->xmask)]; + if (code==blank) continue; + if (code>>15) { // high priority tile + int cval = (code&0xfc00) | (dx<<16) | (ty<<25); + cval|=(code&0x3ff)<<1; + if(code&0x1000) cval^=0xf<<26; + *ts->hc++ = cval; // cache it + continue; + } + + if (code!=oldcode) { + oldcode = code; + // Get tile address/2: + addr=(code&0x7ff)<<5; + if (code&0x1000) addr+=30-ty; else addr+=ty; // Y-flip + +// pal=Pico.cram+((code>>9)&0x30); + pal=((code>>9)&0x30); + } + + if (code&0x0800) zero=TileFlip(dx,addr,pal); + else zero=TileNorm(dx,addr,pal); + + if (zero) blank=code; // We know this tile is blank now + } + + // terminate the cache list + *ts->hc = 0; +} + +// -------------------------------------------- + +void DrawLayer(int plane, int *hcache, int maxcells, int sh) +{ + struct PicoVideo *pvid=&Pico.video; + const char shift[4]={5,6,5,7}; // 32,64 or 128 sized tilemaps (2 is invalid) + struct TileStrip ts; + int width, height, ymask; + int vscroll, htab; + + ts.hc=hcache; + ts.cells=maxcells; + + // Work out the TileStrip to draw + + // Work out the name table size: 32 64 or 128 tiles (0-3) + width=pvid->reg[16]; + height=(width>>4)&3; width&=3; + + ts.xmask=(1<1) ymask =0x0ff; + + // Find name table: + if (plane==0) ts.nametab=(pvid->reg[2]&0x38)<< 9; // A + else ts.nametab=(pvid->reg[4]&0x07)<<12; // B + + htab=pvid->reg[13]<<9; // Horizontal scroll table address + if ( pvid->reg[11]&2) htab+=Scanline<<1; // Offset by line + if ((pvid->reg[11]&1)==0) htab&=~0xf; // Offset by tile + htab+=plane; // A or B + + // Get horizontal scroll value, will be masked later + ts.hscroll=Pico.vram[htab&0x7fff]; + + if((pvid->reg[12]&6) == 6) { + // interlace mode 2 + vscroll=Pico.vsram[plane]; // Get vertical scroll value + + // Find the line in the name table + ts.line=(vscroll+(Scanline<<1))&((ymask<<1)|1); + ts.nametab+=(ts.line>>4)<reg[11]&4) { + // shit, we have 2-cell column based vscroll + // luckily this doesn't happen too often + ts.line=ymask|(shift[width]<<24); // save some stuff instead of line + DrawStripVSRam(&ts, plane); + } else { + vscroll=Pico.vsram[plane]; // Get vertical scroll value + + // Find the line in the name table + ts.line=(vscroll+Scanline)&ymask; + ts.nametab+=(ts.line>>3)<reg[12]&1) + { + nametab=(pvid->reg[3]&0x3c)<<9; // 40-cell mode + nametab+=(Scanline>>3)<<6; + } + else + { + nametab=(pvid->reg[3]&0x3e)<<9; // 32-cell mode + nametab+=(Scanline>>3)<<5; + } + + tilex=tstart<<1; + tend<<=1; + + ty=(Scanline&7)<<1; // Y-Offset into tile + + if(!(rendstatus&2)) { + // check the first tile code + code=Pico.vram[nametab+tilex]; + // if the whole window uses same priority (what is often the case), we may be able to skip this field + if((code>>15) != prio) return; + } + + // Draw tiles across screen: + for (; tilex < tend; tilex++) + { + int addr=0,zero=0; + int pal; + + code=Pico.vram[nametab+tilex]; + if(code==blank) continue; + if((code>>15) != prio) { + rendstatus|=2; + continue; + } + + pal=((code>>9)&0x30); + + if(sh) { + int tmp, *zb = (int *)(HighCol+8+(tilex<<3)); + if(prio) { + tmp = *zb; + if(!(tmp&0x00000080)) tmp&=~0x000000c0; if(!(tmp&0x00008000)) tmp&=~0x0000c000; + if(!(tmp&0x00800000)) tmp&=~0x00c00000; if(!(tmp&0x80000000)) tmp&=~0xc0000000; + *zb++=tmp; tmp = *zb; + if(!(tmp&0x00000080)) tmp&=~0x000000c0; if(!(tmp&0x00008000)) tmp&=~0x0000c000; + if(!(tmp&0x00800000)) tmp&=~0x00c00000; if(!(tmp&0x80000000)) tmp&=~0xc0000000; + *zb++=tmp; + } else { + pal |= 0x40; + } + } + + // Get tile address/2: + addr=(code&0x7ff)<<4; + if (code&0x1000) addr+=14-ty; else addr+=ty; // Y-flip + + if (code&0x0800) zero=TileFlip(8+(tilex<<3),addr,pal); + else zero=TileNorm(8+(tilex<<3),addr,pal); + + if (zero) blank=code; // We know this tile is blank now + } + + // terminate the cache list + //*hcache = 0; +} + +// -------------------------------------------- + +void DrawTilesFromCache(int *hc, int sh) +{ + int code, addr, zero, dx; + int pal; + short blank=-1; // The tile we know is blank + + // *ts->hc++ = code | (dx<<16) | (ty<<25); // cache it + + while((code=*hc++)) { + if(!sh && (short)code == blank) continue; + + // Get tile address/2: + addr=(code&0x7ff)<<4; + addr+=(unsigned int)code>>25; // y offset into tile + dx=(code>>16)&0x1ff; + if(sh) { + unsigned char *zb = HighCol+dx; + if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++; + if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++; + if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++; + if(!(*zb&0x80)) *zb&=0x3f; zb++; if(!(*zb&0x80)) *zb&=0x3f; zb++; + } + + pal=((code>>9)&0x30); + + if (code&0x0800) zero=TileFlip(dx,addr,pal); + else zero=TileNorm(dx,addr,pal); + + if(zero) blank=(short)code; + } +} + +// -------------------------------------------- + +// Index + 0 : hhhhvvvv ab--hhvv yyyyyyyy yyyyyyyy // a: offscreen h, b: offs. v, h: horiz. size +// Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8 + +void DrawSprite(int *sprite, int **hc, int sh) +{ + int width=0,height=0; + int row=0,code=0; + int pal; + int tile=0,delta=0; + int sx, sy; + int (*fTileFunc)(int sx,int addr,int pal); + + // parse the sprite data + sy=sprite[0]; + code=sprite[1]; + sx=code>>16; // X + width=sy>>28; + height=(sy>>24)&7; // Width and height in tiles + sy=(sy<<16)>>16; // Y + + row=Scanline-sy; // Row of the sprite we are on + + if (code&0x1000) row=(height<<3)-1-row; // Flip Y + + tile=code&0x7ff; // Tile number + tile+=row>>3; // Tile number increases going down + delta=height; // Delta to increase tile by going right + if (code&0x0800) { tile+=delta*(width-1); delta=-delta; } // Flip X + + tile<<=4; tile+=(row&7)<<1; // Tile address + + if(code&0x8000) { // high priority - cache it + *(*hc)++ = (tile<<16)|((code&0x0800)<<5)|((sx<<6)&0x0000ffc0)|((code>>9)&0x30)|((sprite[0]>>16)&0xf); + } else { + delta<<=4; // Delta of address + pal=((code>>9)&0x30)|(sh<<6); + + if(sh && (code&0x6000) == 0x6000) { + if(code&0x0800) fTileFunc=TileFlipSH; + else fTileFunc=TileNormSH; + } else { + if(code&0x0800) fTileFunc=TileFlip; + else fTileFunc=TileNorm; + } + + for (; width; width--,sx+=8,tile+=delta) + { + if(sx<=0) continue; + if(sx>=328) break; // Offscreen + + tile&=0x7fff; // Clip tile address + fTileFunc(sx,tile,pal); + } + } +} + + +void DrawSpritesFromCache(int *hc, int sh) +{ + int code, tile, sx, delta, width; + int pal; + int (*fTileFunc)(int sx,int addr,int pal); + + // *(*hc)++ = (tile<<16)|((code&0x0800)<<5)|((sx<<6)&0x0000ffc0)|((code>>9)&0x30)|((sprite[0]>>24)&0xf); + + while((code=*hc++)) { + pal=(code&0x30); + delta=code&0xf; + width=delta>>2; delta&=3; + width++; delta++; // Width and height in tiles + if (code&0x10000) delta=-delta; // Flip X + delta<<=4; + tile=((unsigned int)code>>17)<<1; + sx=(code<<16)>>22; // sx can be negative (start offscreen), so sign extend + + if(sh && pal == 0x30) { // + if(code&0x10000) fTileFunc=TileFlipSH; + else fTileFunc=TileNormSH; + } else { + if(code&0x10000) fTileFunc=TileFlip; + else fTileFunc=TileNorm; + } + + for (; width; width--,sx+=8,tile+=delta) + { + if(sx<=0) continue; + if(sx>=328) break; // Offscreen + + tile&=0x7fff; // Clip tile address + fTileFunc(sx,tile,pal); + } + } +} + + +void BackFill(int reg7, int sh) +{ + unsigned int back=0; + unsigned int *pd=NULL,*end=NULL; + + // Start with a blank scanline (background colour): + back=reg7&0x3f; + back|=sh<<6; + back|=back<<8; + back|=back<<16; + + pd= (unsigned int *)(HighCol+8); + end=(unsigned int *)(HighCol+8+320); + + do { pd[0]=pd[1]=pd[2]=pd[3]=back; pd+=4; } while (pd= 0; i--) + pal[0x40|i] = pal[0xc0|i] = (unsigned short)((pal[i]>>1)&0x0777); + // hilighted pixels + for(i = 0x3f; i >= 0; i--) { + t=pal[i]&0xeee;t+=0x444;if(t&0x10)t|=0xe;if(t&0x100)t|=0xe0;if(t&0x1000)t|=0xe00;t&=0xeee; + pal[0x80|i]=(unsigned short)t; + } + Pico.m.dirtyPal = 0; + } + } + + for(i = 0; i < len; i++) + pd[i] = pal[ps[i]]; +} + + +void FinalizeLineRGB555(int sh) +{ + unsigned short *pd=DrawLineDest; + unsigned char *ps=HighCol+8; + unsigned short *pal=HighPal; + int len, i, t, dirtyPal = Pico.m.dirtyPal; + + if(dirtyPal) { + unsigned short *ppal=Pico.cram; + for(i = 0x3f; i >= 0; i--) + pal[i] = (unsigned short) (((ppal[i]&0x00f)<<12)|((ppal[i]&0x0f0)<<3)|((ppal[i]&0xf00)>>7)); + Pico.m.dirtyPal = 0; + } + + if (Pico.video.reg[12]&1) { + len = 320; + } else { + if(!(PicoOpt&0x100)) pd+=32; + len = 256; + } + + if(sh) { + if(dirtyPal) { + // shadowed pixels + for(i = 0x3f; i >= 0; i--) + pal[0x40|i] = pal[0xc0|i] = (unsigned short)((pal[i]>>1)&0x738e); + // hilighted pixels + for(i = 0x3f; i >= 0; i--) { + t=pal[i]&0xe71c;t+=0x4208;if(t&0x20)t|=0x1c;if(t&0x800)t|=0x700;if(t&0x10000)t|=0xe000;t&=0xe71c; + pal[0x80|i]=(unsigned short)t; + } + } + } + + for(i = 0; i < len; i++) + pd[i] = pal[ps[i]]; +} + + + diff --git a/platform/linux/gp2x.c b/platform/linux/gp2x.c new file mode 100644 index 00000000..2651a50b --- /dev/null +++ b/platform/linux/gp2x.c @@ -0,0 +1,384 @@ +/* faking/emulating gp2x.c by using gtk */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../gp2x/emu.h" +#include "../gp2x/gp2x.h" +#include "../gp2x/usbjoy.h" +#include "../gp2x/version.h" + +void *gp2x_screen; +static int current_bpp = 8; +static int current_pal[256]; +static unsigned long current_keys = 0; +static int sounddev = 0, mixerdev = 0; +static const char *verstring = "PicoDrive " VERSION; + +// dummies +char *ext_menu = 0, *ext_state = 0; + +/* gtk */ +struct gtk_global_struct +{ + GtkWidget *window; + GtkWidget *pixmap1; +} gtk_items; + + +static gboolean delete_event (GtkWidget *widget, GdkEvent *event, gpointer data) +{ + return FALSE; +} + +static void destroy (GtkWidget *widget, gpointer data) +{ + gtk_main_quit (); +} + +static gint key_press_event (GtkWidget *widget, GdkEventKey *event) +{ + switch (event->hardware_keycode) + { + case 0x62: current_keys |= GP2X_UP; break; + case 0x68: current_keys |= GP2X_DOWN; break; + case 0x64: current_keys |= GP2X_LEFT; break; + case 0x66: current_keys |= GP2X_RIGHT; break; + case 0x24: current_keys |= GP2X_START; break; // enter + case 0x23: current_keys |= GP2X_SELECT;break; // ] + case 0x34: current_keys |= GP2X_A; break; // z + case 0x35: current_keys |= GP2X_X; break; // x + case 0x36: current_keys |= GP2X_B; break; // c + case 0x37: current_keys |= GP2X_Y; break; // v + case 0x27: current_keys |= GP2X_L; break; // s + case 0x28: current_keys |= GP2X_R; break; // d + case 0x29: current_keys |= GP2X_PUSH; break; // f + case 0x18: current_keys |= GP2X_VOL_DOWN;break; // q + case 0x19: current_keys |= GP2X_VOL_UP;break; // w + } + + return 0; +} + +static gint key_release_event (GtkWidget *widget, GdkEventKey *event) +{ + switch (event->hardware_keycode) + { + case 0x62: current_keys &= ~GP2X_UP; break; + case 0x68: current_keys &= ~GP2X_DOWN; break; + case 0x64: current_keys &= ~GP2X_LEFT; break; + case 0x66: current_keys &= ~GP2X_RIGHT; break; + case 0x24: current_keys &= ~GP2X_START; break; // enter + case 0x23: current_keys &= ~GP2X_SELECT;break; // ] + case 0x34: current_keys &= ~GP2X_A; break; // z + case 0x35: current_keys &= ~GP2X_X; break; // x + case 0x36: current_keys &= ~GP2X_B; break; // c + case 0x37: current_keys &= ~GP2X_Y; break; // v + case 0x27: current_keys &= ~GP2X_L; break; // s + case 0x28: current_keys &= ~GP2X_R; break; // d + case 0x29: current_keys &= ~GP2X_PUSH; break; // f + case 0x18: current_keys &= ~GP2X_VOL_DOWN;break; // q + case 0x19: current_keys &= ~GP2X_VOL_UP;break; // w + } + + return 0; +} + +static void *gtk_threadf(void *none) +{ + gtk_main(); + + printf("linux: gtk thread finishing\n"); + engineState = PGS_Quit; + + return NULL; +} + +static void gtk_initf(void) +{ + int argc = 0; + char *argv[] = { "" }; + GtkWidget *box; + pthread_t gtk_thread; + + g_thread_init (NULL); + gdk_threads_init (); + gdk_set_locale (); + gtk_init (&argc, (char ***) &argv); + + /* create new window */ + gtk_items.window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + g_signal_connect (G_OBJECT (gtk_items.window), "delete_event", + G_CALLBACK (delete_event), NULL); + + g_signal_connect (G_OBJECT (gtk_items.window), "destroy", + G_CALLBACK (destroy), NULL); + + g_signal_connect (G_OBJECT (gtk_items.window), "key_press_event", + G_CALLBACK (key_press_event), NULL); + + g_signal_connect (G_OBJECT (gtk_items.window), "key_release_event", + G_CALLBACK (key_release_event), NULL); + + gtk_container_set_border_width (GTK_CONTAINER (gtk_items.window), 2); + gtk_window_set_title ((GtkWindow *) gtk_items.window, verstring); + + box = gtk_hbox_new(FALSE, 0); + gtk_widget_show(box); + gtk_container_add (GTK_CONTAINER (gtk_items.window), box); + + /* live pixmap */ + gtk_items.pixmap1 = gtk_image_new (); + gtk_container_add (GTK_CONTAINER (box), gtk_items.pixmap1); + gtk_widget_show (gtk_items.pixmap1); + gtk_widget_set_size_request (gtk_items.pixmap1, 320, 240); + + gtk_widget_show (gtk_items.window); + + // pthread_mutex_init (&thr_mutex, NULL); + // pthread_mutex_lock (&thr_mutex); + // pthread_mutex_init (&scanner_muttex, NULL); + + pthread_create(>k_thread, NULL, gtk_threadf, NULL); +} + +void finalize_image(guchar *pixels, gpointer data) +{ + free(pixels); +} + +/* --- */ + +void gp2x_init(void) +{ + printf("entering init()\n"); fflush(stdout); + + gp2x_screen = malloc(320*240*2 + 320*2); + + // snd + mixerdev = open("/dev/mixer", O_RDWR); + if (mixerdev == -1) + printf("open(\"/dev/mixer\") failed with %i\n", errno); + + gtk_initf(); + + gp2x_usbjoy_init(); + + printf("exitting init()\n"); fflush(stdout); +} + +void gp2x_deinit(void) +{ + free(gp2x_screen); + if (sounddev > 0) close(sounddev); + close(mixerdev); + gp2x_usbjoy_deinit(); +} + +/* video */ +void gp2x_video_flip(void) +{ + GdkPixbuf *pixbuf; + unsigned char *image; + int i; + + gdk_threads_enter(); + + image = malloc (320*240*3); + if (image == NULL) + { + gdk_threads_leave(); + return; + } + + if (current_bpp == 8) + { + unsigned char *pixels = gp2x_screen; + int pix; + + for (i = 0; i < 320*240; i++) + { + pix = current_pal[pixels[i]]; + image[3 * i + 0] = pix >> 16; + image[3 * i + 1] = pix >> 8; + image[3 * i + 2] = pix; + } + } + else + { + unsigned short *pixels = gp2x_screen; + + for (i = 0; i < 320*240; i++) + { + /* in: rrrr rggg gggb bbbb */ + /* out: rrrr r000 gggg gg00 bbbb b000 */ + image[3 * i + 0] = (pixels[i] >> 8) & 0xf8; + image[3 * i + 1] = (pixels[i] >> 3) & 0xfc; + image[3 * i + 2] = (pixels[i] << 3); + } + } + + pixbuf = gdk_pixbuf_new_from_data (image, GDK_COLORSPACE_RGB, + FALSE, 8, 320, 240, 320*3, finalize_image, NULL); + gtk_image_set_from_pixbuf (GTK_IMAGE (gtk_items.pixmap1), pixbuf); + g_object_unref (pixbuf); + + gdk_threads_leave(); +} + +void gp2x_video_changemode(int bpp) +{ + current_bpp = bpp; +} + +void gp2x_video_setpalette(int *pal, int len) +{ + memcpy(current_pal, pal, len*4); +} + +void gp2x_video_RGB_setscaling(int W, int H) +{ +} + +void gp2x_memcpy_all_buffers(void *data, int offset, int len) +{ + memcpy((char *)gp2x_screen + offset, data, len); +} + + +void gp2x_memset_all_buffers(int offset, int byte, int len) +{ + memset((char *)gp2x_screen + offset, byte, len); +} + + +/* sound */ +static int s_oldrate = 0, s_oldbits = 0, s_oldstereo = 0; + +void gp2x_start_sound(int rate, int bits, int stereo) +{ + int frag = 0, bsize, buffers; + + // if no settings change, we don't need to do anything + if (rate == s_oldrate && s_oldbits == bits && s_oldstereo == stereo) return; + + if (sounddev > 0) close(sounddev); + sounddev = open("/dev/dsp", O_WRONLY|O_ASYNC); + if (sounddev == -1) + printf("open(\"/dev/dsp\") failed with %i\n", errno); + + ioctl(sounddev, SNDCTL_DSP_SPEED, &rate); + ioctl(sounddev, SNDCTL_DSP_SETFMT, &bits); + ioctl(sounddev, SNDCTL_DSP_STEREO, &stereo); + // calculate buffer size + buffers = 16; + bsize = rate / 32; + if (rate > 22050) { bsize*=4; buffers*=2; } // 44k mode seems to be very demanding + while ((bsize>>=1)) frag++; + frag |= buffers<<16; // 16 buffers + ioctl(sounddev, SNDCTL_DSP_SETFRAGMENT, &frag); + printf("gp2x_set_sound: %i/%ibit/%s, %i buffers of %i bytes\n", + rate, bits, stereo?"stereo":"mono", frag>>16, 1<<(frag&0xffff)); + + s_oldrate = rate; s_oldbits = bits; s_oldstereo = stereo; +} + +void gp2x_sound_write(void *buff, int len) +{ + write(sounddev, buff, len); +} + +void gp2x_sound_volume(int l, int r) +{ + l=l<0?0:l; l=l>255?255:l; r=r<0?0:r; r=r>255?255:r; + l<<=8; l|=r; + ioctl(mixerdev, SOUND_MIXER_WRITE_PCM, &l); /*SOUND_MIXER_WRITE_VOLUME*/ +} + +/* joy */ +unsigned long gp2x_joystick_read(int allow_usb_joy) +{ + unsigned long value = current_keys; + int i; + + if (allow_usb_joy && num_of_joys > 0) { + // check the usb joy as well.. + gp2x_usbjoy_update(); + for (i = 0; i < num_of_joys; i++) + value |= gp2x_usbjoy_check(i); + } + + return value; +} + +/* 940 */ +int crashed_940 = 0; +void Pause940(int yes) +{ +} + +void Reset940(int yes) +{ +} + +/* faking gp2x cpuctrl.c */ +void cpuctrl_init(void) +{ +} + +void cpuctrl_deinit(void) +{ +} + +void set_FCLK(unsigned MHZ) +{ +} + +void Disable_940(void) +{ +} + +void gp2x_video_wait_vsync(void) +{ +} + +void set_RAM_Timings(int tRC, int tRAS, int tWR, int tMRD, int tRFC, int tRP, int tRCD) +{ +} + +void set_gamma(int g100) +{ +} + + +/* squidgehack.c */ +int mmuhack(void) +{ + return 0; +} + + +int mmuunhack(void) +{ + return 0; +} + + +/* misc */ +void spend_cycles(int c) +{ + usleep(c/*/200*/); +} + + + diff --git a/platform/linux/port_config.h b/platform/linux/port_config.h new file mode 100644 index 00000000..4f183c77 --- /dev/null +++ b/platform/linux/port_config.h @@ -0,0 +1,19 @@ +// port specific settings + +#ifndef PORT_CONFIG_H +#define PORT_CONFIG_H + +#define CPU_CALL + +// draw2.c +#define START_ROW 0 // which row of tiles to start rendering at? +#define END_ROW 28 // ..end + +// pico.c +#define CAN_HANDLE_240_LINES 1 + +#define dprintf(f,...) printf(f"\n",##__VA_ARGS__) +//#define dprintf(x...) + +#endif //PORT_CONFIG_H + diff --git a/platform/readme.txt b/platform/readme.txt new file mode 100644 index 00000000..dea6ec8d --- /dev/null +++ b/platform/readme.txt @@ -0,0 +1,301 @@ + +About +----- + +This version of PicoDrive is another enhanced version of Dave's +Megadrive / Genesis emulator for Pocket PC. The original Dave's code was +heavily modified (including Cyclone core), parts of it were rewritten in +asm, many features added, accuracy increased. This version is aimed at +ARM-based handheld devices, so ports exist for GP2X handheld console, +Symbian smartphones and PocketPC devices. + + +How to make it run +------------------ + +GP2X: +Copy PicoDrive.gpe, code940.bin and mmuhack.o to any place in your filesystem +(all 3 files must be in the same directory) and run PicoDrive.gpe. +Then load a ROM and enjoy! + +Symbian: +Select PicoDrive from application (tools) menu and run it. That's it! + +All: +If you have any problems (game does not boot, sound is glitchy, broken graphics), +make sure you enable "Accurate timing", "Emulate Z80" and then disable +"Fast renderer". This way you will get the best compatibility this emulator can +provide. + + +Configuration +------------- + +See config.txt file. + + +Problems / limitations +---------------------- + +* 32x, Sega CD, SVP are not emulated. +* Various VDP quirks (window bug, scroll size 2, etc.) are not emulated, + as very few games use this. +* Some games don't work or have glitches because of inaccurate timing and sync + between the emulated chips. + + +Credits +------- + +This emulator uses code from these people/projects: + +Dave +Cyclone 68000 core, Pico emulation library +Homepage: http://www.finalburn.com/ + +notaz +GP2X port, Cyclone 68000 hacks, lots of additional coding (see changelog). + +Reesy & FluBBa +DrZ80, the Z80 emulator written in ARM assembly. +Homepage: http://reesy.gp32x.de/ + +Tatsuyuki Satoh, Jarek Burczynski, MultiArcadeMachineEmulator development +software implementation of Yamaha FM sound generator + +MultiArcadeMachineEmulator (MAME) development +Texas Instruments SN76489 / SN76496 programmable tone /noise generator +Homepage: http://www.mame.net/ + + +Additional thanks +----------------- + +* Charles MacDonald (http://cgfm2.emuviews.com/) for old but still very useful + info about genesis hardware. +* Stéphane Dallongeville for creating Gens and making it open-source. +* Steve Snake for all that he has done for Genesis emulation scene. +* Bart Trzynadlowski for his SSFII and 68000 docs. +* Haze for his research (http://haze.mameworld.info). +* Mark and Jean-loup for zlib library. +* Anyone else I forgot. You know who you are. + +GP2X: +* rlyeh and all the other people behind the minimal library. +* Squidge for his famous squidgehack(tm). +* Dzz for his ARM940 sample code. +* GnoStiC & Puck2099 for USB joystick support. +* Hermes PS2R, god_at_hell for the CpuCtrl library. +* craigix for supplying the GP2X hardware and making this port possible. + +Symbian: +* Peter van Sebille for his various open-source Symbian projects to learn from. +* Steve Fischer for his open-source Motorola projects. +* The development team behind "Symbian GCC Improvement Project" + (http://www.inf.u-szeged.hu/symbian-gcc/) for their updated pre-SymbianOS9 + compile tools. +* AnotherGuest for all his Symbian stuff and support. +* Inder for the icons. + + +Changelog +--------- +0.964 + * GP2X: Fixed a sound buffer underflow issue on lower sample rate modes, which was + happening for NTSC games and causing sound clicks. + * GP2X: Redone key config to better support USB joysticks (now multiple joysticks + should be useable and configurable). + + GP2X: Added save confirmation option. + + GP2X: Added 940 CPU crash detection. + + ALL: UIQ3 port added. + +0.963 + * GP2X: Gamma-reset-on-entering-menu bug fixed. + * GP2X: Recompiled PicoDrive with gcc profiling option set as described here: + http://www.gp32x.com/board/index.php?showtopic=28490 + +0.962 + * GP2X: Fixed an issue with incorrect sounds in some games when dualcore operation + was enabled (for example punch sound in SOR). + * GP2X: Limited max volume to 90, because higher values often cause distortions. + * GP2X: Fixed a bug with lower res scaling. + * GP2X: Gamma is now reset on exit. + +0.96 + * ALL: Severely optimized MAME's YM2612 core, part of it is now rewritten in asm. + + GP2X: The YM2612's code now can be run in GP2X's ARM940T CPU, what causes large + performance increase. + * ALL: Accurate renderers are slightly faster now. + + GP2X: Using quadruple buffering instead of doublebuffer now, also updated + framelimitter, this should eliminate some scrolling and tearing problems. + * GP2X: Fixed some flickering issues of 8bit accurate renderer. + + GP2X: craigix's RAM timings now can be enabled in the menu (see advanced options). + + GP2X: Added ability to save config for specific games only. + + GP2X: Gamma control added (using GP2X's hardware capabilities for this). + * GP2X: Volume keys are now configurable. + + GP2X: GnoStiC added USB joystick support, I made it possible to use it for + player 2 control (currently untested). + * GP2X: squidgehack is now applied through kernel module (cleaner way). + +0.95 + * ALL: Fixed a bug in sprite renderer which was causing slowdowns for some games. + + GP2X: Added command line support + + GP2X: Added optional hardware scaling for lower-res games like Shining Force. + * ALL: Sound chips are now sampled 2 times per frame. This fixed some games which + had missing sounds (Vectorman 2 1st level, Thunder Force 3 water level, + etc.). + + ALL: Added another accurate 8-bit renderer which is slightly faster and made it + default. + +0.945 + + GP2X: Added frame limiter for frameskipped modes. + * GP2X: Increased brightness a bit (unused pixel bits now also contain data). + * GP2X: Suidgehack was not applied correctly (was applied before allocating some + high memory and had no effect). + +0.94 + + Added GP2X port. + * Improved interrupt timing, Mazin Saga and Burning Force now works. + * Rewritten renderer code to better suit GP2X, should be faster on other + ports too. + + Added support for banking used by 12-in-1 and 4-in-1 ROMs (thanks Haze). + + Added some protection device faking, used by some unlicensed games like + Super Bubble Bobble, King of Fighters, Elf Wor, ... (thanks to Haze again) + + Added primitive Virtua Racing SVP faking, so menus can be seen now. + +0.93 + * Fixed a problem with P900/P910 key configuration in FC mode. + * Improved shadow/hilight mode emulation. Still not perfect, but should be + enough for most games. + + Save state slots added. + + Region selector added. + +0.92 + VDP changes: + * VDP emulation is now more accurate (fixes flickering in Chase HQ II, + Super Hang-On and some other problems in other games). + * HV counter emulation is now much more accurate. Fixes the Asterix games, + line in Road Rash 3, etc. + * Minor sprite and layer scroll masking bugs fixed. + + Added partial interlace mode renderer (Sonic 2 vs mode) + * Fixed a crash in both renderers when certain size window layers were used. + + Added emulation of shadow/hilight operator sprites. Other shadow/hilight + effects are still unemulated. + + Sprite emulation is more accurate, sprite limit is emulated. + + Added "accurate sprites" option, which always draws sprites in correct + order and emulates sprite collision bit, but is significantly slower. + + Emulation changes: + * Improved interrupt handling, added deferred interrupt emulation + (Lemmings, etc). + + Added serial EEPROM SRAM support (Wonder Boy in Monster World, + Megaman - The Wily Wars and many EA sports games like NBA Jam). + + Implemented ROM banking for Super Street Fighter II - The New Challengers + * Updated to the latest version of DrZ80 core, integrated memory handlers + in it for better performance. A noticeable performance increase, but save + states may not work from the previous version (you can only use them with + sound disabled in that case). + + SRAM word read handler was using incorrect byte order, fixed. + + Changes in Cyclone 0.0086: + + Added missing CHK opcode handler (used by SeaQuest DSV). + + Added missing TAS opcode handler (Gargoyles,Bubba N Stix,...). As in real genesis, + memory write-back phase is ignored (but can be enabled in config.h if needed). + + Added missing NBCD and TRAPV opcode handlers. + + Added missing addressing mode for CMP/EOR. + + Added some minor optimizations. + - Removed 216 handlers for 2927 opcodes which were generated for invalid addressing modes. + + Fixed flags for ASL, NEG, NEGX, DIVU, ADDX, SUBX, ROXR. + + Bugs fixed in MOVEP, LINK, ADDQ, DIVS handlers. + * Undocumented flags for CHK, ABCD, SBCD and NBCD are now emulated the same way as in Musashi. + + Added Uninitialized Interrupt emulation. + + Altered timing for about half of opcodes to match Musashi's. + +0.80 + * Nearly all VDP code was rewritten in ARM asm. Gives ~10-25% performance + increase (depends on game). + * Optimized 32-column renderer not to render tiles offscreen, games which + use 32-column display (like Shining Force) run ~50% faster. + + Added new "Alternative renderer", which gives another ~30-45% performance + increase (in addition to mentioned above), but works only with some games, + because it is missing some features (it uses tile-based renderering + instead of default line-based and disables H-ints). + + Added "fit2" display mode for all FC gamers. It always uses 208x146 for + P800 and 208x208 for all other phones. + + Added volume control for Motorolas (experimental). + + VDP changes: + + Added support for vertical window (used by Vapor Trail, Mercs, GRIND + Stormer and others). + + Added sprite masking (hiding), adds some speed. + + Added preliminary H counter emulation. Comix Zone and Sonic 3D Blast + special stage are now playable. + + Added column based vertical scrolling (Gunstar Heroes battleship level, + Sonic and Knuckles lava boss, etc). + + Emulation changes: + + Re-added and improved Z80 faking when Z80 is disabled. Many games now can + be played without enabling Z80 (Lost Vikings, Syndicate, etc), but some + still need it (International Superstar Soccer Deluxe). + * Improved ym2612 timers, Outrun music plays at correct speed, voices in + Earthworm Jim play better, more games play sound. + * I/O registers now remember their values (needed for Pirates! Gold) + + Added support for 6 button pad. + + Changes in Cyclone 0.0083wip: + + Added missing CHK opcode (used by SeaQuest DSV). + + Added missing TAS opcode (Gargoyles). As in real genesis, write-back phase + is ignored (but is enabled for other systems). + + Backported stuff from Snes9x: + * Fixed Pxxx jog up/down which were not working in game. + + Added an option to gzip save states to save space. + + The emulator now pauses whenever it is loosing focus, so it will now pause + when alarm/ponecall/battery low/... windows come up. + - Removed 'pause on phonecall' feature, as it is no longer needed. + + Video fix for asian A1000s. + +0.70 + * Started using tools from "Symbian GCC Improvement Project", which give + considerable speed increase (~4fps in "center 90" mode). + * Rewrote some drawing routines in ARM assembly (gives ~6 more fps in + "center 90" mode). + * Minor improvement to 0 and 180 "fit" modes. Now they look slightly better + and are faster. + * Minor stability improvements (emulator is less likely to crash). + + Added some background for OSD text for better readability. + + Added Pal/NTSC detection. This is needed for proper sound speed. + + Implemented Reesy's DrZ80 Z80 emu. Made some changes to it with hope to make + it faster. + + Implemented ym2612 emu from the MAME project. Runs well but sometimes sounds + a bit weird. Could be a little faster, so made some changes too. + + Implemented SN76489 emu from the MAME project. + + Added two separate sound output methods (mediaserver and cmaudiofb) with + autodetection (needs testing). + * Fixed VDP DMA fill emulation (as described in Charles MacDonald's docs), + fixes Contra and some other games. + +0.301 + Launcher: + * Launcher now starts emulation process from current directory, + not from hardcoded paths. + * Improved 'pause on call' feature, should hopefully work with Motorola phones. + +0.30 + Initial release. + + +Disclaimer +---------- + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/platform/s60/.rnd b/platform/s60/.rnd new file mode 100644 index 00000000..e4fb9632 Binary files /dev/null and b/platform/s60/.rnd differ diff --git a/platform/s60/ABLD.BAT b/platform/s60/ABLD.BAT new file mode 100644 index 00000000..60cb1556 --- /dev/null +++ b/platform/s60/ABLD.BAT @@ -0,0 +1,15 @@ +@ECHO OFF + +REM Bldmake-generated batch file - ABLD.BAT +REM ** DO NOT EDIT ** + +perl -S ABLD.PL \PICODRIVE\S60\ %1 %2 %3 %4 %5 %6 %7 %8 %9 +if errorlevel==1 goto CheckPerl +goto End + +:CheckPerl +perl -v >NUL +if errorlevel==1 echo Is Perl, version 5.003_07 or later, installed? +goto End + +:End diff --git a/platform/s60/PICO.SUP.MAKE b/platform/s60/PICO.SUP.MAKE new file mode 100644 index 00000000..1633c626 --- /dev/null +++ b/platform/s60/PICO.SUP.MAKE @@ -0,0 +1,16 @@ + +PATH=\s60v1\epoc32\tools\;\s60v1\epoc32\gcc\bin\;C:\winnt\system32;C:\winnt;C:\winnt\System32\Wbem;C:\Program Files\ATI Technologies\ATI Control Panel;C:\Program Files\Common Files\Adaptec Shared\System;C:\Perl\bin;\s60v1\epoc32\tools;c:\MSVC6\VC98\Bin;C:\s60v1\epoc32\tools\nokia_compiler\Symbian_Tools\Command_Line_Tools;C:\Program Files\CSL Arm Toolchain\arm-none-symbianelf\bin;C:\Program Files\CSL Arm Toolchain\bin + +# EPOC DEFINITIONS + +EPOCBLD = \s60v1\EPOC32\BUILD\PICODRIVE\S60\PICO\WINS\ # +EPOCTRG = \s60v1\EPOC32\RELEASE\WINS\ # +EPOCLIB = \s60v1\EPOC32\RELEASE\WINS\ # +EPOCLINK = \s60v1\EPOC32\RELEASE\WINS\ # +EPOCSTATLINK = \s60v1\EPOC32\RELEASE\WINS\ # + + +RECREATEWORKSPACE : + cd \PICODRIVE\S60 + perl -S makmake.pl -D \PICODRIVE\S60\PICO.MMP VC6 + diff --git a/platform/s60/PICODRIVES60.DSP b/platform/s60/PICODRIVES60.DSP new file mode 100644 index 00000000..84d2ffd5 --- /dev/null +++ b/platform/s60/PICODRIVES60.DSP @@ -0,0 +1,152 @@ +# Microsoft Developer Studio Project File - Name="PICODRIVE" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=PICODRIVE - Win32 Uni Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "PICODRIVE.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "PICODRIVE.mak" CFG="PICODRIVE - Win32 Uni Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "PICODRIVE - Win32 Uni Release" (based on\ + "Win32 (x86) Dynamic-Link Library") +!MESSAGE "PICODRIVE - Win32 Uni Debug" (based on\ + "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "PICODRIVE - Win32 Uni Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\Win32_U0" +# PROP BASE Intermediate_Dir ".\Win32_U0" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "\s60v1\EPOC32\RELEASE\WINS\UDEB" +# PROP Intermediate_Dir "\s60v1\EPOC32\BUILD\PICODRIVE\S60\PICODRIVES60\WINS\UDEB" +# ADD CPP /nologo /Zp4 /MDd /W4 /Zi /Od /X /I "\PICODRIVE\PICO" /I "\PICODRIVE\PICO\SOUND" /I "\PICODRIVE\S60" /I "\PICODRIVE" /I "\s60v1\EPOC32\INCLUDE" /I "\s60v1\EPOC32\INCLUDE\LIBC" /D "__SYMBIAN32__" /D "__VC32__" /D "__WINS__" /D "__AVKON_ELAF__" /D "__DLL__" /D "_DEBUG" /D "_UNICODE" /FR /Fd"\s60v1\EPOC32\RELEASE\WINS\UDEB\Z\SYSTEM\APPS\PICODRIVES60\PICODRIVE.PDB" /GF /c +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /machine:IX86 +# ADD LINK32 "\s60v1\EPOC32\RELEASE\WINS\UDEB\EDLL.LIB" "\s60v1\EPOC32\RELEASE\WINS\UDEB\pico.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\a68k.obj" "\s60v1\EPOC32\RELEASE\WINS\UDEB\mz80_asm.obj" "\s60v1\EPOC32\RELEASE\WINS\UDEB\cone.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\eikcore.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\mediaclientaudiostream.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\euser.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\zlib.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\efsrv.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\estlib.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\fbscli.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\estor.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\eikcoctl.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\ws32.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\avkon.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\bafl.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\bitgdi.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\eikdlg.lib" "\s60v1\EPOC32\BUILD\PICODRIVE\S60\PICODRIVES60\WINS\UDEB\PICODRIVE.exp" /nologo /entry:"_E32Dll" /subsystem:windows /dll /pdb:"\s60v1\EPOC32\RELEASE\WINS\UDEB\Z\SYSTEM\APPS\PICODRIVES60\PICODRIVE.pdb" /debug /machine:IX86 /nodefaultlib /include:"?_E32Dll@@YGHPAXI0@Z" /out:"\s60v1\EPOC32\RELEASE\WINS\UDEB\Z\SYSTEM\APPS\PICODRIVES60\PICODRIVE.DLL" /WARN:3 +# SUBTRACT LINK32 /pdb:none +# Begin Special Build Tool +SOURCE=$(InputPath) +PreLink_Cmds=echo Doing first-stage link by name\ + nmake -nologo -f "\PICODRIVE\S60\PICODRIVES60.SUP.MAKE" PRELINKUDEB\ + if errorlevel 1 nmake -nologo -f "\PICODRIVE\S60\PICODRIVES60.SUP.MAKE" STOPLINKUDEB +PostBuild_Cmds=nmake -nologo -f "\PICODRIVE\S60\PICODRIVES60.SUP.MAKE" POSTBUILDUDEB +# End Special Build Tool + +!ELSEIF "$(CFG)" == "PICODRIVE - Win32 Uni Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\Win32_Un" +# PROP BASE Intermediate_Dir ".\Win32_Un" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "\s60v1\EPOC32\RELEASE\WINS\UREL" +# PROP Intermediate_Dir "\s60v1\EPOC32\BUILD\PICODRIVE\S60\PICODRIVES60\WINS\UREL" +# ADD CPP /nologo /Zp4 /MD /W4 /O1 /Op /X /I "\PICODRIVE\PICO" /I "\PICODRIVE\PICO\SOUND" /I "\PICODRIVE\S60" /I "\PICODRIVE" /I "\s60v1\EPOC32\INCLUDE" /I "\s60v1\EPOC32\INCLUDE\LIBC" /D "__SYMBIAN32__" /D "__VC32__" /D "__WINS__" /D "__AVKON_ELAF__" /D "__DLL__" /D "NDEBUG" /D "_UNICODE" /GF /c +# ADD MTL /nologo /mktyplib203 /D /win32 +# ADD BASE RSC /l 0x809 +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /machine:IX86 +# ADD LINK32 "\s60v1\EPOC32\RELEASE\WINS\UREL\EDLL.LIB" "\s60v1\EPOC32\RELEASE\WINS\UREL\pico.lib" "\s60v1\EPOC32\RELEASE\WINS\UREL\a68k.obj" "\s60v1\EPOC32\RELEASE\WINS\UREL\mz80_asm.obj" "\s60v1\EPOC32\RELEASE\WINS\UDEB\cone.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\eikcore.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\mediaclientaudiostream.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\euser.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\zlib.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\efsrv.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\estlib.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\fbscli.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\estor.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\eikcoctl.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\ws32.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\avkon.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\bafl.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\bitgdi.lib" "\s60v1\EPOC32\RELEASE\WINS\UDEB\eikdlg.lib" "\s60v1\EPOC32\BUILD\PICODRIVE\S60\PICODRIVES60\WINS\UREL\PICODRIVE.exp" /nologo /entry:"_E32Dll" /subsystem:windows /dll /machine:IX86 /nodefaultlib /include:"?_E32Dll@@YGHPAXI0@Z" /out:"\s60v1\EPOC32\RELEASE\WINS\UREL\Z\SYSTEM\APPS\PICODRIVES60\PICODRIVE.DLL" /WARN:3 +# Begin Special Build Tool +SOURCE=$(InputPath) +PreLink_Cmds=echo Doing first-stage link by name\ + nmake -nologo -f "\PICODRIVE\S60\PICODRIVES60.SUP.MAKE" PRELINKUREL\ + if errorlevel 1 nmake -nologo -f "\PICODRIVE\S60\PICODRIVES60.SUP.MAKE" STOPLINKUREL +PostBuild_Cmds=nmake -nologo -f "\PICODRIVE\S60\PICODRIVES60.SUP.MAKE" POSTBUILDUREL +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "PICODRIVE - Win32 Uni Debug" +# Name "PICODRIVE - Win32 Uni Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=\PICODRIVE\Unzip.c +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\S60\Picodrive.uid.cpp +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\S60\Picodriveexe.cpp +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\S60\Picodrives60.mmp +# PROP Exclude_From_Build 1 +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=\PICODRIVE\PICO\Ggenie.h +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\PICO\Pico.h +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\Unzip.h +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\S60\Normalvideo.inl +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\S60\Interpolatevideo.inl +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\S60\Picodriveexe.h +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\PICO\Picoint.h +# End Source File +# End Group +# End Target +# End Project diff --git a/platform/s60/PICODRIVES60.SUP.MAKE b/platform/s60/PICODRIVES60.SUP.MAKE new file mode 100644 index 00000000..d3fecd0d --- /dev/null +++ b/platform/s60/PICODRIVES60.SUP.MAKE @@ -0,0 +1,169 @@ + +PATH=\s60v1\epoc32\tools\;\s60v1\epoc32\gcc\bin\;C:\winnt\system32;C:\winnt;C:\winnt\System32\Wbem;C:\Program Files\ATI Technologies\ATI Control Panel;C:\Program Files\Common Files\Adaptec Shared\System;C:\Perl\bin;\s60v1\epoc32\tools;c:\MSVC6\VC98\Bin;C:\s60v1\epoc32\tools\nokia_compiler\Symbian_Tools\Command_Line_Tools;C:\Program Files\CSL Arm Toolchain\arm-none-symbianelf\bin;C:\Program Files\CSL Arm Toolchain\bin + +# EPOC DEFINITIONS + +EPOCBLD = \s60v1\EPOC32\BUILD\PICODRIVE\S60\PICODRIVES60\WINS\ # +EPOCTRG = \s60v1\EPOC32\RELEASE\WINS\ # +EPOCLIB = \s60v1\EPOC32\RELEASE\WINS\ # +EPOCLINK = \s60v1\EPOC32\RELEASE\WINS\ # +EPOCSTATLINK = \s60v1\EPOC32\RELEASE\WINS\ # + +EPOCBLDUDEB = $(EPOCBLD)UDEB +EPOCTRGUDEB = $(EPOCTRG)UDEB +EPOCLIBUDEB = $(EPOCLIB)UDEB +EPOCLINKUDEB = $(EPOCLINK)UDEB +EPOCSTATLINKUDEB = $(EPOCSTATLINK)UDEB + +EPOCBLDUREL = $(EPOCBLD)UREL +EPOCTRGUREL = $(EPOCTRG)UREL +EPOCLIBUREL = $(EPOCLIB)UDEB +EPOCLINKUREL = $(EPOCLINK)UDEB +EPOCSTATLINKUREL = $(EPOCSTATLINK)UREL + + +TRGDIR = Z\SYSTEM\APPS\PICODRIVES60 + +DATADIR = Z\SYSTEM\DATA + +LIBRARY : + @echo WARNING: Not attempting to create "$(EPOCLIB)UDEB\PICODRIVE.LIB". + @echo When exports are frozen in "\PICODRIVE\BWINS\PICODRIVEU.DEF", regenerate Makefile. + + +# REAL TARGET - IMPORT LIBRARY + +"$(EPOCLIB)UDEB\PICODRIVE.LIB" : "\PICODRIVE\BWINS\PICODRIVEU.DEF" MAKEWORKLIBRARY + lib.exe /nologo /machine:i386 /nodefaultlib /name:"PICODRIVE.DLL" /def:"\PICODRIVE\BWINS\PICODRIVEU.DEF" /out:"$(EPOCLIB)UDEB\PICODRIVE.LIB" + del "$(EPOCLIB)UDEB\PICODRIVE.exp" + + +MAKEWORKLIBRARY : "\s60v1\EPOC32\RELEASE\WINS\UDEB" + +"\s60v1\EPOC32\RELEASE\WINS\UDEB" : + @perl -S emkdir.pl "\s60v1\EPOC32\RELEASE\WINS\UDEB" + + +# BUILD - UDEB + +LIBS= \ + "$(EPOCSTATLINKUDEB)\PICO.LIB" \ + "$(EPOCSTATLINKUDEB)\A68K.OBJ" \ + "$(EPOCSTATLINKUDEB)\MZ80_ASM.OBJ" \ + "$(EPOCLINKUDEB)\CONE.LIB" \ + "$(EPOCLINKUDEB)\EIKCORE.LIB" \ + "$(EPOCLINKUDEB)\MEDIACLIENTAUDIOSTREAM.LIB" \ + "$(EPOCLINKUDEB)\EUSER.LIB" \ + "$(EPOCLINKUDEB)\ZLIB.LIB" \ + "$(EPOCLINKUDEB)\EFSRV.LIB" \ + "$(EPOCLINKUDEB)\ESTLIB.LIB" \ + "$(EPOCLINKUDEB)\FBSCLI.LIB" \ + "$(EPOCLINKUDEB)\ESTOR.LIB" \ + "$(EPOCLINKUDEB)\EIKCOCTL.LIB" \ + "$(EPOCLINKUDEB)\WS32.LIB" \ + "$(EPOCLINKUDEB)\AVKON.LIB" \ + "$(EPOCLINKUDEB)\BAFL.LIB" \ + "$(EPOCLINKUDEB)\BITGDI.LIB" \ + "$(EPOCLINKUDEB)\EIKDLG.LIB" + +LINK_OBJS= \ + "$(EPOCBLDUDEB)\PICODRIVE.UID.obj" \ + "$(EPOCBLDUDEB)\PICODRIVEEXE.obj" \ + "$(EPOCBLDUDEB)\UNZIP.obj" + +STAGE1_LINK_FLAGS="$(EPOCSTATLINKUDEB)\EDLL.LIB" \ + $(LIBS) /nologo /entry:"_E32Dll" /subsystem:windows /dll /debug \ + /incremental:no /machine:IX86 /nodefaultlib /include:"?_E32Dll@@YGHPAXI0@Z" /out:"$(EPOCBLDUDEB)\PICODRIVE.DLL" /WARN:3 + +PRELINKUDEB : $(LINK_OBJS) "$(EPOCSTATLINKUDEB)\EDLL.LIB" $(LIBS) + link.exe @<< + $(STAGE1_LINK_FLAGS) $(LINK_OBJS) +<< + del "$(EPOCBLDUDEB)\PICODRIVE.DLL" + del "$(EPOCBLDUDEB)\PICODRIVE.exp" + dumpbin /exports /out:"$(EPOCBLDUDEB)\PICODRIVE.inf" "$(EPOCBLDUDEB)\PICODRIVE.lib" + del "$(EPOCBLDUDEB)\PICODRIVE.lib" + perl -S makedef.pl -Inffile "$(EPOCBLDUDEB)\PICODRIVE.inf" "$(EPOCBLD)PICODRIVE.def" + del "$(EPOCBLDUDEB)\PICODRIVE.inf" + lib.exe /nologo /machine:i386 /nodefaultlib /name:"PICODRIVE.DLL" /def:"$(EPOCBLD)PICODRIVE.def" /out:"$(EPOCBLDUDEB)\PICODRIVE.lib" + del "$(EPOCBLDUDEB)\PICODRIVE.lib" + @echo First-stage link successful + + +STOPLINKUDEB : DELEXPOBJUDEB + @echo Stopped the build by removing the export object, + @echo if present, because the pre-link stage failed + + +POSTBUILDUDEB : DELEXPOBJUDEB LIBRARY + + +DELEXPOBJUDEB : + if exist "$(EPOCBLDUDEB)\PICODRIVE.exp" del "$(EPOCBLDUDEB)\PICODRIVE.exp" + + + +# BUILD - UREL + +LIBS= \ + "$(EPOCSTATLINKUREL)\PICO.LIB" \ + "$(EPOCSTATLINKUREL)\A68K.OBJ" \ + "$(EPOCSTATLINKUREL)\MZ80_ASM.OBJ" \ + "$(EPOCLINKUREL)\CONE.LIB" \ + "$(EPOCLINKUREL)\EIKCORE.LIB" \ + "$(EPOCLINKUREL)\MEDIACLIENTAUDIOSTREAM.LIB" \ + "$(EPOCLINKUREL)\EUSER.LIB" \ + "$(EPOCLINKUREL)\ZLIB.LIB" \ + "$(EPOCLINKUREL)\EFSRV.LIB" \ + "$(EPOCLINKUREL)\ESTLIB.LIB" \ + "$(EPOCLINKUREL)\FBSCLI.LIB" \ + "$(EPOCLINKUREL)\ESTOR.LIB" \ + "$(EPOCLINKUREL)\EIKCOCTL.LIB" \ + "$(EPOCLINKUREL)\WS32.LIB" \ + "$(EPOCLINKUREL)\AVKON.LIB" \ + "$(EPOCLINKUREL)\BAFL.LIB" \ + "$(EPOCLINKUREL)\BITGDI.LIB" \ + "$(EPOCLINKUREL)\EIKDLG.LIB" + +LINK_OBJS= \ + "$(EPOCBLDUREL)\PICODRIVE.UID.obj" \ + "$(EPOCBLDUREL)\PICODRIVEEXE.obj" \ + "$(EPOCBLDUREL)\UNZIP.obj" + +STAGE1_LINK_FLAGS="$(EPOCSTATLINKUREL)\EDLL.LIB" \ + $(LIBS) /nologo /entry:"_E32Dll" /subsystem:windows /dll \ + /incremental:no /machine:IX86 /nodefaultlib /include:"?_E32Dll@@YGHPAXI0@Z" /out:"$(EPOCBLDUREL)\PICODRIVE.DLL" /WARN:3 + +PRELINKUREL : $(LINK_OBJS) "$(EPOCSTATLINKUREL)\EDLL.LIB" $(LIBS) + link.exe @<< + $(STAGE1_LINK_FLAGS) $(LINK_OBJS) +<< + del "$(EPOCBLDUREL)\PICODRIVE.DLL" + del "$(EPOCBLDUREL)\PICODRIVE.exp" + dumpbin /exports /out:"$(EPOCBLDUREL)\PICODRIVE.inf" "$(EPOCBLDUREL)\PICODRIVE.lib" + del "$(EPOCBLDUREL)\PICODRIVE.lib" + perl -S makedef.pl -Inffile "$(EPOCBLDUREL)\PICODRIVE.inf" "$(EPOCBLD)PICODRIVE.def" + del "$(EPOCBLDUREL)\PICODRIVE.inf" + lib.exe /nologo /machine:i386 /nodefaultlib /name:"PICODRIVE.DLL" /def:"$(EPOCBLD)PICODRIVE.def" /out:"$(EPOCBLDUREL)\PICODRIVE.lib" + del "$(EPOCBLDUREL)\PICODRIVE.lib" + @echo First-stage link successful + + +STOPLINKUREL : DELEXPOBJUREL + @echo Stopped the build by removing the export object, + @echo if present, because the pre-link stage failed + + +POSTBUILDUREL : DELEXPOBJUREL LIBRARY + + +DELEXPOBJUREL : + if exist "$(EPOCBLDUREL)\PICODRIVE.exp" del "$(EPOCBLDUREL)\PICODRIVE.exp" + + + + +RECREATEWORKSPACE : + cd \PICODRIVE\S60 + perl -S makmake.pl -D \PICODRIVE\S60\PICODRIVES60.MMP VC6 + diff --git a/platform/s60/PicoDrive.UID.CPP b/platform/s60/PicoDrive.UID.CPP new file mode 100644 index 00000000..b9d9b8f7 --- /dev/null +++ b/platform/s60/PicoDrive.UID.CPP @@ -0,0 +1,5 @@ +// Makmake-generated uid source file +#include +#pragma data_seg(".E32_UID") +__WINS_UID(0x1000007a,0x00000000,0x00000000) +#pragma data_seg() diff --git a/platform/s60/PicoDrive.rss b/platform/s60/PicoDrive.rss new file mode 100644 index 00000000..660e9e9a --- /dev/null +++ b/platform/s60/PicoDrive.rss @@ -0,0 +1,136 @@ +// PicoDriveS60.RSS +// +// + +NAME PICO +#include +#include +#include +#include +RESOURCE RSS_SIGNATURE { } + +RESOURCE TBUF16 { buf=""; } + +RESOURCE EIK_APP_INFO + { + menubar = r_pico_menubar; + } + +RESOURCE MENU_BAR r_pico_menubar // *** Menu bar +{ + titles = + { + }; +} + +RESOURCE ARRAY r_picodrive_keys +{ +items= +{ + LBUF{txt="Up";}, + LBUF{txt="Down";}, + LBUF{txt="Left";}, + LBUF{txt="Right";}, + LBUF{txt="A";}, + LBUF{txt="B";}, + LBUF{txt="C";}, + LBUF{txt="X";}, + LBUF{txt="Y";}, + LBUF{txt="Z";}, + LBUF{txt="Mode";}, + LBUF{txt="Start";}, + LBUF{txt="Up&Left";}, + LBUF{txt="Up&Right";}, + LBUF{txt="Down&Right";}, + LBUF{txt="Down&Left";}, + LBUF{txt="Soft reset";}, + LBUF{txt="Pan left";}, + LBUF{txt="Pan right";} + }; + } + + + +RESOURCE DIALOG r_pico_file_select_dialog +{ +flags = EGeneralQueryFlags; +buttons = R_AVKON_SOFTKEYS_DONE_CANCEL; +items = +{ +DLG_LINE +{ +type = EAknCtListQueryControl; +id = EListQueryControl; + +control = AVKON_LIST_QUERY_CONTROL +{ +heading = "Files"; +listtype = EAknCtSinglePopupMenuListBox; +listbox = LISTBOX +{ +flags = EAknDialogSelectionList; +height = 3; +width = 1; +}; +}; +} +}; +} + +RESOURCE DIALOG r_pico_add_cheat +{ + title="Add cheatcode"; + flags=EEikDialogFlagNoDrag | + EEikDialogFlagCbaButtons | + EEikDialogFlagModeless|EEikDialogFlagWait; + buttons = R_AVKON_SOFTKEYS_OK_CANCEL; + items= + { + DLG_LINE + { + type=EEikCtLabel; + id=0x2002; + itemflags = EEikDlgItemNonFocusing; + control= LABEL + + { + txt = "Enter cheatcode"; + + }; + }, + DLG_LINE + { + itemflags = EEikDlgItemNonFocusing; + id=0x2001; + type=EEikCtLabel; + control= LABEL { + horiz_align=EEikLabelAlignHLeft; + txt = "\nGG: XXXX-XXXX\nPatch: XXXXXX:YYYY"; + }; + }, + DLG_LINE + { + type=EEikCtEdwin; + id=0x2000; + itemflags = EEikDlgItemOfferAllHotKeys|EEikDlgItemSeparatorAfter; + + control= EDWIN { + maxlength=12; + }; + + + } + }; +} + +RESOURCE ARRAY r_picodrive_regions +{ + items= + { + LBUF{txt="Region: Auto";}, + LBUF{txt="Region: Jap NTSC";}, + LBUF{txt="Region: Jap PAL";}, + LBUF{txt="Region: US NTSC";}, + LBUF{txt="Region: EUR PAL";} + }; +} diff --git a/platform/s60/PicoDriveAppS60.mmp b/platform/s60/PicoDriveAppS60.mmp new file mode 100644 index 00000000..bb81c500 --- /dev/null +++ b/platform/s60/PicoDriveAppS60.mmp @@ -0,0 +1,31 @@ +// +// MAKEFILE.MMP for component PicoDrive S60 +// + +target PicoDriveS60.app +targetpath system\apps\PicoDriveS60 +targettype app + +UID 0x100039ce 0x101F9B49 +MACRO SERIES60 +SOURCEPATH ..\s60 +userinclude ..\s60 +systeminclude \epoc32\include \epoc32\include\libc ..\s60 + +// app source +source PicoDriveAppS60.cpp + +// libraries +library cone.lib eikcore.lib +library euser.lib apparc.lib +library efsrv.lib apgrfx.lib +library avkon.lib + + +//resource file +sourcepath ..\S60 +resource PicoDriveS60.rss + + +// Color Bitmap - UK only +AIF picodriveS60.aif ..\S60 picodriveS60aif.rss c12 PicoL.bmp PicoLm.bmp diff --git a/platform/s60/PicoDriveExe.Cpp b/platform/s60/PicoDriveExe.Cpp new file mode 100644 index 00000000..de576aa7 --- /dev/null +++ b/platform/s60/PicoDriveExe.Cpp @@ -0,0 +1,2495 @@ +#include +#include +#include +#include +#include +#include +#ifdef S60V3 +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#include "PicoDriveexe.h" +#include "pico.h" +#include "unzip.h" +#include "PicoInt.h" +#include "GGenie.h" + +TInt KLineGap = 2; +static const char* KAboutText = +"This emulator uses code from\n" +"these people/projects:\n" +"\n" +"Dave\n" +"Cyclone 68000 core,\n" +"Pico emulation library\n" +"Homepage:http://www.finalburn.com\n" +"E-mail: david(at)finalburn.com\n" +"\n" +"notaz\n" +"UIQ port,Cyclone 68000 hacks,some\n" +"additional coding (see changelog).\n" +"Homepage:http://notaz.atspace.com/\n" +"E-mail: notasas(at)gmail.com\n" +"\n" +"Reesy\n" +"DrZ80, the Z80 emulator\n" +"written in ARM assembly.\n" +"Homepage: http://reesy.gp32x.de/\n" +"E-mail:drsms_reesy(at)yahoo.co.uk\n" +"\n" +"Tatsuyuki Satoh, Jarek Burczynski,\n" +"MultiArcadeMachineEmulator\n" +"development\n" +"software implementation of\n" +"Yamaha FM sound generator\n" +"\n" +"MultiArcadeMachineEmulator(MAME)\n" +"development\n" +"Texas Instruments SN76489/SN76496\n" +"programmable tone/noise generator\n" +"Homepage: http://www.mame.net/\n" +"\n" +"Additional thanks\n" +"-----------------\n" +"* Peter van Sebille for ECompXL\n" +" and his various open-source\n" +" Symbian project to learn from.\n" +"* Mark and Jean-loup for zlib\n" +" library.\n" +"* Reesy for also finding some\n" +" Cyclone bugs.\n" +"* Charles MacDonald\n" +" (http://cgfm2.emuviews.com/)\n" +" for old but still very useful\n" +" info about genesis hardware.\n" +"* Stúphane Dallongeville\n" +" for creating Gens\n" +" (http://www.gens.ws)\n" +"*The development team behind the\n" +" Symbian GCC Improvement Project\n" +" http://www.inf.u-szeged.hu\n" +" /symbian-gcc/) for their updated\n" +" compiler tools.\n" +"* Inder for the icons.\n"; + +// Picodrive prefrence uid +const TUid KPicoDrivePrefs={0x1234432E}; + +// Bittable corresponding to the bitvalues for the different control actions +TUint16 KBitValTable[EPicoNoKeys]={1,2,4,8 ,64,16,32,1024,512,256,2048,128,5,9,10,6,0,0,0}; + +extern"C" unsigned short *framebuff = 0; // temporary buffer in sega native BGR format +const int framebuffsize = ((8+320)*(224+16))*2; // actual framebuffer size (in bytes+to support new rendering mode) + +// Colour lookuptable from BGR to RGB +unsigned short gColorMapTab[4096]; + +// Scaling line table +TUint8 gColumnStepTable[320]; +TUint8 gNarrowColumnStepTable[256]; +unsigned short gLineTable[240]; +TUint32 gLineOffsets[416]; +TUint32 gFullOffset; +extern int PsndLen; + +#ifndef S60V3 +GLDEF_C TInt E32Dll(TDllReason) +{ + return KErrNone; +} +#ifdef __WINS__ +_LIT(KLitResourceFileName, "z:\\system\\apps\\picodrives60\\PicoDriveS60.rsc"); +#else +_LIT(KLitResourceFileName, "PicoDriveS60.rsc"); +#endif + +#endif + +#ifdef __WINS__ +RHeap* gChunk; +#endif +struct Target Targ; + +#ifdef S60V3 +#include "S60V3Video.inl" +#else +#include "NormalVideo.inl" +#include "InterpolateVideo.inl" +#endif + +TInt CPicoDriveUi::AsyncUpdateL(TAny* aAppUi) +{ + static_cast(aAppUi)->UpdateScreen(); + return 0; +} + +void CPicoDriveUi::StartAsynchUpdate() +{ + TCallBack callback(AsyncUpdateL,iEikonEnv->EikAppUi()); + iAsyncUpdate.Cancel(); + iAsyncUpdate.Set(callback); + iAsyncUpdate.CallBack(); +} + + +CPicoDriveUi::CPicoDriveUi():iIdleCallBack(CActive::EPriorityIdle),iStartUp(CActive::EPriorityIdle), +iAsyncUpdate(CActive::EPriorityStandard) +{ + iCurrentScan=-1; + FramesPerSecond=60; + PicoOpt = 7; + iLastAboutPos = -1; + iFrameSkip = -1; + PsndRate = 8000; + iInterpolate = ETrue; + iSoundVolume = 6; + gFullOffset = 0; +} + +CPicoDriveUi::~CPicoDriveUi() +{ + delete iKeyNames; + delete iRegNames; + if(iView) + { + RemoveFromStack(iView); + delete iView; + } + delete iBackBuffer; + delete iSndStream; +#ifndef S60V3 + iCoeEnv->DeleteResourceFile(iResourceFileId); +#endif + +#ifdef __WINS__ + if(gChunk != NULL) + { + gChunk->Close(); + } +#endif + free(framebuff); + framebuff = 0; + CloseSTDLIB(); +} + +TKeyResponse CPicoDriveUi::HandleKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType) +{ + if(iCheatEnter) + { + return iCheatDlg->OfferKeyEventL(aKeyEvent,aType); + } + + if(aType==EEventKey && aKeyEvent.iScanCode==EStdKeyBackspace) + { + if(iPicoMenu ==ESelectSoundMenu) + { + if(iSndRateChanged) + { + if(!UpdatePSndRate()) // Not compatible.. reset to 8000 + { + PsndRate = 8000; + UpdatePSndRate(); + } + + if(iRomLoaded) + { + sound_rerate(); + } + } + + iView->Clear(); + iPicoMenu = EPicoMainMenu; + PutMainMenu(); + return EKeyWasConsumed; + } + else if (iPicoMenu == ESelectControlsMenu) + { + iView->Clear(); + iPicoMenu = EPicoMainMenu; + PutMainMenu(); + return EKeyWasConsumed; + } + else if(iPicoMenu == ESelectScrMenu) + { + iScrMode = iLastScrMode; + iView->Clear(); + iPicoMenu = EPicoMainMenu; + PutMainMenu(); + return EKeyWasConsumed; + } + else if(iPicoMenu == ESelectCheatMenu) + { + if(iCheatSelection<2) + { + iView->Clear(); + iPicoMenu = EPicoMainMenu; + PutMainMenu(); + } + else + { + TInt index = (iListOffset+iCheatSelection)-2; + TInt noFound = 0; + for(TInt i = 0; i < 256;i++) + { + if (Liste_GG[i].code[0] != 0) + { + noFound++; + if(noFound-1 == index) + { + Liste_GG[i].code[0] = 0; + Liste_GG[i].active = 0; + iNoCheats--; + iListOffset = 0; + iCheatSelection = 0; + break; + } + + } + } + + iView->Clear(); + PutCheatSelect(); + } + + return EKeyWasConsumed; + } + + if(!iEmuRunning && (iPicoMenu!=EPicoMainMenu ||iCurrentScan!=-1) ) + return EKeyWasNotConsumed; + + if(iRomLoaded ) + { + iEmuRunning=!iEmuRunning; + + if(iEmuRunning && iRomLoaded) + { + iView->Clear(); + TCallBack callback(StartEmulatorL,this); + iStartUp.Set(callback); + iStartUp.CallBack(); + } + } + return EKeyWasConsumed; + } + + if(!iEmuRunning) + { + if(iCurrentScan==-1) + { + if(aType==EEventKey) + { + + switch(aKeyEvent.iScanCode) // first determine bit value to change + { + case EStdKeyUpArrow: + switch(iPicoMenu) + { + case ESelectControlsMenu: + { + iCtrlSelection=!iCtrlSelection; + PutControllerSelect(); + }break; + case EPicoMainMenu: + if(iSelection>0) + iSelection--; + else iSelection=EExitPico; + PutMainMenu(); + break; + case ESelectScrMenu: + if(iScrMode>0) + iScrMode--; + else iScrMode=10; + PutScreenSelect(); + break; + case ESelectCheatMenu: + if(iCheatSelection>0) + iCheatSelection--; + else + iCheatSelection = ELastCheatItem-1; + PutCheatSelect(); + break; + case EAboutPicoMenu: + { + iView->Clear(); + PutAbout(); + }break; + case ESelectSoundMenu: + { + if(iSndSelection>0) + iSndSelection--; + else + iSndSelection = ELastSoundItem-1; + PutSoundSelect(); + }break; + } + break; + case EStdKeyDownArrow: + switch(iPicoMenu) + { + case ESelectControlsMenu: + { + iCtrlSelection=!iCtrlSelection; + PutControllerSelect(); + }break; + case EPicoMainMenu: + iSelection++; + if(iSelection==ELastMenuItem) + iSelection=0; + PutMainMenu(); + break; + case ESelectScrMenu: + iScrMode++; + if(iScrMode==11) + iScrMode=0; + PutScreenSelect(); + break; + case ESelectCheatMenu: + if(iCheatSelection<(ELastCheatItem+iNoCheats-1) && iCheatSelection<6) + iCheatSelection++; + else if(iCheatSelection == ELastCheatItem+4 && iListOffsetClear(); + PutAbout(); + }break; + case ESelectSoundMenu: + { + iSndSelection++; + if(iSndSelection==ELastSoundItem) + iSndSelection=0; + PutSoundSelect(); + }break; + } + break; + case EStdKeyDevice0: + case EStdKeyDevice3: + { + switch(iPicoMenu) + { + case ESelectControlsMenu: + { + if(iCtrlSelection == EConfigControls) + { + iPicoMenu = EPicoMainMenu; + iView->Clear(); + iCurrentScan=0; + PutConfigKeys(); + } + else + { + iEnableSixButtons = !iEnableSixButtons; + PicoOpt=PicoOpt^ 32; + + PutControllerSelect(); + } + }break; + case ESelectCheatMenu: + { + switch(iCheatSelection) + { + case EAddCheat: + { + TBuf8<16> cheatCode; + iCheatEnter = ETrue; + iCheatDlg = new (ELeave) CPicoAddCheatDlg(cheatCode); + iCheatDlg->SetMopParent(iEikonEnv->EikAppUi()); + TInt result = iCheatDlg->ExecuteLD(R_PICO_ADD_CHEAT); + + if(result == EEikBidOk) + { + for(TInt i = 0; i < 256;i++) + { + if (Liste_GG[i].code[0] == 0) + { + if(check_code((const char*) cheatCode.PtrZ(),i)) + { + decode( Liste_GG[i].code, (patch *) (&(Liste_GG[i].addr))); + + if ((Liste_GG[i].restore == 0xFFFFFFFF) && (Liste_GG[i].addr < Pico.romsize) && (iRomLoaded)) + { + Liste_GG[i].restore = (unsigned int) (Pico.rom[Liste_GG[i].addr] & 0xFF); + Liste_GG[i].restore += (unsigned int) ((Pico.rom[Liste_GG[i].addr + 1] & 0xFF) << 8); + } + iNoCheats++; + Liste_GG[i].active = 1; + } + break; // Found position free + } + } + } + iCheatDlg = NULL; + iCheatEnter = EFalse; + }break; + case EClearCheats: + { + iNoCheats = 0; + for(TInt i = 0; i < 256;i++) + { + Liste_GG[i].code[0] = 0; + Liste_GG[i].active = 0; + } + } + break; + default: + { + TInt index = (iListOffset+iCheatSelection)-2; + TInt noFound = 0; + for(TInt i = 0; i < 256;i++) + { + if (Liste_GG[i].code[0] != 0) + { + noFound++; + if(noFound-1 == index) + { + Liste_GG[i].active=!Liste_GG[i].active; + break; + } + + } + } + } + break; + + } + + PutCheatSelect(); + } + break; + case EAboutPicoMenu: + { + iView->Clear(); + PutAbout(); + }break; + case ESelectScrMenu: + { + + switch(iScrMode) + { + case 5: + iInterpolate = !iInterpolate; + iView->Clear(); + PutScreenSelect(); + break; + case 6: + iFrameSkip++; + if(iFrameSkip == 11) + { + iFrameSkip = -1; + } + iView->Clear(); + PutScreenSelect(); + break; + case 7: + PicoOpt = PicoOpt^0x40; + iView->Clear(); + PutScreenSelect(); + break; + case 8: + PicoOpt = PicoOpt^0x80; + iView->Clear(); + PutScreenSelect(); + break; + case 9: + PicoOpt = PicoOpt^0x10; + iView->Clear(); + PutScreenSelect(); + break; + case 10: + switch(PicoRegionOverride) + { + case 0: + default: + PicoRegionOverride = 1; + break; + case 1: + PicoRegionOverride = 2; + break; + case 2: + PicoRegionOverride = 4; + break; + case 4: + PicoRegionOverride = 8; + break; + case 8: + PicoRegionOverride = 0; + break; + } + + iView->Clear(); + PutScreenSelect(); + break; + default: + { + TBitmapUtil util(iBackBuffer); + util.Begin(TPoint(0,0)); + TSize sz=iBackBuffer->SizeInPixels(); + TInt dataSize=sz.iWidth*sz.iHeight*2; + TPtr8 ptr(reinterpret_cast(iBackBuffer->DataAddress()),dataSize,dataSize); + ptr.Fill(0); + util.End(); + iPicoMenu=EPicoMainMenu; + iView->Clear(); + PutMainMenu(); + TargetInit(); + SaveSettingsL(); + }break; + } + }break; + case ESelectSoundMenu: + { + switch(iSndSelection) + { + case EEnableZ80: + PicoOpt=PicoOpt^4; + break; + case EEnableYM2612: + PicoOpt=PicoOpt^1; + break; + case EEnableSN76496: + PicoOpt=PicoOpt^2; + break; + case ESoundVolume: + { + iSoundVolume++; + if(iSoundVolume==11) + { + iSoundVolume=0; + iEnableSound=EFalse; + } + else + { + iEnableSound=ETrue; + iSndStream->SetVolume((iSndStream->MaxVolume()*iSoundVolume)/10); + } + + if(!iEnableSound) + { + iSndStream->Stop(); + } + }break; + case ESoundRate: + { + iSndRateChanged = ETrue; + + switch(PsndRate) + { + case 8000: + PsndRate = 11025; + break; + case 11025: + PsndRate = 16000; + break; + case 16000: + PsndRate = 22050; + break; + case 22050: + PsndRate = 8000; + break; + } + }break; + } + PutSoundSelect(); + }break; + case EPicoMainMenu: + { + switch(iSelection) + { + case EResetHw: + { + if(!PicoReset(0)) + { + iEmuRunning=ETrue; + TCallBack callback(StartEmulatorL,this); + iStartUp.Set(callback); + iStartUp.CallBack(); + } + } + break; + case ELoadState: + { + if(iRomLoaded) + { + saveLoadGame(1,0); + iEmuRunning=ETrue; + iView->Clear(); + TCallBack callback(StartEmulatorL,this); + iStartUp.Set(callback); + iStartUp.CallBack(); + } + } + break; + case ESaveState: + { + if(iRomLoaded) + { + saveLoadGame(0,0); + iEmuRunning=ETrue; + iView->Clear(); + TCallBack callback(StartEmulatorL,this); + iStartUp.Set(callback); + iStartUp.CallBack(); + + } + } + break; + case ELoadRom: + { + TParsePtr parse(iRomName); + iRomName=parse.DriveAndPath(); + if(SelectFile(iRomName)) + { + SaveSettingsL(); + EmulateExit(); + TPtr8 ptr((unsigned char*)RomName,256); + ptr.Fill(0,256); + ptr.Copy(iRomName); + User::CompressAllHeaps(); + if(EmulateInit()==0) + { + if(Pico.m.pal) + { + FramesPerSecond=50; + } + else + { + FramesPerSecond=60; + } + + SetKeyBlockMode(ENoKeyBlock); + iEmuRunning=ETrue; + iRomLoaded=ETrue; + iView->Clear(); + TCallBack callback(StartEmulatorL,this); + iStartUp.Set(callback); + iStartUp.CallBack(); + } + else + { + iRomName=KNullDesC(); + iView->Clear(); + PutMainMenu(); + iRomLoaded=EFalse; + } + } + else + { + iView->Clear(); + PutMainMenu(); + } + } + break;//load rom + case ESetControls: + iPicoMenu = ESelectControlsMenu; + PutControllerSelect(); + break; + case ESetScreen: + iView->Clear(); + iLastScrMode = iScrMode; // In case of cancel + PutScreenSelect(); + iPicoMenu=ESelectScrMenu; + break; + case ESelectSound: + { + iSndRateChanged = EFalse; + iPicoMenu=ESelectSoundMenu; + PutSoundSelect(); + }break; + case ESelectCheat: + { + iPicoMenu=ESelectCheatMenu; + iListOffset = 0; + iNoCheats = 0; + for(TInt i = 0; i < 256;i++) + { + if (Liste_GG[i].code[0] != 0) + { + iNoCheats++; + if ((Liste_GG[i].restore != 0xFFFFFFFF) && (Liste_GG[i].addr < Pico.romsize) && (iRomLoaded)) + { + Pico.rom[Liste_GG[i].addr] = (unsigned char)(Liste_GG[i].restore & 0xFF); + Pico.rom[Liste_GG[i].addr + 1] = (unsigned char)((Liste_GG[i].restore & 0xFF00) >> 8); + } + + } + } + + PutCheatSelect(); + } + break; + case EAboutPico: + { + iView->Clear(); + PutAbout(); + iPicoMenu=EAboutPicoMenu; + }break; + case EExitPico: + { + SaveSettingsL(); + EmulateExit(); + Exit(); + } + break; + } + } + }break; + } + break; + } + } + } + else + { + if(aType == EEventKeyDown) + { + if(aKeyEvent.iScanCode != EStdKeyBackspace) + { + iScanCodes[iCurrentScan]=aKeyEvent.iScanCode; + } + else + { + iScanCodes[iCurrentScan] = KErrNotFound; + } + + iCurrentScan++; + if(iCurrentScan==iKeyNames->Count()) + { + SaveSettingsL(); + iCurrentScan=-1; + iView->DrawText(_L("Done!"),TPoint(0,iFontHeight*11)); + + User::After(1000000); + iView->Clear(); + PutMainMenu(); + } + else + { + iView->Clear(); + PutConfigKeys(); + } + } + } + } + else + { + if((aType == EEventKeyUp || aType == EEventKeyDown)) + { + TUint16 bitVal=0; + for(TInt loop=0;loop<16;loop++) + { + if(aKeyEvent.iScanCode==iScanCodes[loop]) + { + bitVal=KBitValTable[loop]; + break; + } + } + + if(aType == EEventKeyUp) + { + iPad1=iPad1&(65535-bitVal); // remove bit + } + else + { + iPad1=(iPad1|bitVal); // set bit + } + } + + if(aType == EEventKey) + { + if(aKeyEvent.iScanCode == iScanCodes[EPicoResetKey]) + { + PicoReset(0); + } + + if(aKeyEvent.iScanCode == iScanCodes[EPicoPanLKey] && gFullOffset>0) + { + gFullOffset-=24; + } + else if(aKeyEvent.iScanCode == iScanCodes[EPicoPanRKey]&& gFullOffset<144) + { + gFullOffset+=24; + } + } + } + + return EKeyWasConsumed; +} + +TInt CPicoDriveUi::SelectFile(TFileName& aFileName) +{ + TFileName filename=aFileName; + TInt selectedIndex=-1; + RArray romList; + TDriveList driveList; + TBool refresh=EFalse; + TInt lastLength=-1; + do + { + CAknListQueryDialog* dlg = new (ELeave) CAknListQueryDialog(&selectedIndex); + CDesCArrayFlat* list=new (ELeave) CDesCArrayFlat(5); + refresh=EFalse; + if(filename.Length()==0) + { + + iEikonEnv->FsSession().DriveList(driveList); + for(TInt drive=0;drive form; + form.Format(_L("%c:\\"),drive+65); + list->AppendL(form); + } + } + } + else + { + CDir* romDir = NULL;; + romList.Reset(); + iEikonEnv->FsSession().GetDir(filename,KEntryAttMatchMask,0,romDir); + + if(romDir!=NULL) + list->AppendL(_L(".. ")); + + if(romDir!=NULL && romDir->Count()>0) + { + for(TInt loop=0;loopCount();loop++) + { + const TEntry& entry=(*romDir)[loop]; + TFileName name=entry.iName; + if(entry.IsDir()) + { + name.Append(_L(" ")); + list->AppendL(name); + romList.Append(entry); + } + else + { + TParsePtr parse(name); + + if(parse.Ext().CompareF(_L(".bin"))==KErrNone || + parse.Ext().CompareF(_L(".smd"))==KErrNone || + parse.Ext().CompareF(_L(".zip"))==KErrNone) + { + romList.Append(entry); + list->AppendL(name); + } + } + + } + delete romDir; + romDir=NULL; + } + else // no files found.. or path not found.. return to + { + if(filename.Length()>3) // more than a c:\ specified + { + + refresh=ETrue; + filename=KNullDesC(); + } + else return EFalse; + } + + } + if(list->Count()>0) + { + dlg->PrepareLC(R_PICO_FILE_SELECT_DIALOG); + dlg->SetItemTextArray(list); + if(dlg->RunLD()) + { + if(filename.Length()==0) + { + TFileName driveLetter; + TUint8 driveL; + TInt countedDrives=0; + for(TInt drive=0;drive0) + { + selectedIndex--; + const TEntry& entry=romList[selectedIndex]; + TFileName name =entry.iName; + if(entry.IsDir()) + { + lastLength=aFileName.Length(); + filename.Append(name); + filename.Append(_L("\\")); + + refresh=ETrue; + + } + else + { + filename.Append(name); + aFileName=filename; + romList.Close(); + return ETrue; + } + } + else + { + refresh=ETrue; + TInt pos=filename.Left(filename.Length()-1).LocateReverse('\\'); + if(pos!=KErrNotFound) + filename=filename.Left(pos+1);// keep + else filename=KNullDesC(); + // and changefilename.. + + //return 2;// go up one. + } + } + } + else + { + romList.Close(); + return EFalse; + } + } + }while(refresh); + romList.Close(); + return EFalse; +} + +void CPicoDriveUi::SaveSettingsL() +{ +#ifdef S60V3 + CDictionaryStore* prefs = Application()->OpenIniFileLC(iEikonEnv->FsSession()); +#else + CDictionaryFileStore* prefs=CDictionaryFileStore::OpenLC(iEikonEnv->FsSession(),iAppPath,TUid::Uid(0)); +#endif + ExternalizeL(*prefs); + prefs->CommitL(); + CleanupStack::PopAndDestroy();//close prefs +} + + +void CPicoDriveUi::ExternalizeL(CDictionaryStore& aStore) +{ + RDictionaryWriteStream writeStream; + writeStream.AssignLC(aStore, KPicoDrivePrefs); + + TInt loop=0; + for(loop=0;loopNormalFont()->HeightInPixels()+KLineGap; + iScanCodes[0]= EStdKeyUpArrow; + iScanCodes[1]= EStdKeyDownArrow; + iScanCodes[2]=EStdKeyLeftArrow; + iScanCodes[3]= EStdKeyRightArrow; + iScanCodes[6]=EStdKeyDevice0; + iScanCodes[4]= EStdKeyDevice1; + iScanCodes[5]=EStdKeyDevice3; + iScanCodes[7]=0;//x + iScanCodes[8]=0; // y + iScanCodes[9]=0;//z + iScanCodes[10]=0;// mode + iScanCodes[11]= '0'; // start +#ifdef __WINS__ + gChunk = UserHeap::ChunkHeap(&_L("ROMHEAP"),512000,16384000); +#endif + +#ifndef S60V3 + TFileName name; + iEikonEnv->RootWin().SetName(_L("PicoDrive")); +#ifndef __WINS__ + RProcess process; + process.Rename(_L("PicoDrive")); + TFileName fname =process.FileName(); + TParsePtr parser(fname); + name.Append(parser.DriveAndPath()); +#endif + name.Append(KLitResourceFileName()); + iAppPath=_L("C:"); + iAppPath.Append(TParsePtr(name).Path()); + iAppPath.Append(_L("PicoDriveS60.ini")); + iResourceFileId = iCoeEnv->AddResourceFileL(name); // eb205: needs to hunt around drives +#endif // S60V3 + iKeyNames =iEikonEnv->ReadDesCArrayResourceL(R_PICODRIVE_KEYS); + iRegNames = iEikonEnv->ReadDesCArrayResourceL(R_PICODRIVE_REGIONS); + + iEikonEnv->FsSession().MkDirAll(TParsePtr(iAppPath).DriveAndPath()); +#ifdef S60V3 + CDictionaryStore* prefs = Application()->OpenIniFileLC(iEikonEnv->FsSession()); + InternalizeL(*prefs); + CleanupStack::PopAndDestroy();//close prefs +#else + TRAPD(err,{CDictionaryFileStore* prefs=CDictionaryFileStore::OpenLC(iEikonEnv->FsSession(),iAppPath,TUid::Uid(0)); + InternalizeL(*prefs); + CleanupStack::PopAndDestroy();//close prefs + }); +#endif + + if(iFirstStart) + { + iPicoMenu = EAboutPicoMenu; + } + + iView=new (ELeave)CQPicoDriveView; + iView->ConstructL(); + AddToStackL(iView); + iDisplayMode =iEikonEnv->ScreenDevice()->DisplayMode(); + if(iDisplayMode != EColor64K && iDisplayMode != EColor4K) + { + iDisplayMode=EColor64K;; // Also tried to switch to by the view. + } + CalculatePaletteTable(); + iBackBuffer= new (ELeave)CFbsBitmap; + iBackBuffer->Create(iEikonEnv->ScreenDevice()->SizeInPixels(),iDisplayMode); + TBitmapUtil util(iBackBuffer); + util.Begin(TPoint(0,0)); + TSize sz=iBackBuffer->SizeInPixels(); + Targ.view = TRect(TPoint(0,0),sz); + TInt dataSize=sz.iWidth*sz.iHeight*2; + Targ.scanline_length = sz.iWidth*2; + Targ.screen_offset = Targ.scanline_length*(sz.iHeight-1); + TPtr8 ptr(reinterpret_cast(iBackBuffer->DataAddress()),dataSize,dataSize); + ptr.Fill(0); + util.End(); + SetKeyBlockMode(ENoKeyBlock); + iSelection=0; + + iSndStream = CMdaAudioOutputStream::NewL(*this); + iAudioSettings.Query(); + iAudioSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate8000Hz; + iAudioSettings.iChannels = TMdaAudioDataSettings::EChannelsMono; + iAudioSettings.iFlags = 0; + iAudioSettings.iVolume = iAudioSettings.iMaxVolume/2; + iSndStream->Open(&iAudioSettings); + CActiveScheduler::Start(); // wait for open +} + +void CPicoDriveUi::PutAbout(TBool iOnlyRedraw) +{ + TPtrC8 charPtr((unsigned char*)KAboutText,strlen(KAboutText)); + HBufC* credits = HBufC::NewLC(charPtr.Length()); + credits->Des().Copy(charPtr); + + if(iLastAboutPos>=credits->Length()) + { + iLastAboutPos = -1; + iView->Clear(); + iPicoMenu = EPicoMainMenu; + PutMainMenu(); + } + else + { + if(iLastAboutPos == -1) + iLastAboutPos = 0; + iView->DrawText(_L("PicoDrive S60 Credits"),TPoint(0,0)); + if(iOnlyRedraw && iLastAboutPos == 0) + iView->DrawTextInRect(*credits,TRect(0,iFontHeight*2,Targ.view.iBr.iX,Targ.view.iBr.iY),iLastAboutPos); + else + iLastAboutPos = iView->DrawTextInRect(*credits,TRect(0,iFontHeight*2,Targ.view.iBr.iX,Targ.view.iBr.iY),iLastAboutPos); + } + CleanupStack::PopAndDestroy(credits); + +} +void CPicoDriveUi::PutMainMenu() +{ + iView->DrawText(_L("PicoDrive S60"),TPoint(0,0)); + iView->DrawText(_L("by Dave et Co"),TPoint(0,iFontHeight*1)); + + iView->DrawText(_L("Load ROM"),TPoint(0,iFontHeight*3),iSelection==0); + iView->DrawText(_L("Load state"),TPoint(0,iFontHeight*4),iSelection==1); + iView->DrawText(_L("Save state"),TPoint(0,iFontHeight*5),iSelection==2); + iView->DrawText(_L("Configure controls"),TPoint(0,iFontHeight*6),iSelection==3); + iView->DrawText(_L("Configure screen"),TPoint(0,iFontHeight*7),iSelection==4); + iView->DrawText(_L("Configure sound"),TPoint(0,iFontHeight*8),iSelection==5); + iView->DrawText(_L("Game Genie/Cheats"),TPoint(0,iFontHeight*9),iSelection==6); + + iView->DrawText(_L("Reset"),TPoint(0,iFontHeight*10),iSelection==7); + + iView->DrawText(_L("Credits"),TPoint(0,iFontHeight*11),iSelection==8); + iView->DrawText(_L("Exit"),TPoint(0,iFontHeight*12),iSelection==9); + if(iRomName.Length()>0) + { + iView->DrawText(TParsePtr(iRomName).Name(),TPoint(0,iFontHeight*13)); + } + else + { + iView->DrawText(_L("No rom loaded"),TPoint(0,iFontHeight*13)); + } + +} + +void CPicoDriveUi::PutScreenSelect() +{ + TInt regionIndex = 0; + + switch(PicoRegionOverride) + { + default: + regionIndex = 0; + break; + case 1: + regionIndex = 1; + break; + case 2: + regionIndex = 2; + break; + case 4: + regionIndex = 3; + break; + case 8: + regionIndex = 4; + break; + } + + iView->DrawText(_L("PicoDrive S60"),TPoint(0,0)); + iView->DrawText(_L("Screen options"),TPoint(0,iFontHeight)); + iView->DrawText(_L("Portrait"),TPoint(0,iFontHeight*3),iScrMode==0); + iView->DrawText(_L("Landscape Left"),TPoint(0,iFontHeight*4),iScrMode==1); + iView->DrawText(_L("Landscape Right"),TPoint(0,iFontHeight*5),iScrMode==2); + iView->DrawText(_L("Portrait stretched"),TPoint(0,iFontHeight*6),iScrMode==3); + iView->DrawText(_L("Portrait full"),TPoint(0,iFontHeight*7),iScrMode==4); + if(iInterpolate) + { + iView->DrawText(_L("Interpolate on"),TPoint(0,iFontHeight*8),iScrMode==5); + } + else + { + iView->DrawText(_L("Interpolate off"),TPoint(0,iFontHeight*8),iScrMode==5); + } + + if(iFrameSkip == -1) + { + iView->DrawText(_L("Frameskip auto"),TPoint(0,iFontHeight*9),iScrMode==6); + } + else + { + TBuf<64> skip; + skip.Format(_L("Frameskip %d"),iFrameSkip); + iView->DrawText(skip,TPoint(0,iFontHeight*9),iScrMode==6); + } + + if(PicoOpt & 0x40) + { + iView->DrawText(_L("Accurate timing on"),TPoint(0,iFontHeight*10),iScrMode==7); + } + else + { + iView->DrawText(_L("Accurate timing off"),TPoint(0,iFontHeight*10),iScrMode==7); + } + + if(PicoOpt & 0x80) + { + iView->DrawText(_L("Accurate sprites on"),TPoint(0,iFontHeight*11),iScrMode==8); + } + else + { + iView->DrawText(_L("Accurate sprites off"),TPoint(0,iFontHeight*11),iScrMode==8); + } + + if(PicoOpt & 0x10) + { + iView->DrawText(_L("Alt. renderer on"),TPoint(0,iFontHeight*12),iScrMode==9); + } + else + { + iView->DrawText(_L("Alt. renderer off"),TPoint(0,iFontHeight*12),iScrMode==9); + } + + iView->DrawText(iRegNames->MdcaPoint(regionIndex),TPoint(0,iFontHeight*13),iScrMode==10); + +} + +void CPicoDriveUi::PutSoundSelect() +{ + iView->Clear(); + iView->DrawText(_L("PicoDrive S60"),TPoint(0,0)); + iView->DrawText(_L("Sound options"),TPoint(0,iFontHeight)); + if (PicoOpt&4) + iView->DrawText(_L("Z80 enabled"),TPoint(0,iFontHeight*3),iSndSelection==EEnableZ80); + else + iView->DrawText(_L("Z80 disabled"),TPoint(0,iFontHeight*3),iSndSelection==EEnableZ80); + if (PicoOpt&1) + iView->DrawText(_L("YM2612 enabled"),TPoint(0,iFontHeight*4),iSndSelection==EEnableYM2612); + else + iView->DrawText(_L("YM2612 disabled"),TPoint(0,iFontHeight*4),iSndSelection==EEnableYM2612); + + if (PicoOpt&2) + iView->DrawText(_L("SN76496 enabled"),TPoint(0,iFontHeight*5),iSndSelection==EEnableSN76496); + else + iView->DrawText(_L("SN76496 disabled"),TPoint(0,iFontHeight*5),iSndSelection==EEnableSN76496); + + + TBuf<32> vol; + vol.Format(_L("Volume %d"),iSoundVolume*10); + iView->DrawText(vol,TPoint(0,iFontHeight*6),iSndSelection==ESoundVolume); + + vol.Format(_L("Sample rate %dKhz"),PsndRate/1000); + iView->DrawText(vol,TPoint(0,iFontHeight*7),iSndSelection==ESoundRate); +} + + +void CPicoDriveUi::PutCheatSelect() +{ + iView->Clear(); + iView->DrawText(_L("PicoDrive S60"),TPoint(0,0)); + iView->DrawText(_L("Cheat options"),TPoint(0,iFontHeight)); + + iView->DrawText(_L("Add cheat"),TPoint(0,iFontHeight*3),iCheatSelection==EAddCheat); + iView->DrawText(_L("Clear cheats"),TPoint(0,iFontHeight*4),iCheatSelection==EClearCheats); + TInt noCheats = 0; + TBuf<17>cheatCode; + + for(TInt i = iListOffset; (i < 256)&&(noCheats<5); i++) + { + if (Liste_GG[i].code[0] != 0) + { + + TRgb textColour = Liste_GG[i].active?KRgbGreen:KRgbDarkGreen; + if(iCheatSelection == 2+(i-iListOffset)) + { + textColour = Liste_GG[i].active?KRgbRed:KRgbDarkRed; + } + + TPtrC8 ptr((const unsigned char*)Liste_GG[i].code,strlen(Liste_GG[i].code)); + cheatCode.Copy(ptr); + + iView->DrawText(cheatCode,TPoint(0,iFontHeight*(5+noCheats)),EFalse,textColour); + + noCheats++; + } + } + + iView->DrawText(_L("Supports GG & Patch"),TPoint(0,iFontHeight*11)); + iView->DrawText(_L("GG: XXXX-XXXX"),TPoint(0,iFontHeight*12)); + iView->DrawText(_L("Patch: XXXXXX:YYYY"),TPoint(0,iFontHeight*13)); +} + +void CPicoDriveUi::PutControllerSelect() +{ + iView->Clear(); + iView->DrawText(_L("PicoDrive S60"),TPoint(0,0)); + iView->DrawText(_L("Controller options"),TPoint(0,iFontHeight)); + if (iEnableSixButtons) + iView->DrawText(_L("6 button pad"),TPoint(0,iFontHeight*3),iCtrlSelection==EControllerType); + else + iView->DrawText(_L("3 button pad"),TPoint(0,iFontHeight*3),iCtrlSelection==EControllerType); + iView->DrawText(_L("Configure keys"),TPoint(0,iFontHeight*4),iCtrlSelection==EConfigControls); + + + +} + + +void CPicoDriveUi::PutConfigKeys() +{ + iView->DrawText(_L("PicoDrive S60"),TPoint(0,0)); + iView->DrawText(_L("Configure keys"),TPoint(0,iFontHeight)); + iView->DrawText(_L("Please press:"),TPoint(0,iFontHeight*3)); + iView->DrawText(iKeyNames->MdcaPoint(iCurrentScan),TPoint(0,iFontHeight*4)); + + iView->DrawText(_L("Press 'C' to skip this!"),TPoint(0,iFontHeight*6)); + +} + +TInt CPicoDriveUi::IdleCallBackStop(TAny* /*aAppUi*/) +{ + CActiveScheduler::Stop(); + return 0; +} + +TInt CPicoDriveUi::StartEmulatorL(TAny* aAppUi) +{ + static_cast(aAppUi)->StartEmulatorL(); + return 0; +} + +void CPicoDriveUi::HandleForegroundEventL(TBool aForeground) +{ + if(iView != NULL) + { + iView->iForeground=aForeground; + } + + if(!aForeground) + { + if(iView != NULL) + { + iView->AbortNow(RDirectScreenAccess::ETerminateCancel); + } + } + else + { + if(iView != NULL) + { + iView->Restart(RDirectScreenAccess::ETerminateCancel); + UpdateScreen(); + } + + SetKeyBlockMode(ENoKeyBlock); + } + +} + +void CPicoDriveUi::UpdateScreen() +{ + if(!iEmuRunning) + { + iView->Clear(); + if(iCurrentScan>=0) + { + PutConfigKeys(); + } + else if(iPicoMenu==ESelectScrMenu) + { + PutScreenSelect(); + } + else if (iPicoMenu==EAboutPicoMenu) + { + PutAbout(ETrue); + } + else if (iPicoMenu==ESelectSoundMenu) + { + PutSoundSelect(); + } + else if (iPicoMenu==ESelectControlsMenu) + { + PutControllerSelect(); + } + else if (iPicoMenu==ESelectCheatMenu) + { + PutCheatSelect(); + } + else + PutMainMenu(); + + } +} + +void CPicoDriveUi::StartEmulatorL() +{ + iView->Clear(); + TTime time; + time.HomeTime(); +#ifdef S60V3 + LastSecond=(TInt)(time.Int64()/1000);//GetTickCount(); +#else + LastSecond=(TInt)(time.Int64()/1000).GetTInt();//GetTickCount(); +#endif + FramesDone=0; + + iSndStream->SetVolume((iSndStream->MaxVolume()*iSoundVolume)/10); + UpdatePSndRate(); + + while(iEmuRunning) + { + EmulateFrame(); + } + iSndStream->Stop(); + iView->Clear(); + PutMainMenu(); + +} + +/** + * Calculates the palette table 0-4096 + */ +void CPicoDriveUi::CalculatePaletteTable() +{ + for(TInt cram =0;cram<4096;cram++) + { + if(iDisplayMode == EColor4K) + { + unsigned short high=0x111; + high|=(cram&0x00e)<<8; // Red + high|=(cram&0x0e0); // Green + high|=(cram&0xe00)>> 8; // Blue + gColorMapTab[cram] = high; + } + else // 64K color mode + { + unsigned short high=0x0841; + // Convert 0000bbbb ggggrrrr + // to rrrr1ggg g10bbbb1 + high|=(cram&0x00f)<<12; // Red + high|=(cram&0x0f0)<< 3; // Green + high|=(cram&0xf00)>> 7; // Blue + gColorMapTab[cram] = high; + } + } +} + +int CPicoDriveUi::TargetInit() +{ + PicoCram=NULL; + TUint16 currentLine = 0; + TReal xFactor = 1; + TReal xNarrowFactor = 1; + TReal yFactor = 1; + TInt loop; + + memset(framebuff,0,framebuffsize); + + if(iScrMode==0) + { +#ifdef S60V3 + xFactor = ((TReal)Targ.view.iBr.iX/(TReal)320); + xNarrowFactor = ((TReal)Targ.view.iBr.iX/(TReal)256); + + if(xFactor>1) + xFactor = 1; + + if(xNarrowFactor>1) + xNarrowFactor = 1; + + yFactor = ((TReal)Targ.view.iBr.iY/(TReal)240); + + if(yFactor>1) + yFactor = 1; + + for(loop = 0;loop<256;loop++) + { + TInt line = (loop*xNarrowFactor); + TInt nextLine = ((loop+1)*xNarrowFactor); + if(line != nextLine) + { + gNarrowColumnStepTable[loop] = 1; + } + else + { + gNarrowColumnStepTable[loop] = 0; + } + } + + for(loop = 0;loop<320;loop++) + { + TInt line = (loop*xFactor); + TInt nextLine = ((loop+1)*xFactor); + if( line != nextLine) + { + gColumnStepTable[loop] = 1; + } + else + { + gColumnStepTable[loop] = 0; + } + } + + for(TInt loop = 0;loop<240;loop++) + { + gLineTable[loop] = currentLine; + if((loop*yFactor) != ((loop+1)*yFactor)) + currentLine++; + } + myPicoScan=EmulateScan16; + +#else + if(iInterpolate) + myPicoScan=EmulateScan16_176Interpolate; + else + myPicoScan=EmulateScan16_176; + for(TInt loop = 0;loop<240;loop++) + { + gLineTable[loop] = currentLine; + if(((loop*3)/4) != (((loop+1)*3)/4)) + currentLine++; + } +#endif + KBitValTable[0] = 1; + KBitValTable[1] = 2; + KBitValTable[2] = 4; + KBitValTable[3] = 8; + } +#ifdef S60V3 + else if (iScrMode == 1 || iScrMode == 2) + { + xFactor = ((TReal)Targ.view.iBr.iY/(TReal)320); + xNarrowFactor = ((TReal)Targ.view.iBr.iY/(TReal)256); + + if(xFactor>2) + xFactor = 2; + + if(xNarrowFactor>2) + xNarrowFactor = 2; + + yFactor = ((TReal)Targ.view.iBr.iX/(TReal)240); + if(yFactor>2) + yFactor = 2; + + for(loop = 0;loop<256;loop++) + { + TInt col = (loop*xNarrowFactor); + TInt nextCol= ((loop+1)*xNarrowFactor); + + gNarrowColumnStepTable[loop] = nextCol-col;; + } + + for(loop = 0;loop<320;loop++) + { + TInt col = (loop*xFactor); + TInt nextCol= ((loop+1)*xFactor); + + gColumnStepTable[loop] = nextCol-col;; + } + + for(TInt loop = 0;loop<240;loop++) + { + gLineTable[loop] = currentLine; + TInt line = (loop*yFactor); + TInt nextLine = ((loop+1)*yFactor); + currentLine+=(nextLine-line); + } + if(iScrMode == 2) + { + KBitValTable[0] = 4; + KBitValTable[1] = 8; + KBitValTable[2] = 2; + KBitValTable[3] = 1; + myPicoScan=EmulateScanFullRight16; + } + else + { + KBitValTable[0] = 8; + KBitValTable[1] = 4; + KBitValTable[2] = 1; + KBitValTable[3] = 2; + myPicoScan=EmulateScanFull16; + } +#else +else if (iScrMode == 1) +{ + if(iInterpolate) + myPicoScan=EmulateScanFull16_176Interpolate; + else + myPicoScan=EmulateScanFull16_176; + + for(TInt loop = 0;loop<240;loop++) + { + gLineTable[loop] = currentLine; + if(((loop*3)/4) != (((loop+1)*3)/4)) + currentLine++; + } + KBitValTable[0] = 8; + KBitValTable[1] = 4; + KBitValTable[2] = 1; + KBitValTable[3] = 2; +#endif + } +#ifndef S60V3 + else if(iScrMode==2) + { + if(iInterpolate) + myPicoScan=EmulateScanFullRight16_176Interpolate; + else + myPicoScan=EmulateScanFullRight16_176; + for(TInt loop = 0;loop<240;loop++) + { + gLineTable[loop] = currentLine; + if(((loop*3)/4) != (((loop+1)*3)/4)) + currentLine++; + } + KBitValTable[0] = 4; + KBitValTable[1] = 8; + KBitValTable[2] = 2; + KBitValTable[3] = 1; + } +#endif + else + { +#ifdef S60V3 + xFactor = ((TReal)Targ.view.iBr.iX/(TReal)320); + xNarrowFactor = ((TReal)Targ.view.iBr.iX/(TReal)256); + + if(xFactor>2) + xFactor = 2; + + if(xNarrowFactor>2) + xNarrowFactor = 2; + + yFactor = ((TReal)Targ.view.iBr.iY/(TReal)240); + + if(yFactor>2) + yFactor = 2; + + for(loop = 0;loop<256;loop++) + { + TInt col = (loop*xNarrowFactor); + TInt nextCol= ((loop+1)*xNarrowFactor); + + gNarrowColumnStepTable[loop] = nextCol-col;; + } + + for(loop = 0;loop<320;loop++) + { + TInt col = (loop*xFactor); + TInt nextCol= ((loop+1)*xFactor); + + gColumnStepTable[loop] = nextCol-col;; + } + + for(TInt loop = 0;loop<240;loop++) + { + gLineTable[loop] = currentLine; + TInt line = (loop*yFactor); + TInt nextLine = ((loop+1)*yFactor); + currentLine+=(nextLine-line); + } + myPicoScan=EmulateStretchScan16; +#else + if(iScrMode == 4) + { + myPicoScan=EmulateStretchScan16_320; + iInterpolate = EFalse; // not needed + } + else + { + if(iInterpolate) + myPicoScan=EmulateStretchScan16_176Interpolate; + else + myPicoScan=EmulateStretchScan16_176; + } + + for(TInt loop = 0;loop<240;loop++) + { + gLineTable[loop] = currentLine; + if(((loop*15)/16) != (((loop+1)*15)/16)) + currentLine++; + } +#endif + KBitValTable[0] = 1; + KBitValTable[1] = 2; + KBitValTable[2] = 4; + KBitValTable[3] = 8; + } + + if(iView) + iView->SetRect(TRect(TPoint(0,0),iEikonEnv->ScreenDevice()->SizeInPixels())); +#ifdef S60V3 + switch(iScrMode) + { + case 0: + case 3: + case 4: + iPutRect=TRect(TPoint(0,0),TSize(xFactor*320,yFactor*240)); + iPutPoint=TPoint(Targ.view.Size().iWidth/2-iPutRect.Size().iWidth/2,Targ.view.Size().iHeight/2-iPutRect.Size().iHeight/2); + + break; + case 1: + case 2: + iPutRect=TRect(TPoint(0,0),TSize(yFactor*240,xFactor*320)); + iPutPoint=TPoint(Targ.view.Size().iWidth/2-iPutRect.Size().iWidth/2,Targ.view.Size().iHeight/2-iPutRect.Size().iHeight/2); + break; + + } +#else + switch(iScrMode) + { + case 0: + iPutPoint=TPoint(0,20); + iPutRect=TRect(TPoint(0,0),TSize(176,168)); + break; + case 1: + case 2: + iPutPoint=TPoint(4,1); + iPutRect=TRect(TPoint(4,1),TSize(168,205)); + + break; + case 3: + case 4: + iPutPoint=TPoint(0,0); + iPutRect=TRect(TPoint(0,0),TSize(176,208)); + break; + } +#endif + CalulateLineStarts(); + return 0; +} +#ifdef S60V3 +#define KCenterOffset 8 +#else +#define KCenterOffset 0 +#endif +void CPicoDriveUi::CalulateLineStarts() +{ + switch(iScrMode) + { + case 0: + case 3: + case 4: + { + for(TInt loop = 0;loopFsSession(),iRomName,0); + file.Close(); + f=fopen(RomName,"rb"); + if (f==NULL) + return 1; + TInt result =PicoCartLoad(f,&RomData,&RomSize); + fclose(f); + if(result) + return 1; // failed to load cart + } + + TParsePtr parser(iRomName); + TPtr8 ptr(Pico.rom_name,511); + ptr.Copy(parser.DriveAndPath()); + ptr.Append(parser.Name()); + ptr.ZeroTerminate(); + + PicoCartInsert(RomData,RomSize); + Load_Patch_File(); + saveLoadGame(1, 1); // load sram if any saved + + if(!iEnableSixButtons) + PicoOpt=PicoOpt& 223; + else + PicoOpt=PicoOpt|32; + return 0; +} + +void CPicoDriveUi::EmulateExit() +{ + // Save sram if any + if(RomData != NULL) + { + if(SRam.changed) + { + saveLoadGame(0,1); + SRam.changed = 0; + } + + Save_Patch_File(); + // Remove cartridge + PicoCartInsert(NULL,0); + PicoUnloadCart(RomData); + RomData=NULL; RomSize=0; + } + PicoExit(); +} + +int CPicoDriveUi::InputFrame() +{ + if(PicoOpt & 3) + { + PsndOut=(short*)(iMonoSound.Ptr()+2*iCurrentSeg*PsndLen); + } + else + { + PsndOut=NULL; + } + + Patch_Codes(); + + PicoFrame(); + + if(PicoOpt & 3) + { + iCurrentSeg++; + if(iCurrentSeg==6) + { + iMonoSound.SetLength(PsndLen*2*6); + iSndStream->WriteL(iMonoSound); + iCurrentSeg=0; + } + } + + TCallBack callback(IdleCallBackStop,this); + iIdleCallBack.Cancel(); + iIdleCallBack.Set(callback); + iIdleCallBack.CallBack(); + CActiveScheduler::Start(); + + + PicoPad[0]=iPad1; + return 0; +} + + + +int CPicoDriveUi::EmulateFrame() +{ + int i=0,need=2; + if (!iRomLoaded) + return 1; + // Speed throttle: + if(iFrameSkip ==-1) // auto skipping + { + int time=0,frame=0; + TTime newtime; + newtime.HomeTime(); +#ifdef S60V3 + TInt64 tic=(newtime.Int64()/1000); + time=(tic-LastSecond); // This will be about 0-1000 ms +#else + TInt64 tic=(newtime.Int64()/1000).GetTInt(); + time=(tic-LastSecond).GetTInt(); // This will be about 0-1000 ms +#endif + frame=time*FramesPerSecond/1000; + need=frame-FramesDone; + FramesDone=frame; + + if (FramesPerSecond>0) + { + // Carry over any >60 frame count to one second + while (FramesDone>=FramesPerSecond) { FramesDone-=FramesPerSecond; LastSecond+=1000; } + } + + if (need<=0) { + TTime nextTime; + do + { + nextTime.HomeTime(); + }while((nextTime.Int64()-newtime.Int64())<15000); + } + if (need>10) need=10; // Limit frame skipping + } + else + { + need = iFrameSkip+1; + } + PicoSkipFrame=1; + for (i=0;iDataAddress(); + + if (Targ.screen == NULL) + { + util.End(); + return 1; + } + + PicoScan=myPicoScan; // Setup scanline callback + InputFrame(); + + + if(PicoOpt & 0x10) // need to render separatly + { + unsigned short* framebuffptr = framebuff+2632; + + if(!(Pico.video.reg[12]&1)) + { + framebuffptr=framebuffptr-32; + } + + TInt skipNext =0; + for(TInt loop = 0;loop<224;loop++) + { + if(skipNext == 0) + { + skipNext = PicoScan(loop,framebuffptr); + } + else + skipNext--; + framebuffptr+=328; + } + } + PicoScan=NULL; + util.End(); + + Targ.screen = NULL; + + iView->PutBitmap(iBackBuffer,iPutPoint,iPutRect);; + + return 0; +} + + +void CPicoDriveUi::MaoscOpenComplete(TInt aError) +{ + if(aError == KErrNone) + { + iSndStream->SetPriority(EPriorityMuchMore, EMdaPriorityPreferenceNone); + iSndStream->SetVolume((iSndStream->MaxVolume()*iSoundVolume)/10); + if(!UpdatePSndRate()) + { + PsndRate = 8000; + UpdatePSndRate(); + } + } + CActiveScheduler::Stop(); +} + +void CPicoDriveUi::MaoscBufferCopied(TInt /*aError*/, const TDesC8& /*aBuffer*/) +{ +} + +void CPicoDriveUi::MaoscPlayComplete(TInt aError) +{ + if(aError != KErrNone) + { + iSndStream->SetVolume((iSndStream->MaxVolume()*iSoundVolume)/10); + UpdatePSndRate(); + } +} + +TBool CPicoDriveUi::UpdatePSndRate() +{ + TInt sampleRate = TMdaAudioDataSettings::ESampleRate8000Hz; + if(PsndRate == 11025) + sampleRate = TMdaAudioDataSettings::ESampleRate11025Hz; + else if (PsndRate == 16000) + sampleRate = TMdaAudioDataSettings::ESampleRate16000Hz; + else if (PsndRate == 22050) + sampleRate = TMdaAudioDataSettings::ESampleRate22050Hz; + + TRAPD(err,iSndStream->SetAudioPropertiesL(sampleRate,TMdaAudioDataSettings::EChannelsMono)); + return (err == KErrNone); +} + +size_t gzRead2(void *p, size_t _size, size_t _n, void *file) +{ + return gzread(file, p, _n); +} + + +size_t gzWrite2(void *p, size_t _size, size_t _n, void *file) +{ + return gzwrite(file, p, _n); +} + + + +// this function is shared between both threads +int CPicoDriveUi::saveLoadGame(int load, int sram) +{ + int res = 0; + + if(!(iRomName.Length()>0)) return -1; + + // make save filename + strcpy(saveFname,RomName); + saveFname[KMaxFileName-5] = 0; + if(saveFname[strlen(saveFname)-4] == '.') saveFname[strlen(saveFname)-4] = 0; + strcat(saveFname, sram ? ".srm" : ".mds"); + + if(sram) { + int sram_size = SRam.end-SRam.start+1; + if(SRam.reg_back & 4) sram_size=0x2000; + if(!SRam.data) return 0; // SRam forcefully disabled for this game + if(load) { + PmovFile = fopen(saveFname, "rb"); + if(!PmovFile) return -1; + fread(SRam.data, 1, sram_size, (FILE *) PmovFile); + fclose((FILE *) PmovFile); + } else { + // sram save needs some special processing + // see if we have anything to save + for(; sram_size > 0; sram_size--) + if(SRam.data[sram_size-1]) break; + + if(sram_size) { + PmovFile = fopen(saveFname, "wb"); + res = fwrite(SRam.data, 1, sram_size, (FILE *) PmovFile); + res = (res != sram_size) ? -1 : 0; + fclose((FILE *) PmovFile); + } + } + PmovFile = 0; + return res; + } else { + // try gzip first + //if(currentConfig.iFlags & 0x80) { + strcat(saveFname, ".gz"); + if( (PmovFile = gzopen(saveFname, load ? "rb" : "wb")) ) { + areaRead = gzRead2; + areaWrite = gzWrite2; + if(!load) gzsetparams(PmovFile, 9, Z_DEFAULT_STRATEGY); + } else + saveFname[strlen(saveFname)-3] = 0; + // } + + if(!PmovFile) { // gzip failed or was disabled + if( (PmovFile = fopen(saveFname, load ? "rb" : "wb")) ) { + areaRead = (arearw *) fread; + areaWrite = (arearw *) fwrite; + } + } + if(PmovFile) { + PmovAction = load ? 6 : 5; // load/save + PmovState(); + if(areaRead == gzRead2) + gzclose(PmovFile); + else fclose ((FILE *) PmovFile); + PmovFile = 0; + } else { + res = -1; + } + + return res; + } + +} + +CQPicoDriveView::~CQPicoDriveView() +{ + iDsa->Cancel(); + delete iDsa; +} + +void CQPicoDriveView::Restart(RDirectScreenAccess::TTerminationReasons /*aReason*/) +{ + if(iForeground) + { + iDsa->Cancel(); + iDsa->StartL(); + iDsa->Gc()->SetClippingRegion(iDsa->DrawingRegion()); + iDrawingOn=ETrue; + } +} + +void CQPicoDriveView::AbortNow(RDirectScreenAccess::TTerminationReasons /*aReason*/) +{ + iDsa->Cancel(); + iDrawingOn=EFalse; +} + + + +void CQPicoDriveView::Draw(const TRect& aRect) const +{ + CWindowGc& gc=SystemGc(); + + gc.SetBrushColor(KRgbBlack); + gc.SetBrushStyle(CGraphicsContext::ESolidBrush); + gc.SetPenStyle(CGraphicsContext::ENullPen); + gc.DrawRect(aRect); + static_cast(iEikonEnv->EikAppUi())->StartAsynchUpdate(); +} + +void CQPicoDriveView::ConstructL() +{ + CreateWindowL(); + ActivateL(); + SetFocus(ETrue); + SetRect(TRect(TPoint(0,0),iEikonEnv->ScreenDevice()->SizeInPixels())/*iEikonEnv->EikAppUi()->ClientRect()*/); + iDsa=CDirectScreenAccess::NewL(iEikonEnv->WsSession(),*iEikonEnv->ScreenDevice(),Window(),*this); + iDsa->StartL(); + iDsa->Gc()->SetClippingRegion(iDsa->DrawingRegion()); + iDrawingOn=ETrue; + if(Window().DisplayMode() != EColor4K && Window().DisplayMode() != EColor64K) + { + Window().SetRequiredDisplayMode(EColor64K); // Try to set 64K color mode + } +} +void CQPicoDriveView::Clear() +{ + CBitmapContext* gc; + if(iDrawingOn) + { + gc=iDsa->Gc(); + } + else + { + ActivateGc(); + gc=&SystemGc(); + } + + gc->SetBrushColor(KRgbBlack); + gc->SetBrushStyle(CGraphicsContext::ESolidBrush); + gc->SetPenStyle(CGraphicsContext::ENullPen); + gc->DrawRect(Rect()); + if(iDrawingOn) + { + iDsa->ScreenDevice()->Update(); + iEikonEnv->WsSession().Flush(); + } + else + { + DeactivateGc(); + } +} + +void CQPicoDriveView::DrawText(const TDesC& aText,TPoint aPoint,TBool aHighLight,TRgb aTextColour) +{ + CBitmapContext* gc; + if(iDrawingOn) + { + gc=iDsa->Gc(); + } + else + { + ActivateGc(); + gc=&SystemGc(); + } + + gc->SetBrushColor(KRgbBlack); + gc->SetBrushStyle(CGraphicsContext::ESolidBrush); + if(!aHighLight) + { + gc->SetPenColor(aTextColour); + } + else + { + gc->SetPenColor(KRgbRed); + } + gc->SetPenStyle(CGraphicsContext::ESolidPen); + aPoint.iY+=iEikonEnv->NormalFont()->HeightInPixels()-2; + aPoint.iX=Size().iWidth/2-iEikonEnv->NormalFont()->TextWidthInPixels(aText)/2; + gc->UseFont(iEikonEnv->NormalFont()); + gc->DrawText(aText,aPoint); + gc->DiscardFont(); + + if(iDrawingOn) + { + iDsa->ScreenDevice()->Update(); + } + else + { + DeactivateGc(); + } +} + +TInt CQPicoDriveView::DrawTextInRect(const TDesC& aText,TRect aRect,TInt aStartPos) +{ + CBitmapContext* gc; + TInt pos = aStartPos; + TInt len = aText.Length(); + if(iDrawingOn) + { + gc=iDsa->Gc(); + } + else + { + ActivateGc(); + gc=&SystemGc(); + } + + gc->SetBrushColor(KRgbBlack); + gc->SetBrushStyle(CGraphicsContext::ESolidBrush); + + gc->SetPenColor(KRgbWhite); + + gc->SetPenStyle(CGraphicsContext::ESolidPen); + gc->UseFont(iEikonEnv->DenseFont()); + while(posDenseFont()->HeightInPixels()+3)) + { + TInt newline = aText.Right(len-pos).Locate('\n'); + if(newline == KErrNotFound) + newline=(len-1)-pos; + gc->DrawText(aText.Mid(pos,newline),aRect,iEikonEnv->DenseFont()->HeightInPixels()); + pos=pos+newline+1; // skip new line + aRect.iTl+=TSize(0,iEikonEnv->DenseFont()->HeightInPixels()+3); + } + gc->DiscardFont(); + + if(iDrawingOn) + { + iDsa->ScreenDevice()->Update(); + } + else + { + DeactivateGc(); + } + return pos; +} + + +void CQPicoDriveView::PutBitmap(CFbsBitmap* aBitmap,TPoint aPoint,TRect aRect) +{ + if(iDrawingOn) + { + //#ifdef __WINS__ + iDsa->Gc()->BitBlt(aPoint,aBitmap,aRect); + iDsa->ScreenDevice()->Update(); + //#endif + //iEikonEnv->WsSession().Flush(); + } + else + { + ActivateGc(); + CWindowGc& gc=SystemGc(); + gc.BitBlt(aPoint,aBitmap,aRect); + DeactivateGc(); + } +} + + + +void Execute() +{ + __UHEAP_MARK; + CTrapCleanup* cleanup = CTrapCleanup::New(); + + // Create a eikenv + CEikonEnv* eikenv = new CEikonEnv; + if (!eikenv) + { + return /*KErrNoMemory*/; + } + TRAPD(eikErr, eikenv->ConstructL()); + if (eikErr != KErrNone) + { + delete eikenv; + return /*eikErr*/; + } + CPicoDriveUi* appUi = new (ELeave) CPicoDriveUi; + if (!appUi) + { + delete eikenv; + return /*KErrNoMemory*/; + } + + TRAPD(constructErr,appUi->ConstructL()); + + eikenv->SetAppUi(appUi); // passing ownership of appUi to coe + + TInt leaveValue = KErrNone; + if (leaveValue != KErrNone) + { + delete eikenv; + } + else + { + // now accept request from clients (start the scheduler) + eikenv->ExecuteD(); + //delete eikenv; // ExecuteD kills eikenv + + } + + delete cleanup; + + __UHEAP_MARKEND; +} + +//ARM build +#ifdef S60V3 +CPicoDriveApp::CPicoDriveApp() +{ +} + +CPicoDriveApp::~CPicoDriveApp() +{ +} + +CApaDocument* CPicoDriveApp::CreateDocumentL() +{ + return new (ELeave) CPicoDriveDoc(*this); +} + + +TUid CPicoDriveApp::AppDllUid()const +{ + return TUid::Uid(0xA00007BE); +} + +/** + * From @c CApaApplication. Opens the .ini file associated with the + * application. By default, ini files are not supported by SERIES60 + * applications. If you want to use an ini file, either override this + * function to base call @c CEikApplication::OpenIniFileLC, or call it + * directly. + * @param aFs File server session to use. Not used. + * @return Pointer to the dictionary store object representing the + * application's .ini file. + */ +CDictionaryStore* CPicoDriveApp::OpenIniFileLC(RFs& aFs) const +{ + return CEikApplication::OpenIniFileLC(aFs); +} + +CPicoDriveDoc::CPicoDriveDoc(CEikApplication& aApp):CAknDocument(aApp) +{ +} + +CPicoDriveDoc::~CPicoDriveDoc() +{ +} + +CEikAppUi* CPicoDriveDoc::CreateAppUiL() +{ + return new (ELeave) CPicoDriveUi; +} + +#ifdef S60V3 +LOCAL_C +#endif +CApaApplication* NewApplication() { + // Return pointer to newly created Application + return new CPicoDriveApp; +} +#include +#endif +GLDEF_C TInt E32Main() +{ +#ifdef S60V3 + return EikStart::RunApplication(NewApplication); +#else + Execute(); +#endif + return KErrNone; +} +#if defined(__WINS__) + +#ifndef S60V3 +EXPORT_C TInt WinsMain() +{ + E32Main(); + return KErrNone; +} +#endif + +extern "C" void my_free(void* anAddress) +{ + if(gChunk != NULL) + { + gChunk->Free(anAddress); + } +} + +extern "C" void* my_malloc(int aSize) +{ + if(gChunk != NULL) + { + return gChunk->Alloc(aSize); + } + return NULL; +} +#endif + diff --git a/platform/s60/PicoDriveExe.h b/platform/s60/PicoDriveExe.h new file mode 100644 index 00000000..506206e6 --- /dev/null +++ b/platform/s60/PicoDriveExe.h @@ -0,0 +1,281 @@ +#ifndef PicoDriveH +#define PicoDriveH +#include +#include +#include +#include +#include +#include +#include + +#include +struct Target +{ + unsigned char *screen; + TPoint point; // Screen to client point + TRect view,update; + TInt scanline_length; + TInt screen_offset; + TBool stretch_line; + +}; + +enum TPicoMainMenu +{ + ELoadRom, + ELoadState, + ESaveState, + ESetControls, + ESetScreen, + ESelectSound, + ESelectCheat, + EResetHw, + EAboutPico, + EExitPico, + ELastMenuItem +}; + +enum TPicoSoundMenu +{ + EEnableZ80, + EEnableYM2612, + EEnableSN76496, + ESoundVolume, + ESoundRate, + ELastSoundItem +}; + +enum TPicoCheatMenu +{ + EAddCheat, + EClearCheats, + ELastCheatItem +}; + +enum TPicoControllerMenu +{ + EControllerType, + EConfigControls +}; +enum TPicoMenus +{ + EPicoMainMenu, + ESelectScrMenu, + EAboutPicoMenu, + ESelectSoundMenu, + ESelectControlsMenu, + ESelectCheatMenu +}; + +enum TPicoKeys +{ + EPicoUpKey, + EPicoDownKey, + EPicoLeftKey, + EPicoRightKey, + EPicoAKey, + EPicoBKey, + EPicoCKey, + EPicoXKey, + EPicoYKey, + EPicoZKey, + EPicoModeKey, + EPicoStartKey, + EPicoULKey, + EPicoURKey, + EPicoDRKey, + EPicoDLKey, + EPicoResetKey, + EPicoPanLKey, + EPicoPanRKey, + EPicoNoKeys +}; + +class CPicoAddCheatDlg:public CEikDialog +{ +public: + CPicoAddCheatDlg(TDes8& aCheatCode):iCheatCode(aCheatCode){}; + ~CPicoAddCheatDlg(){ iEikonEnv->EikAppUi()->RemoveFromStack(this);} + TBool OkToExitL(TInt /*aButtonId*/) + { + static_cast(ControlOrNull(0x2000))->GetText(iUniCheatCode); + iCheatCode.Copy(iUniCheatCode); + return ETrue; + } + + void PreLayoutDynInitL() + { + iEikonEnv->EikAppUi()->AddToStackL(this); + } +private: + TDes8& iCheatCode; + TBuf<16> iUniCheatCode; +}; + +#ifdef S60V3 +class CPicoDriveDoc:public CAknDocument +{ +public: + CPicoDriveDoc(CEikApplication& aApp); + ~CPicoDriveDoc(); + CEikAppUi* CreateAppUiL(); +}; + +class CPicoDriveApp:public CAknApplication +{ +public: + CPicoDriveApp(); + ~CPicoDriveApp(); + TUid AppDllUid()const; + CApaDocument* CreateDocumentL(); + + /** + * From @c CApaApplication. Opens the .ini file associated with the + * application. By default, ini files are not supported by SERIES60 + * applications. If you want to use an ini file, either override this + * function to base call @c CEikApplication::OpenIniFileLC, or call it + * directly. + * @param aFs File server session to use. Not used. + * @return Pointer to the dictionary store object representing the + * application's .ini file. + */ + CDictionaryStore* OpenIniFileLC(RFs& aFs) const; +}; +#endif + +class CQPicoDriveView:public CCoeControl,public MDirectScreenAccess + { +public: + CQPicoDriveView() {}; + ~CQPicoDriveView(); + void Draw(const TRect& aRect) const; + void ConstructL(); + void PutBitmap(CFbsBitmap* aBitmap,TPoint aPoint,TRect aRect); + void Restart(RDirectScreenAccess::TTerminationReasons aReason); + void AbortNow(RDirectScreenAccess::TTerminationReasons aReason); + void DrawText(const TDesC& aText,TPoint aPoint,TBool aHighLight=EFalse,TRgb aTextColour = KRgbWhite); + TInt DrawTextInRect(const TDesC& aText,TRect aRect,TInt aStartPos); + void Clear(); + CDirectScreenAccess* iDsa; + TBool iDrawingOn; + TBool iForeground; + }; + + +class CPicoDriveUi:public CAknAppUi,public MMdaAudioOutputStreamCallback +{ +public: + CPicoDriveUi(); + ~CPicoDriveUi(); + void ConstructL(); + void StartAsynchUpdate(); +protected: + static TInt AsyncUpdateL(TAny* aAppUi); + void StartEmulatorL(); + virtual TKeyResponse HandleKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType); + void HandleForegroundEventL(TBool aForeground); + // Menu drawers + void PutMainMenu(); + void PutScreenSelect(); + void PutControllerSelect(); + void PutConfigKeys(); + void PutSoundSelect(); + void PutCheatSelect(); + void PutAbout(TBool iOnlyRedraw = EFalse); + + // Asynch screen update callback + void UpdateScreen(); + + TInt SelectFile(TFileName& aFileName); + // Emulation functions + int EmulateInit(); + void EmulateExit(); + int EmulateFrame(); + int InputFrame(); + int TargetInit(); + void CalulateLineStarts(); + + static TInt IdleCallBackStop(TAny* aAppUi); + static TInt StartEmulatorL(TAny* aAppUi); + // Settings storage + void SaveSettingsL(); + void InternalizeL(const CDictionaryStore& aStore); + void ExternalizeL( CDictionaryStore& aStore); + + // Save state handling + int saveLoadGame(int load, int sram); + + /** + * Calculates the palette table 0-4096 + */ + void CalculatePaletteTable(); + CAsyncCallBack iIdleCallBack; + + // Variables + TUint16 iPad1; + TUint16 iPad2; + TFileName iRomName; + char RomName[260]; + TInt iScanCodes[EPicoNoKeys]; + TInt iCurrentScan; + CDesCArrayFlat* iKeyNames; + CDesCArrayFlat* iRegNames; + TBool iEmuRunning; + CQPicoDriveView* iView; + TInt iResourceFileId; + CAsyncCallBack iStartUp; + CFbsBitmap* iBackBuffer; + TFileName iAppPath; + TPoint iPutPoint; + TRect iPutRect; + TInt iSelection; + TInt iSndSelection; + TInt iCtrlSelection; + TInt iCheatSelection; + TInt iNoCheats; + TBool iCheatEnter; + CEikDialog* iCheatDlg; + TInt iListOffset; + TInt iScrMode; + TInt iLastScrMode; + TBool iRomLoaded; + TBool iInterpolate; + TBool iStretch; + TBool iEnableSixButtons; + TPicoMenus iPicoMenu; + CAsyncCallBack iAsyncUpdate; + + // sound support + CMdaAudioOutputStream* iSndStream; + TMdaAudioDataSettings iAudioSettings; + TBuf8<442*2*6> iMonoSound; + TInt iCurrentSeg; + TBool iEnableSound; + TBool iSndRateChanged; + TInt iSoundVolume; // 0-10 in 10% percent + void MaoscOpenComplete(TInt aError); + void MaoscBufferCopied(TInt aError, const TDesC8& aBuffer); + void MaoscPlayComplete(TInt aError); + // Update the sound output rate + TBool UpdatePSndRate(); + + // Rom pointers + unsigned char *RomData; + unsigned int RomSize; + + TInt64 LastSecond; + int FramesDone; + int FramesPerSecond; + TDisplayMode iDisplayMode; + TInt iLastAboutPos; + TBool iFirstStart; + TInt iFrameSkip; + TInt iFontHeight; + int (*myPicoScan)(unsigned int scan,unsigned short *pal); + TBuf<1024> iTempString; + // make save filename + char saveFname[KMaxFileName]; + +}; + +#endif diff --git a/platform/s60/PicoDriveS60.mmp b/platform/s60/PicoDriveS60.mmp new file mode 100644 index 00000000..8d5d01ba --- /dev/null +++ b/platform/s60/PicoDriveS60.mmp @@ -0,0 +1,37 @@ +target PicoDrive.exe +TARGETTYPE exedll +TARGETPATH system\apps\PicoDriveS60 +SOURCEPATH ..\S60 +source picodriveexe.cpp +sourcepath .. +source unzip.c +#ifndef WINS +sourcepath ..\gcc +source libgcc2.c +#endif + +SYSTEMINCLUDE \epoc32\include \epoc32\include\libc +USERINCLUDE ..\pico ..\pico\sound ..\s60 .. +// libraries +library cone.lib EIKCORE.lib MEDIACLIENTAUDIOSTREAM.LIB +library euser.lib zlib.lib +library efsrv.lib estlib.lib fbscli.lib estor.lib eikcoctl.lib +library ws32.lib AVKON.LIB bafl.lib bitgdi.lib eikdlg.lib + +staticlibrary pico.lib + +#if defined(WINS) +staticlibrary a68k.obj +staticlibrary mz80_asm.obj +#else +staticlibrary cyclone.o +staticlibrary DRZ80.o +staticlibrary draw.o +//staticlibrary blit.o +staticlibrary ym2612_helper.o +staticlibrary memory.o +staticlibrary draw2.o +#endif + +EPOCHEAPSIZE 1024000 8192000 +//EPOCSTACKSIZE 65535 diff --git a/platform/s60/PicoDriveS60.rss b/platform/s60/PicoDriveS60.rss new file mode 100644 index 00000000..e3e0950a --- /dev/null +++ b/platform/s60/PicoDriveS60.rss @@ -0,0 +1,150 @@ +// PicoDriveS60.RSS +// +// + +NAME Pico +#include +#include +#include +#include +RESOURCE RSS_SIGNATURE { } + +RESOURCE TBUF16 { buf=""; } + +RESOURCE EIK_APP_INFO + { + menubar = r_miniapp_menubar; + cba=R_AVKON_SOFTKEYS_OPTIONS_BACK; + } + + + +RESOURCE MENU_BAR r_miniapp_menubar // *** Menu bar +{ + titles = + { + MENU_TITLE { menu_pane = r_miniapp_menu; txt = "PicoDrive"; } + + }; +} + +RESOURCE MENU_PANE r_miniapp_menu // *** Submenu 1 +{ + items = + { + MENU_ITEM { command = EEikCmdExit; txt = "Close";} + }; +} + +RESOURCE ARRAY r_picodrive_keys +{ +items= +{ + LBUF{txt="Up";}, + LBUF{txt="Down";}, + LBUF{txt="Left";}, + LBUF{txt="Right";}, + LBUF{txt="A";}, + LBUF{txt="B";}, + LBUF{txt="C";}, + LBUF{txt="X";}, + LBUF{txt="Y";}, + LBUF{txt="Z";}, + LBUF{txt="Mode";}, + LBUF{txt="Start";}, + LBUF{txt="Up&Left";}, + LBUF{txt="Up&Right";}, + LBUF{txt="Down&Right";}, + LBUF{txt="Down&Left";}, + LBUF{txt="Soft reset";}, + LBUF{txt="Pan left";}, + LBUF{txt="Pan right";} + }; + } + + + + +RESOURCE DIALOG r_pico_file_select_dialog +{ +flags = EGeneralQueryFlags; +buttons = R_AVKON_SOFTKEYS_DONE_CANCEL; +items = +{ +DLG_LINE +{ +type = EAknCtListQueryControl; +id = EListQueryControl; + +control = AVKON_LIST_QUERY_CONTROL +{ +heading = "Files"; +listtype = EAknCtSinglePopupMenuListBox; +listbox = LISTBOX +{ +flags = EAknDialogSelectionList; +height = 3; +width = 1; +}; +}; +} +}; +} + +RESOURCE DIALOG r_pico_add_cheat +{ + title="Add cheatcode"; + flags=EEikDialogFlagNoDrag | + EEikDialogFlagCbaButtons | + EEikDialogFlagModeless|EEikDialogFlagWait; + buttons = R_AVKON_SOFTKEYS_OK_CANCEL; + items= + { + DLG_LINE + { + type=EEikCtLabel; + id=0x2002; + itemflags = EEikDlgItemNonFocusing; + control= LABEL + + { + txt = "Enter cheatcode"; + + }; + }, + DLG_LINE + { + itemflags = EEikDlgItemNonFocusing; + id=0x2001; + type=EEikCtLabel; + control= LABEL { + horiz_align=EEikLabelAlignHLeft; + txt = "\nGG: XXXX-XXXX\nPatch: XXXXXX:YYYY"; + }; + }, + DLG_LINE + { + type=EEikCtEdwin; + id=0x2000; + itemflags = EEikDlgItemOfferAllHotKeys|EEikDlgItemSeparatorAfter; + + control= EDWIN { + maxlength=12; + }; + + + } + }; +} + +RESOURCE ARRAY r_picodrive_regions +{ + items= + { + LBUF{txt="Region: Auto";}, + LBUF{txt="Region: Jap NTSC";}, + LBUF{txt="Region: Jap PAL";}, + LBUF{txt="Region: US NTSC";}, + LBUF{txt="Region: EUR PAL";} + }; +} diff --git a/platform/s60/PicoDriveS60Aif.rss b/platform/s60/PicoDriveS60Aif.rss new file mode 100644 index 00000000..ef40e19d --- /dev/null +++ b/platform/s60/PicoDriveS60Aif.rss @@ -0,0 +1,20 @@ +#include + + +RESOURCE AIF_DATA + { + app_uid= 0x101F9B49; + // + hidden=KAppNotHidden; + embeddability=KAppNotEmbeddable; + caption_list= + { + CAPTION { code=ELangEnglish; caption="PicoDrive"; }, + CAPTION { code=ELangAmerican; caption="PicoDrive"; } + }; + // + num_icons=1; + } + + + diff --git a/platform/s60/PicoDriveS60V3.mmp b/platform/s60/PicoDriveS60V3.mmp new file mode 100644 index 00000000..7247cbea --- /dev/null +++ b/platform/s60/PicoDriveS60V3.mmp @@ -0,0 +1,77 @@ +target PicoDrive.exe +TARGETTYPE exe +TARGETPATH sys\bin +SOURCEPATH ..\S60 +UID 0x100039ce 0xA00007BE +source picodriveexe.cpp +sourcepath .. +source unzip.c + +SYSTEMINCLUDE \epoc32\include \epoc32\include\libc +systeminclude \epoc32\include\mmf\plugin + +USERINCLUDE ..\pico ..\pico\sound ..\s60 .. +// libraries +library cone.lib EIKCORE.lib MEDIACLIENTAUDIOSTREAM.LIB +library euser.lib apparc.lib +library efsrv.lib estlib.lib fbscli.lib estor.lib eikcoctl.lib +library ws32.lib AVKON.LIB bafl.lib bitgdi.lib gdi.lib eikdlg.lib + +staticlibrary pico.lib + +#if defined(WINS) +staticlibrary a68k.obj +staticlibrary mz80_asm.obj +staticlibrary zlib.lib +#else +staticlibrary cyclone.o +staticlibrary DRZ80.o +staticlibrary draw.o +//staticlibrary blit.o +staticlibrary ym2612_helper.o +staticlibrary zlib.lib +staticlibrary memory.o +staticlibrary draw2.o +#endif + + +sourcepath ..\S60 + +DOCUMENT interpolatevideo.inl +DOCUMENT normalvideo.inl +DOCUMENT S60V3Video.inl +START RESOURCE PicoDrive_reg.rss +TARGETPATH \private\10003a3f\apps +END + +START RESOURCE PicoDrive_loc.rss +TARGETPATH \Resource\Apps +LANG SC +END + +SOURCEPATH ..\s60 +START RESOURCE PicoDrive.rss +HEADER +TARGETPATH \Resource\Apps +LANG SC +END + +START BITMAP PicoDrive.mbm +TARGETPATH \Resource\Apps +SOURCEPATH ..\s60 +// Source Color-depth Source-bitmap-list +// c denotes whether the bitmap is a colour bitmap and the digits represent the +// colour-depth of the bitmap and the bitmap mask respectively +SOURCE c24 PicoS.bmp +SOURCE 8 PicoSMI.bmp +SOURCE c24 PicoL.bmp +SOURCE 8 PicoLMI.bmp +END + + +MACRO S60V3 + +EPOCHEAPSIZE 1024000 8192000 + + +CAPABILITY NONE diff --git a/platform/s60/PicoDrive_Loc.rss b/platform/s60/PicoDrive_Loc.rss new file mode 100644 index 00000000..d3698cf7 --- /dev/null +++ b/platform/s60/PicoDrive_Loc.rss @@ -0,0 +1,22 @@ +#include + +// This file localise the applications icons and caption +RESOURCE LOCALISABLE_APP_INFO + { + caption_and_icon = + { + CAPTION_AND_ICON_INFO + { + // The caption text is defined in the rls file + caption = "PicoDrive"; + // Icons are used to represent applications in the + // application launcher and application title bar. + // The number_of_icons value identifies how many icons + // that exist in the icon_file. + number_of_icons = 2; + // Using the application icons. + icon_file = "\\Resource\\Apps\\PicoDrive.mbm"; + } + }; + } + diff --git a/platform/s60/PicoDrive_reg.rss b/platform/s60/PicoDrive_reg.rss new file mode 100644 index 00000000..d1d93635 --- /dev/null +++ b/platform/s60/PicoDrive_reg.rss @@ -0,0 +1,18 @@ +// All registration files need to #include appinfo.rh. +#include + +// All registration files must define UID2, which is always +// KUidAppRegistrationResourceFile, and UID3, which is the application's UID. +UID2 KUidAppRegistrationResourceFile +UID3 0xA00007BE // application UID + +// Registration file need to containo an APP_REGISTRATION_INFO resource that +// minimally needs to provide the name of the application binary (using the +// app_file statement). +RESOURCE APP_REGISTRATION_INFO + { + app_file = "PicoDrive"; // filename of application binary (minus extension) + // Specify the location of the localisable icon/caption definition file + localisable_resource_file = "\\Resource\\Apps\\PicoDrive_loc"; + } + diff --git a/platform/s60/PicoL.bmp b/platform/s60/PicoL.bmp new file mode 100644 index 00000000..578f0138 Binary files /dev/null and b/platform/s60/PicoL.bmp differ diff --git a/platform/s60/PicoLM.bmp b/platform/s60/PicoLM.bmp new file mode 100644 index 00000000..8586d825 Binary files /dev/null and b/platform/s60/PicoLM.bmp differ diff --git a/platform/s60/PicoLMI.bmp b/platform/s60/PicoLMI.bmp new file mode 100644 index 00000000..942cc1e9 Binary files /dev/null and b/platform/s60/PicoLMI.bmp differ diff --git a/platform/s60/PicoS.bmp b/platform/s60/PicoS.bmp new file mode 100644 index 00000000..33728b6b Binary files /dev/null and b/platform/s60/PicoS.bmp differ diff --git a/platform/s60/PicoSM.bmp b/platform/s60/PicoSM.bmp new file mode 100644 index 00000000..eb218a47 Binary files /dev/null and b/platform/s60/PicoSM.bmp differ diff --git a/platform/s60/PicoSMI.bmp b/platform/s60/PicoSMI.bmp new file mode 100644 index 00000000..f6f04137 Binary files /dev/null and b/platform/s60/PicoSMI.bmp differ diff --git a/platform/s60/Picodriveapps60.cpp b/platform/s60/Picodriveapps60.cpp new file mode 100644 index 00000000..ec1a293a --- /dev/null +++ b/platform/s60/Picodriveapps60.cpp @@ -0,0 +1,178 @@ +#include "PicoDriveAppS60.h" +#include +#include +#include +EXPORT_C CApaApplication* NewApplication() +{ + return (new CPicoDrive); +} + +CPicoDrive::CPicoDrive() +{ +} + + +CPicoDrive::~CPicoDrive() +{ +} + + +CApaDocument* CPicoDrive::CreateDocumentL() + { + return new (ELeave) CPicoDriveDoc(*this); + } +TUid CPicoDrive::AppDllUid() const + { + return TUid::Uid(0x101F9B49); + } + + +CPicoDriveDoc::CPicoDriveDoc(CEikApplication& aApp):CAknDocument(aApp) +{ +} + +CPicoDriveDoc::~CPicoDriveDoc() + { + } + +CEikAppUi* CPicoDriveDoc::CreateAppUiL() + { + return new (ELeave) CPicoDriveUi; + } + + +void CPicoDriveUi::HandleForegroundEventL(TBool aForeground) +{ + if(aForeground) + { + BringUpEmulatorL(); + } +} + +CPicoDriveUi::CPicoDriveUi() +{ +} + +CPicoDriveUi::~CPicoDriveUi() + { + + RemoveFromViewStack(*iView,iView); + DeregisterViewAndRemoveStack(*iView); + delete iView; + if(iWatcher) + { + iThreadWatch.LogonCancel(iWatcher->iStatus); + iWatcher->Cancel(); + } + delete iWatcher; + + iThreadWatch.Close(); + } + + +void CPicoDriveUi::ConstructL() + { + BaseConstructL(); + iView = new(ELeave)CPicoView; + iView->SetMopParent(this); + iView->ConstructL(); + RegisterViewAndAddStackL(*iView); + AddToViewStackL(*iView,iView); + SetDefaultViewL(*iView); + TBuf<128> startFile; + startFile = iEikonEnv->EikAppUi()->Application()->AppFullName(); + TParse parser; + parser.Set(startFile,NULL,NULL); + + startFile = parser.DriveAndPath(); +#ifndef __WINS__ + startFile.Append( _L("PicoDrive.EXE")); +#else + startFile.Append( _L("PicoDrive.DLL")); +#endif + CApaCommandLine* cmdLine=CApaCommandLine::NewLC(startFile); + RApaLsSession lsSession; + lsSession.Connect(); + CleanupClosePushL(lsSession); + lsSession.StartApp(*cmdLine,iThreadId); + CleanupStack::PopAndDestroy();//close lsSession + CleanupStack::PopAndDestroy(cmdLine); + User::After(500000);// Let the application start + TApaTaskList taskList(iEikonEnv->WsSession()); + TApaTask myTask=taskList.FindApp(TUid::Uid(0x101F9B49)); + myTask.SendToBackground(); + TApaTask exeTask=taskList.FindByPos(0); + iExeWgId=exeTask.WgId(); + if(iThreadWatch.Open(iThreadId)==KErrNone) + { + iWatcher = new (ELeave)CPicoWatcher; + iWatcher->iAppUi=this; + iThreadWatch.Logon(iWatcher->iStatus); + } +} + + +CPicoWatcher::CPicoWatcher():CActive(EPriorityStandard) +{ + CActiveScheduler::Add(this); + iStatus=KRequestPending; + SetActive(); +} + +CPicoWatcher::~CPicoWatcher() +{ +} +void CPicoWatcher::DoCancel() +{ +} + +void CPicoWatcher::RunL() +{ + iAppUi->HandleCommandL(EEikCmdExit); +} + +void CPicoDriveUi::BringUpEmulatorL() +{ + RThread thread; + if(thread.Open(iThreadId)==KErrNone) + { + thread.Close(); + TApaTask apaTask(iEikonEnv->WsSession()); + apaTask.SetWgId(iExeWgId); + apaTask.BringToForeground(); + } + else + { + iExeWgId=-1; + } +} + + + +void CPicoDriveUi::HandleCommandL(TInt aCommand) +{ + + switch(aCommand) + { + case EEikCmdExit: + { + RThread thread; + if(thread.Open(iThreadId)==KErrNone) + { + thread.Terminate(0); + thread.Close(); + } + Exit(); + } + break; + + } +} + +GLDEF_C TInt E32Dll(TDllReason) +{ + return KErrNone; +} + + + diff --git a/platform/s60/Picodriveapps60.h b/platform/s60/Picodriveapps60.h new file mode 100644 index 00000000..9647a3b0 --- /dev/null +++ b/platform/s60/Picodriveapps60.h @@ -0,0 +1,78 @@ +#ifndef picodriveapps60h +#define picodriveapps60h + +#include +#include +#include +#include +#include +#include +#include +class CPicoView:public MCoeView,public CCoeControl +{ +public: + CPicoView() {}; + ~CPicoView(){}; + void ConstructL(){CreateWindowL();SetRect(iEikonEnv->EikAppUi()->ClientRect());ActivateL();SetBlank();}; + void ViewDeactivated(){MakeVisible(EFalse);}; + void ViewActivatedL(const TVwsViewId& /*aPrevViewId*/,TUid /*aCustomMessageId*/,const TDesC8& /*aCustomMessage*/) + { + MakeVisible(ETrue); + } + TVwsViewId ViewId() const + { + TVwsViewId viewId(TUid::Uid(0x101F9B49),TUid::Uid(0x101010)); + return viewId; + } +}; + +class CPicoDrive:public CEikApplication +{ +public: + CPicoDrive(); + ~CPicoDrive(); + CApaDocument* CreateDocumentL(); + TUid AppDllUid() const; +}; + + +#include + +class CPicoDriveDoc:public CAknDocument +{ +public: + ~CPicoDriveDoc(); + CEikAppUi* CreateAppUiL(); + void ConstructL(); + CPicoDriveDoc(CEikApplication& aApplicaiton); +}; + +#include +class CPicoDriveUi; +class CPicoWatcher:public CActive +{ +public: + CPicoWatcher(); + ~CPicoWatcher(); + void DoCancel(); + void RunL(); + CPicoDriveUi* iAppUi; +}; + +class CPicoDriveUi:public CAknAppUi +{ +public: + CPicoDriveUi(); + ~CPicoDriveUi(); + void ConstructL(); + void HandleCommandL(TInt aCommand); + void HandleForegroundEventL(TBool aForeground); + void BringUpEmulatorL(); +private: + CPicoView* iView; + TThreadId iThreadId; + TInt iExeWgId; + RThread iThreadWatch; + CPicoWatcher* iWatcher; +}; +#endif \ No newline at end of file diff --git a/platform/s60/S60V3/ABLD.BAT b/platform/s60/S60V3/ABLD.BAT new file mode 100644 index 00000000..f074c88b --- /dev/null +++ b/platform/s60/S60V3/ABLD.BAT @@ -0,0 +1,15 @@ +@ECHO OFF + +REM Bldmake-generated batch file - ABLD.BAT +REM ** DO NOT EDIT ** + +perl -S ABLD.PL "\picodrive\s60\s60v3\\" %1 %2 %3 %4 %5 %6 %7 %8 %9 +if errorlevel==1 goto CheckPerl +goto End + +:CheckPerl +perl -v >NUL +if errorlevel==1 echo Is Perl, version 5.003_07 or later, installed? +goto End + +:End diff --git a/platform/s60/S60V3/bld.inf b/platform/s60/S60V3/bld.inf new file mode 100644 index 00000000..35b00f67 --- /dev/null +++ b/platform/s60/S60V3/bld.inf @@ -0,0 +1,12 @@ +PRJ_PLATFORMS + +GCCE winscw + + +PRJ_MMPFILES +..\pico.mmp BUILD_AS_ARM +..\picodriveS60V3.mmp BUILD_AS_ARM + + + + diff --git a/platform/s60/S60v3video.inl b/platform/s60/S60v3video.inl new file mode 100644 index 00000000..00e65b62 --- /dev/null +++ b/platform/s60/S60v3video.inl @@ -0,0 +1,371 @@ +static int EmulateScanFull16(unsigned int scan,unsigned short *data) +{ + unsigned short *ps=NULL,*end=NULL; + unsigned short *pd=NULL; + unsigned short *pdSrc1 = NULL; + unsigned short *pdSrc2 = NULL; + int screenScan; + + int index = 0; + int xpitch=0; + TInt retValue = 0; + if(scan<224) + retValue = 1-(gLineTable[scan+1]-gLineTable[scan]); + screenScan = gLineTable[scan]; + + if ((int)screenScan< 0) return 0; // Out of range + if ((int)screenScan>=Targ.view.iBr.iY) return 0; // Out of range + + pd=(unsigned short*)(Targ.screen+screenScan*2+Targ.screen_offset); + pdSrc1 = pd; + + xpitch=-(Targ.scanline_length>>1); + if((Pico.video.reg[12]&1)) + { + ps=data; end=ps+320; + do + { + if(gColumnStepTable[index]>1) + { + *pd = gColorMapTab[*ps]; + pd+=xpitch; + *pd = ((gColorMapTab[*ps]+gColorMapTab[*(ps+1)])>>1); + index++; + ps++; + } + else if(gColumnStepTable[index]>0) + { + *pd = gColorMapTab[*ps]; + index++; + ps++; + } + else + { + *pd = ((gColorMapTab[*ps]+gColorMapTab[*(ps+1)])>>1); + ps+=2; + index+=2; + } + pd+=xpitch; + } + while (ps1) + { + *pd = gColorMapTab[*ps]; + pd+=xpitch; + *pd = ((gColorMapTab[*ps]+gColorMapTab[*(ps+1)])>>1); + index++; + } + else if(gNarrowColumnStepTable[index]>0) + { + *pd = gColorMapTab[*ps]; + ps++; + index++; + } + else + { + *pd = ((gColorMapTab[*ps]+gColorMapTab[*(ps+1)])>>1); + ps+=2; + index+=2; + } + pd+=xpitch; + } + while (ps0 && screenScan != gLineTable[scan-1]+1) + { + pdSrc2 = pdSrc1-2; + pd = pdSrc1-1; + + for(TInt loop=0;loop>1); + pd+=xpitch; + pdSrc1+=xpitch; + pdSrc2+=xpitch; + } + + } + + return retValue; +} + +static int EmulateScanFullRight16(unsigned int scan,unsigned short *data) +{ + unsigned short *ps=NULL,*end=NULL; + unsigned short *pd=NULL; + unsigned short *pdSrc1 = NULL; + unsigned short *pdSrc2 = NULL; + int screenScan; + int xpitch=0; + int retValue = 0; + int index = 0; + if(scan<224) + retValue = 1-(gLineTable[scan+1]-gLineTable[scan]); + screenScan = gLineTable[scan]; + + if ((int)screenScan< 0) return 0; // Out of range + if ((int)screenScan>=Targ.view.iBr.iY) return 0; // Out of range + + pd=(unsigned short*)(Targ.screen+Targ.scanline_length-screenScan*2); + pdSrc1 = pd; + + xpitch=+(Targ.scanline_length>>1); + if((Pico.video.reg[12]&1)) + { + ps=data; end=ps+320; + do + { + if(gColumnStepTable[index]>1) + { + *pd = gColorMapTab[*ps]; + pd+=xpitch; + *pd = ((gColorMapTab[*ps]+gColorMapTab[*(ps+1)])>>1); + index++; + ps++; + } + else if(gColumnStepTable[index]>0) + { + *pd = gColorMapTab[*ps]; + index++; + ps++; + } + else + { + *pd = ((gColorMapTab[*ps]+gColorMapTab[*(ps+1)])>>1); + ps+=2; + index+=2; + } + pd+=xpitch; + } + while (ps1) + { + *pd = gColorMapTab[*ps]; + pd+=xpitch; + *pd = ((gColorMapTab[*ps]+gColorMapTab[*(ps+1)])>>1); + index++; + } + else if(gNarrowColumnStepTable[index]>0) + { + *pd = gColorMapTab[*ps]; + ps++; + index++; + } + else + { + *pd = ((gColorMapTab[*ps]+gColorMapTab[*(ps+1)])>>1); + ps+=2; + index+=2; + } + pd+=xpitch; + } + while (ps0 && screenScan != gLineTable[scan-1]+1) + { + pdSrc2 = pdSrc1+2; + pd = pdSrc1+1; + + for(TInt loop=0;loop>1); + pd+=xpitch; + pdSrc1+=xpitch; + pdSrc2+=xpitch; + } + + } + + return retValue; +} + + + +static int EmulateScan16(unsigned int scan,unsigned short *data) +{ + // int len=0; + unsigned short *ps=NULL,*end=NULL; + unsigned short *pd=NULL; + int xpitch=0; + int retValue = 0; + int index = 0; + + if(scan<224) + retValue = 1-(gLineTable[scan+1]-gLineTable[scan]); + scan = gLineTable[scan]; + + if ((int)scan< 0) return 0; // Out of range + if ((int)scan>=Targ.view.iBr.iY) return 0; // Out of range + + pd=(unsigned short*)(Targ.screen+scan*Targ.scanline_length); + + xpitch=2; + if((Pico.video.reg[12]&1)) + { + ps=data; end=ps+320; + do + { + if(gColumnStepTable[index]>0) + { + *pd = gColorMapTab[*ps]; + ps++; + + index++; + } + else + { + *pd = ((gColorMapTab[*ps]+gColorMapTab[*(ps+1)])>>1); + ps+=2; + index+=2; + } + pd++; + + } + while (ps0) + { + *pd = gColorMapTab[*ps]; + ps++; + index++; + } + else + { + *pd = ((gColorMapTab[*ps]+gColorMapTab[*(ps+1)])>>1); + ps+=2; + index+=2; + } + pd++; + } + while (ps=Targ.view.iBr.iY) + return 0; // Out of range + + pd=(unsigned short*)(Targ.screen+screenScan*Targ.scanline_length); + pdSrc1 = pd; + + if((Pico.video.reg[12]&1)) + { + ps=data; end=ps+320; + do + { + if(gColumnStepTable[index]>1) + { + *pd = gColorMapTab[*ps]; + pd++; + *pd = ((gColorMapTab[*ps]+gColorMapTab[*(ps+1)])>>1); + index++; + ps++; + } + else if(gColumnStepTable[index]>0) + { + *pd = gColorMapTab[*ps]; + index++; + ps++; + } + else + { + *pd = ((gColorMapTab[*ps]+gColorMapTab[*(ps+1)])>>1); + ps+=2; + index+=2; + } + pd++; + } + while (ps1) + { + *pd = gColorMapTab[*ps]; + pd++; + *pd = ((gColorMapTab[*ps]+gColorMapTab[*(ps+1)])>>1); + index++; + } + else if(gNarrowColumnStepTable[index]>0) + { + *pd = gColorMapTab[*ps]; + ps++; + index++; + } + else + { + *pd = ((gColorMapTab[*ps]+gColorMapTab[*(ps+1)])>>1); + ps+=2; + index+=2; + } + pd++; + } + while (ps0 && screenScan != gLineTable[scan-1]+1) + { + pdSrc2 = pdSrc1-Targ.scanline_length; + pd = pdSrc1-(Targ.scanline_length>>1); + + for(TInt loop=0;loop>1); + pd++; + pdSrc1++; + pdSrc2++; + } + + } + + return retValue; +} diff --git a/platform/s60/bld.inf b/platform/s60/bld.inf new file mode 100644 index 00000000..c0432ec3 --- /dev/null +++ b/platform/s60/bld.inf @@ -0,0 +1,12 @@ +PRJ_PLATFORMS + +WINS ARMI arm4 thumb winscw + + +PRJ_MMPFILES +.\pico.mmp +.\picodriveS60.mmp +.\PicoDriveAppS60.mmp + + + diff --git a/platform/s60/c.bat b/platform/s60/c.bat new file mode 100644 index 00000000..0233a31e --- /dev/null +++ b/platform/s60/c.bat @@ -0,0 +1 @@ +createsis sign -key key-gen1.key -cert cert-gen1.cer -pass pico picodrives603rd.sis PicoS603rd.sis \ No newline at end of file diff --git a/platform/s60/cert-gen.cer b/platform/s60/cert-gen.cer new file mode 100644 index 00000000..c67cdb01 --- /dev/null +++ b/platform/s60/cert-gen.cer @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDRzCCAwWgAwIBAgIBADALBgcqhkjOOAQDBQAwgYgxEjAQBgNVBAoTCVBpY29E +cml2ZTFyMHAGA1UEAxNpUGljb0RyaXZlUzYwIDNyZCBFZGl0aW9uIGI2YjM0MGEw +NDUwZWZiOGVhMWU5Nzg0ZjhlMTc3NDkzYWUxZTk3M2I2YzFlZTQ4YzdjZTc5NTRm +YTE1NzMzMjNkNzZjNWJjOThmM2QxYWIzMB4XDTA2MDczMDE0MjQzNFoXDTA3MDcz +MDE0MjQzNFowgYgxEjAQBgNVBAoTCVBpY29Ecml2ZTFyMHAGA1UEAxNpUGljb0Ry +aXZlUzYwIDNyZCBFZGl0aW9uIGI2YjM0MGEwNDUwZWZiOGVhMWU5Nzg0ZjhlMTc3 +NDkzYWUxZTk3M2I2YzFlZTQ4YzdjZTc5NTRmYTE1NzMzMjNkNzZjNWJjOThmM2Qx +YWIzMIIBtjCCASsGByqGSM44BAEwggEeAoGBAKFNfGnxxT6j7q2lPQt1MnJckjyY +hYC6obfgf6gE/3XV0zNFU5TZlQkZph78m4Zp4GtK5oW/spVyCLfnwgs4UnH0E3tf +MOG1wXDhaHLjgAENiD4iQbumqTN5ri0wXcqnJC5rigk//TR3mvZ7JvjDeaMXK+Xu +gE/1uF8JoxAQHC/zAhUAl8PPPiuqVpZ6bWAwDeyBmHsKOOUCgYA6cPQiswwNVZWZ +mF5DALTAm6/zrPUkmBbe8Vk2jW37lVpIoLCJofNskNpshe4ZTTHtGOgzhjaCOsgL +juf2O0QqhZG8Wwhzo2fNosbZWxonSmmg1JIKn/32oK6FjaK3VAWno+lgGK0GhTC6 +Or+HqvvLdtaBeXHqrZWBXfvbYU8XAAOBhAACgYBVTFzZLgkclbXWAsszLExHwCYm +p3Jw10VfNBJxiYq5JxP+jifLLwt9nyt65h4N/y3AyYxL/f11mU7XUGsTU7x4U3NF +9WStFmpBOlJ1MrH09v2L1yi/D8gA7wfRgerErIadurc3ZcfqHyiafaoABzGczttq +vE1o/BRWm+GmciQjVjALBgcqhkjOOAQDBQADLwAwLAIUMc/hS91kPFwtmUO7j4Dp +3deMtZQCFGigHND6/mfaWOyfip4mQe2s4l4T +-----END CERTIFICATE----- diff --git a/platform/s60/cert-gen1.cer b/platform/s60/cert-gen1.cer new file mode 100644 index 00000000..72bfa5a9 --- /dev/null +++ b/platform/s60/cert-gen1.cer @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDSTCCAwagAwIBAgIBADALBgcqhkjOOAQDBQAwgYgxEjAQBgNVBAoTCVBpY29E +cml2ZTFyMHAGA1UEAxNpUGljb0RyaXZlUzYwIDNyZCBFZGl0aW9uIDY3MzZkOWY0 +NjZjMDNmY2Y3MmE2ZDhkYTgxYWFlZjEyYWFlOTc3NDExZmEyZDM0ZDY2MDE5Zjk1 +NmRiMzA2NmUyNTkyZjE0NTNlMjBhNDc2MB4XDTA2MDgwMjIyMjI0MFoXDTA3MDgw +MjIyMjI0MFowgYgxEjAQBgNVBAoTCVBpY29Ecml2ZTFyMHAGA1UEAxNpUGljb0Ry +aXZlUzYwIDNyZCBFZGl0aW9uIDY3MzZkOWY0NjZjMDNmY2Y3MmE2ZDhkYTgxYWFl +ZjEyYWFlOTc3NDExZmEyZDM0ZDY2MDE5Zjk1NmRiMzA2NmUyNTkyZjE0NTNlMjBh +NDc2MIIBtzCCASwGByqGSM44BAEwggEfAoGBALRUuJYcdrh5PdDdpsN2t4mBhNy2 +Vy+GEF2LR8KzHXB27KdAYvqhQmpCJ6gMyC3zvg6Gw1s0lyO/f+HI563qqUYFgxbx +ka4F2lWxeQOnw/bB2NhG/WGqVPHsARyg8+RI1cfVwHo67Fj91aftE0gTUzw/ZiCT +QYrLxvuaatiyrKP9AhUAlk4NyEkcgRkZeyiae/QaIq9VScECgYEArw/5SQAoluMg +8y0VqTZp23e8zsBN46VwYOq4kBY4b1Evl6UoX20hcWtanqvozlkLKEVP/BbCHut7 +YUgy/zPtAc4hv/biUd1uEIsCf/4NvVBP5NBHal0xzcJQQDMiA0nha3igOQ4v2ItT +Oqsts0HDzxK3OxC3XuirRiOlLTSywKADgYQAAoGACbtcf0HKOT2ZD5n+KUJDOZS2 +ipJsSQUjVdJqgcZo+M6+Hg9KpSIMTexr3CW3JtvwNZx4hh5EbtyuYiYnjmTX611L +258Ytr1pw93F7LztO/H0GOCU977Y7s/UZtoF/XJiGKKuYGLEiBIzBWUEchvDgpIB +J0D1lZa5JLfrt6i68pkwCwYHKoZIzjgEAwUAAzAAMC0CFBseBBEe6eFXOP0Oo1T1 +sdN2bzfyAhUAilFr5j3mPd3p0Gs+hZe+33NzSdg= +-----END CERTIFICATE----- diff --git a/platform/s60/createS60v3.bat b/platform/s60/createS60v3.bat new file mode 100644 index 00000000..0233a31e --- /dev/null +++ b/platform/s60/createS60v3.bat @@ -0,0 +1 @@ +createsis sign -key key-gen1.key -cert cert-gen1.cer -pass pico picodrives603rd.sis PicoS603rd.sis \ No newline at end of file diff --git a/platform/s60/install.txt b/platform/s60/install.txt new file mode 100644 index 00000000..83582749 --- /dev/null +++ b/platform/s60/install.txt @@ -0,0 +1,112 @@ +Welcome to the S60 version +of Picodrive! + +Credits +------- +This work is mainly based on +Picodrive by Dave, +(www.finalburn.com) +with added sound support and other improvements by Notaz +(http://notaz.atspace.com). + +ARM asm Z80 core is provided by DrZ80 by Reezy +(http://reesy.gp32x.de/) +and YM2612 and SN76489 support are provided by the M.A.M.E project +(http://www.mame.net/). + +See credits within Picodrive for more information. + +Instructions +------------ +Picodrive S60 is a Megadrive/ Genesis emulator which enables you to play old games on your S60 phone. + +When its started you are presented with a main menu. + +Use arrows to navigate up and down in the menu and use left softkey or the middle button to select an option + +* Load ROM +Displays a simple built in filebrowser. Displays the last folder you browsed,and default this is top level, with a drive listine (E: is your memory card) + +Use the left soft key (right softkey will cancel) and then navigate until you are in the folder with your rom files. +Use the left softkey to select a file, and emulation will comence as soon as the rom has been loaded. + +Supported data types are either SMD,BIN or a ZIP with a single SMD or BIN file inside. + +* Load state +Only working when a rom has been loaded, used to load a saved game state for the currently loaded rom. Emulation will resume automatically when the state has been loaded. + +* Save state +Only working when a rom has been loaded. Saves the current state of a rom. + +* Configure controls +Lets you configure the controls to use for game play. +Only one control at port 1 is supported. It might be either a 3 button or 6 button joypad. +Select using the confirm/left softkey and return to the main menu using the 'C' key. +Default is +3 button pad. +Up - Joystick up +Down - Joystick down +Left - Joystick left +Right - Joystick right + A - Left soft key + B - Middle/confirm key + C - Right soft key + X - Not configured + Y - Not configured + Z - Not configured +Start - '0' key +Up&Left - Not configured +Up&Right - Not configured +Down&Right - Not configured +Down&Left - Not configured + +'C' key is used to get back to the main menu when running the emulation and should not be used for anything else. + +3 button pad/6 button pad - Selects to toggle between the two pad types + +Configure keys - Select this to redefine the key bindings +Press the key you want to assign to the requested action. +You can assign the same key to the same action, and is good if you dont need the 8 way controls. + +* Configure screen +Lets you configure the screen mode and frameskip. +Use left softkey or confirm key to select mode. After adjust interpolate or frameskip, select a screen mode to exit the menu + +Portrait is a scaled mode, to 176x168 (default) +Landscape modes are a portrait mode which scales down to 208x168 +Portrait stretched is a scaled modenot in aspect, and scales to 176x208 + +Interpolate on means that a scanline is interpolated to a smoother look, but this also requires more cpu. +(default on) + +Frameskip lets you decide if you want to set your own constant frameskip or let the action decide +(default is auto) + + +* Configure sound +Lets you configure sound settings. +Use confirm or left soft key to change a value and use the 'c' key to exit to the main menu + +Z80 - Used in many games to drive the sound Will cost a penalty in shown FPS, but can increase compability if enabled even if sound is turned off. +(default is on) +YM2612 - FM OPL sound Enable for FM sound +(default is on) +SN76496 - TI Sound chip - Enable for sound +(default is on) +Volume - Select to change volume +(Default is 60%) +Sample rate - Select to toggle between 8Khz,11Khz,16Khz and 22Khz. If you select a rate which is not compatible with your phone it will be reset back to 8Khz. +(default is 8KHZ) + +* Reset +Will reset the current rom if loaded, and resume execution from the start + +* Credits +Displays a full credits list for the Picodrive project + +* Exit +Exit Picodrive + +Last line will display the name of the rom currently loaded + +Please enjoy and have fun. \ No newline at end of file diff --git a/platform/s60/interpolatevideo.inl b/platform/s60/interpolatevideo.inl new file mode 100644 index 00000000..a0fa3f58 --- /dev/null +++ b/platform/s60/interpolatevideo.inl @@ -0,0 +1,213 @@ +static int EmulateScanFull16_176Interpolate(unsigned int scan,unsigned short *data) +{ + unsigned short *ps=NULL,*end=NULL; + unsigned char *pd=NULL; + int xpitch=0; + TInt retValue = 0; + if(scan<224) + retValue = 1-(gLineTable[scan+1]-gLineTable[scan]); + scan = gLineTable[scan]; + + if ((int)scan< 0) return 0; // Out of range + if ((int)scan>=176) return 0; // Out of range + + pd=Targ.screen+gLineOffsets[scan];//Targ.screen+scan*2+Targ.screen_offset+8; + + xpitch=-Targ.scanline_length; + if((Pico.video.reg[12]&1)) + { + ps=data; end=ps+320; + // Reduce 14 pixels into 9 + do + { + *(unsigned short *)pd=gColorMapTab[ps[0]];pd+=xpitch; + *(unsigned short *)pd=(unsigned short)((gColorMapTab[ps[1]]+gColorMapTab[ps[2]])>>1);pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[3]];pd+=xpitch; + *(unsigned short *)pd=(unsigned short)((gColorMapTab[ps[4]]+gColorMapTab[ps[5]])>>1);pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[6]];pd+=xpitch; + *(unsigned short *)pd=(unsigned short)((gColorMapTab[ps[7]]+gColorMapTab[ps[8]])>>1);pd+=xpitch; + *(unsigned short *)pd=(unsigned short)((gColorMapTab[ps[9]]+gColorMapTab[ps[10]])>>1);pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[11]];pd+=xpitch; + *(unsigned short *)pd=(unsigned short)((gColorMapTab[ps[12]]+gColorMapTab[ps[13]])>>1);pd+=xpitch; + ps+=14; + } + while (ps>1);pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[4]];pd+=xpitch; + ps+=5; + } + while (ps=176) return 0; // Out of range + + pd=Targ.screen+gLineOffsets[scan];//Targ.screen+Targ.scanline_length-scan*2-8; + + xpitch=+Targ.scanline_length; + if((Pico.video.reg[12]&1)) + { + ps=data; end=ps+320; + // Reduce 14 pixels into 9 + do + { + *(unsigned short *)pd=gColorMapTab[ps[0]];pd+=xpitch; + *(unsigned short *)pd=(unsigned short)((gColorMapTab[ps[1]]+gColorMapTab[ps[2]])>>1);pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[3]];pd+=xpitch; + *(unsigned short *)pd=(unsigned short)((gColorMapTab[ps[4]]+gColorMapTab[ps[5]])>>1);pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[6]];pd+=xpitch; + *(unsigned short *)pd=(unsigned short)((gColorMapTab[ps[7]]+gColorMapTab[ps[8]])>>1);pd+=xpitch; + *(unsigned short *)pd=(unsigned short)((gColorMapTab[ps[9]]+gColorMapTab[ps[10]])>>1);pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[11]];pd+=xpitch; + *(unsigned short *)pd=(unsigned short)((gColorMapTab[ps[12]]+gColorMapTab[ps[13]])>>1);pd+=xpitch; + ps+=14; + } + while (ps>1);pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[4]];pd+=xpitch; + ps+=5; + } + while (ps=176) return 0; // Out of range + + pd=Targ.screen+gLineOffsets[scan];//Targ.screen+scan*Targ.scanline_length; + + xpitch=2; + if((Pico.video.reg[12]&1)) + { + ps=data; end=ps+320; + // Reduce 9 pixels into 5 + do + { + *(unsigned short *)pd=(unsigned short)((gColorMapTab[ps[0]]+gColorMapTab[ps[1]])>>1);pd+=xpitch; + *(unsigned short *)pd=(unsigned short)((gColorMapTab[ps[2]]+gColorMapTab[ps[3]])>>1);pd+=xpitch; + *(unsigned short *)pd=(unsigned short)((gColorMapTab[ps[4]]+gColorMapTab[ps[5]])>>1);pd+=xpitch; + *(unsigned short *)pd=(unsigned short)((gColorMapTab[ps[6]]+gColorMapTab[ps[7]])>>1);pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[8]];pd+=xpitch; + ps+=9; + } + while (ps>1);pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[3]];pd+=xpitch; + *(unsigned short *)pd=(unsigned short)((gColorMapTab[ps[4]]+gColorMapTab[ps[5]])>>1);pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[6]];pd+=xpitch; + *(unsigned short *)pd=(unsigned short)((gColorMapTab[ps[7]]+gColorMapTab[ps[8]])>>1);pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[9]];pd+=xpitch; + ps+=10; + } + while (ps=208) + return 0; // Out of range + + pd=Targ.screen+gLineOffsets[scan];//Targ.screen+scan*Targ.scanline_length; + + xpitch=2; + if((Pico.video.reg[12]&1)) + { + ps=data; end=ps+320; + // Reduce 9 pixels into 5 + do + { + *(unsigned short *)pd=(unsigned short)((gColorMapTab[ps[0]]+gColorMapTab[ps[1]])>>1);pd+=xpitch; + *(unsigned short *)pd=(unsigned short)((gColorMapTab[ps[2]]+gColorMapTab[ps[3]])>>1);pd+=xpitch; + *(unsigned short *)pd=(unsigned short)((gColorMapTab[ps[4]]+gColorMapTab[ps[5]])>>1);pd+=xpitch; + *(unsigned short *)pd=(unsigned short)((gColorMapTab[ps[6]]+gColorMapTab[ps[7]])>>1);pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[8]];pd+=xpitch; + ps+=9; + } + while (ps>1);pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[3]];pd+=xpitch; + *(unsigned short *)pd=(unsigned short)((gColorMapTab[ps[4]]+gColorMapTab[ps[5]])>>1);pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[6]];pd+=xpitch; + *(unsigned short *)pd=(unsigned short)((gColorMapTab[ps[7]]+gColorMapTab[ps[8]])>>1);pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[9]];pd+=xpitch; + ps+=10; + } + while (ps=176) return 0; // Out of range + + pd=Targ.screen+gLineOffsets[scan];//Targ.screen+scan*2+Targ.screen_offset+8; + + xpitch=-Targ.scanline_length; + if(Pico.video.reg[12]&1) + { + ps=data; end=ps+320; + // Reduce 14 pixels into 9 + do + { + *(unsigned short *)pd=gColorMapTab[ps[0]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[1]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[3]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[4]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[6]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[7]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[9]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[11]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[12]];pd+=xpitch; + ps+=14; + } + while (ps=176) return 0; // Out of range + + pd=Targ.screen+gLineOffsets[scan];//Targ.screen+Targ.scanline_length-scan*2-8; + + xpitch=+Targ.scanline_length; + if(Pico.video.reg[12]&1) + { + ps=data; end=ps+320; + // Reduce 14 pixels into 9 + do + { + *(unsigned short *)pd=gColorMapTab[ps[0]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[1]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[3]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[4]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[6]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[7]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[9]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[11]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[12]];pd+=xpitch; + ps+=14; + } + while (ps=176) return 0; // Out of range + + pd=Targ.screen+gLineOffsets[scan];//Targ.screen+scan*Targ.scanline_length; + + xpitch=2; + if(Pico.video.reg[12]&1) + { + ps=data; end=ps+320; + // Reduce 9 pixels into 5 + do + { + *(unsigned short *)pd=gColorMapTab[ps[0]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[2]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[4]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[6]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[8]];pd+=xpitch; + ps+=9; + } + while (ps=208) + return 0; // Out of range + + pd=Targ.screen+gLineOffsets[scan];//Targ.screen+scan*Targ.scanline_length; + + xpitch=2; + if(Pico.video.reg[12]&1) + { + ps=data; end=ps+320; + // Reduce 9 pixels into 5 + do + { + *(unsigned short *)pd=gColorMapTab[ps[0]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[2]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[4]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[6]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[8]];pd+=xpitch; + ps+=9; + } + while (ps=208) + return 0; // Out of range + + pd=Targ.screen+gLineOffsets[scan];//Targ.screen+scan*Targ.scanline_length; + + xpitch=2; + ps=data+gFullOffset; end=ps+176; +/* if(!(Pico.video.reg[12]&1)) + { + ps=data+gFullOffset; end=ps+176; + } + else + { + ps=data+32+gFullOffset; end=ps+176; + }*/ + + // Draw 8 pixels in a row + do + { + *(unsigned short *)pd=gColorMapTab[ps[0]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[1]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[2]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[3]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[4]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[5]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[6]];pd+=xpitch; + *(unsigned short *)pd=gColorMapTab[ps[7]];pd+=xpitch; + ps+=8; + } + while (ps +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=PICO - Win32 Uni Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "PICO.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "PICO.mak" CFG="PICO - Win32 Uni Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "PICO - Win32 Uni Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "PICO - Win32 Uni Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "PICO - Win32 Uni Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\Win32_U0" +# PROP BASE Intermediate_Dir ".\Win32_U0" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "\s60v1\EPOC32\RELEASE\WINS\UDEB" +# PROP Intermediate_Dir "\s60v1\EPOC32\BUILD\PICODRIVE\S60\PICO\WINS\UDEB" +# ADD CPP /nologo /Zp4 /MDd /W4 /Zi /Od /X /I "\PICODRIVE\PICO" /I "\PICODRIVE\CYCLONE" /I "\s60v1\EPOC32\INCLUDE" /I "\s60v1\EPOC32\INCLUDE\LIBC" /D "__SYMBIAN32__" /D "__VC32__" /D "__WINS__" /D "__AVKON_ELAF__" /D "_USE_MZ80" /D "EMU_A68K" /D "_DEBUG" /D "_UNICODE" /FR /Fd"\s60v1\EPOC32\RELEASE\WINS\UDEB\PICO.PDB" /GF /c +# ADD BASE RSC /l 0x809 +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /machine:IX86 +# ADD LIB32 /nologo /subsystem:windows /machine:IX86 /nodefaultlib /out:"\s60v1\EPOC32\RELEASE\WINS\UDEB\PICO.LIB" + +!ELSEIF "$(CFG)" == "PICO - Win32 Uni Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\Win32_Un" +# PROP BASE Intermediate_Dir ".\Win32_Un" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "\s60v1\EPOC32\RELEASE\WINS\UREL" +# PROP Intermediate_Dir "\s60v1\EPOC32\BUILD\PICODRIVE\S60\PICO\WINS\UREL" +# ADD CPP /nologo /Zp4 /MD /W4 /O1 /Op /X /I "\PICODRIVE\PICO" /I "\PICODRIVE\CYCLONE" /I "\s60v1\EPOC32\INCLUDE" /I "\s60v1\EPOC32\INCLUDE\LIBC" /D "__SYMBIAN32__" /D "__VC32__" /D "__WINS__" /D "__AVKON_ELAF__" /D "_USE_MZ80" /D "EMU_A68K" /D "NDEBUG" /D "_UNICODE" /GF /c +# ADD BASE RSC /l 0x809 +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /machine:IX86 +# ADD LIB32 /nologo /subsystem:windows /machine:IX86 /nodefaultlib /out:"\s60v1\EPOC32\RELEASE\WINS\UREL\PICO.LIB" + +!ENDIF + +# Begin Target + +# Name "PICO - Win32 Uni Debug" +# Name "PICO - Win32 Uni Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=\PICODRIVE\PICO\Area.c +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\PICO\Cart.c +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\PICO\Draw.c +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\PICO\Draw2.c +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\PICO\Ggenie.c +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\PICO\Memory.c +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\PICO\Misc.c +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\PICO\Pico.c +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\PICO\Sek.c +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\PICO\Utils.c +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\PICO\Videoport.c +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\PICO\SOUND\Sn76496.c +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\PICO\SOUND\Sound.c +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\PICO\SOUND\Ym2612.c +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\S60\Pico.mmp +# PROP Exclude_From_Build 1 +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=\PICODRIVE\PICO\Ggenie.h +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\PICO\SOUND\Sn76496.h +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\PICO\SOUND\Ym2612.h +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\PICO\Pico.h +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\PICO\SOUND\Mz80.h +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\PICO\SOUND\Driver.h +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\PICO\SOUND\Sound.h +# End Source File +# Begin Source File + +SOURCE=\PICODRIVE\PICO\Picoint.h +# End Source File +# End Group +# End Target +# End Project diff --git a/platform/s60/pico.mmp b/platform/s60/pico.mmp new file mode 100644 index 00000000..0adc4449 --- /dev/null +++ b/platform/s60/pico.mmp @@ -0,0 +1,24 @@ +// *** Definitions + +TARGET pico.lib +TARGETTYPE lib +SOURCEPATH ..\pico + +source Area.c Cart.c Draw.c Memory.c Misc.c Pico.c Sek.c Utils.c VideoPort.c Draw2.c ggenie.c +// source Draw2.c +SYSTEMINCLUDE \epoc32\include \epoc32\include\libc +USERINCLUDE ..\pico ..\cyclone + +sourcepath ..\pico\sound +source sn76496.c sound.c ym2612.c +#ifdef WINS +MACRO _USE_MZ80 +MACRO EMU_A68K +#else +MACRO EMU_C68K +MACRO _USE_DRZ80 +MACRO _ASM_DRAW_C +MACRO _ASM_MEMORY_C +MACRO _USE_YM2612_ASM_HELPER +#endif + diff --git a/platform/s60/pico_UDEB.mak b/platform/s60/pico_UDEB.mak new file mode 100644 index 00000000..9fe91c20 --- /dev/null +++ b/platform/s60/pico_UDEB.mak @@ -0,0 +1,6 @@ + +BLD: UDEB +REBUILD : CLEANUDEB UDEB + +include pico.mak + diff --git a/platform/s60/pico_UREL.mak b/platform/s60/pico_UREL.mak new file mode 100644 index 00000000..0b68805b --- /dev/null +++ b/platform/s60/pico_UREL.mak @@ -0,0 +1,6 @@ + +BLD: UREL +REBUILD : CLEANUREL UREL + +include pico.mak + diff --git a/platform/s60/picodrives601st.pkg b/platform/s60/picodrives601st.pkg new file mode 100644 index 00000000..1ddd8853 --- /dev/null +++ b/platform/s60/picodrives601st.pkg @@ -0,0 +1,27 @@ +; +; Basic install file for picodriveS60 +; + +; Languages +; none - English only by default + +; Installation header +; Only one component name as we only support English +; UID is the app's UID +#{"PicoDriveS60 1st Edition "},( 0x101F9B49 ),0,60,0 +(0x101F6F88), 0, 0, 0, {"Series60ProductID"} +; Application file +"\epoc32\release\armi\urel\picodriveS60.app"-"!:\system\apps\picodriveS60\picodriveS60.app" +"\epoc32\release\armi\urel\picodrive.exe"-"!:\system\apps\picodriveS60\picodrive.exe" +"\epoc32\release\armi\urel\picodriveS60.rsc"-"!:\system\apps\picodriveS60\picodriveS60.rsc" +"\epoc32\release\armi\urel\picodriveS60.aif"-"!:\system\apps\picodriveS60\picodriveS60.aif" +""-"c:\system\apps\picodriveS60\picodriveS60.ini",FN + +".\install.txt"-"!:\system\apps\PicodriveS60\install.txt",FILETEXT +; Required files +; None +; Component .sis files +; None + + + \ No newline at end of file diff --git a/platform/s60/picodrives602nd.pkg b/platform/s60/picodrives602nd.pkg new file mode 100644 index 00000000..9eddda19 --- /dev/null +++ b/platform/s60/picodrives602nd.pkg @@ -0,0 +1,26 @@ +; +; Basic install file for picodriveS60 +; + +; Languages +; none - English only by default + +; Installation header +; Only one component name as we only support English +; UID is the app's UID +#{"PicoDriveS60 2nd Edition "},( 0x101F9B49 ),0,60,0 +(0x101F6F88), 0, 0, 0, {"Series60ProductID"} +; Application file +"\epoc32\release\armi\urel\picodriveS60.app"-"!:\system\apps\picodriveS60\picodriveS60.app" +"\epoc32\release\armi\urel\picodrive.exe"-"!:\system\apps\picodriveS60\picodrive.exe" +"\epoc32\data\z\system\apps\picodrives60\picodriveS60.rsc"-"!:\system\apps\picodriveS60\picodriveS60.rsc" +"\epoc32\data\z\system\apps\picodrives60\picodriveS60.aif"-"!:\system\apps\picodriveS60\picodriveS60.aif" +""-"c:\system\apps\picodriveS60\picodriveS60.ini",FN +".\install.txt"-"!:\system\apps\PicodriveS60\install.txt",FILETEXT +; Required files +; None +; Component .sis files +; None + + + \ No newline at end of file diff --git a/platform/s60/picodrives603rd.pkg b/platform/s60/picodrives603rd.pkg new file mode 100644 index 00000000..7c6225da --- /dev/null +++ b/platform/s60/picodrives603rd.pkg @@ -0,0 +1,35 @@ +; +; Basic install file for picodriveS60 +; + +; Languages +;Language - standard language definitions +&EN +; List of localised vendor names - one per language. At least one must be provided (English [EN]). +; List must correspond to list of languages specified elsewhere in the .pkg +%{"PicoDrive"} +; The non-localised, globally unique vendor name (mandatory) +:"PicoDrive" + +; Installation header +; Only one component name as we only support English +; UID is the app's UID +#{"PicoDriveS60 3rd Edition "},( 0xA00007BE ),0,50,0 +;Supports Series 60 v 3.0 +[0x101F7961], 0, 0, 0, {"Series60ProductID"} +; Application file +"\epoc32\release\gcce\urel\picodrive.exe"-"!:\sys\bin\picodrive.exe" +"\epoc32\data\z\resource\apps\picodrive.rsc"-"!:\resource\apps\picodrive.rsc" +"\epoc32\data\z\resource\apps\picodrive.mbm"-"!:\resource\apps\picodrive.mbm" +"\epoc32\data\z\resource\apps\picodrive_loc.rsc"-"!:\resource\apps\picodrive_loc.rsc" +"\epoc32\data\z\private\10003a3f\apps\picodrive_reg.rsc"-"!:\private\10003a3f\import\apps\picodrive_reg.rsc" + +""-"c:\private\A00007BE\picodriveS60.ini",FN +".\install.txt"-"!:\resource\apps\picodrive_install.txt",FILETEXT +; Required files +; None +; Component .sis files +; None + + + \ No newline at end of file diff --git a/platform/s60/picodrives60v3.dsp b/platform/s60/picodrives60v3.dsp new file mode 100644 index 00000000..bea20251 --- /dev/null +++ b/platform/s60/picodrives60v3.dsp @@ -0,0 +1,1542 @@ +# Microsoft Developer Studio Project File - Name="PicoDrive" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) External Target" 0x0106 + +CFG=PicoDrive - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "PicoDrive.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "PicoDrive.mak" CFG="PicoDrive - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "PicoDrive - Win32 Release" (based on "Win32 (x86) External Target") +!MESSAGE "PicoDrive - Win32 Debug" (based on "Win32 (x86) External Target") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" + +!IF "$(CFG)" == "PicoDrive - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\Debug" +# PROP BASE Intermediate_Dir ".\Debug" +# PROP BASE Cmd_Line "NMAKE /f PicoDrive.mak " +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "PicoDrive.exe" +# PROP BASE Bsc_Name "PicoDrive.bsc" +# PROP BASE Target_Dir "" +# PROP Use_MFC +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "\S60V3\EPOC32\RELEASE\WINSCW\UDEB" +# PROP Intermediate_Dir "\S60V3\EPOC32\BUILD\picodrive\s60\picodrives60v3\WINSCW\UDEB" +# PROP Cmd_Line ""\S60V3\epoc32\tools\MAKE.exe" -r -f picodrives60v3_UDEB.mak " +# PROP Rebuild_Opt "REBUILD" +# PROP Target_File "PicoDrive.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "PicoDrive - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\Release" +# PROP BASE Intermediate_Dir ".\Release" +# PROP BASE Cmd_Line "NMAKE /f PicoDrive.mak " +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "PicoDrive.exe" +# PROP BASE Bsc_Name "PicoDrive.bsc" +# PROP BASE Target_Dir "" +# PROP Use_MFC +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "\S60V3\EPOC32\RELEASE\WINSCW\UREL" +# PROP Intermediate_Dir "\S60V3\EPOC32\BUILD\picodrive\s60\picodrives60v3\WINSCW\UREL" +# PROP Cmd_Line ""\S60V3\epoc32\tools\MAKE.exe" -r -f picodrives60v3_UREL.mak " +# PROP Rebuild_Opt "REBUILD" +# PROP Target_File "PicoDrive.exe" +# PROP Bsc_Name "PicoDrive.bsc" +# PROP Target_Dir "" + + +!ENDIF + +# Begin Target + +# Name "PicoDrive - Win32 Debug" +# Name "PicoDrive - Win32 Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=\picodrive\S60\Picodrive_reg.rss +USERDEP__PicoDrive_reg="\S60V3\EPOC32\include\AppInfo.rh" "\S60V3\epoc32\include\variant\Symbian_OS_v9.1.hrh" +!IF "$(CFG)" == "PicoDrive - Win32 Debug" + +# PROP Intermediate_Dir "\S60V3\EPOC32\BUILD\picodrive\s60\picodrives60v3\WINSCW" +# Begin Custom Build - Building resources from Picodrive_reg.rss +InputPath=\picodrive\S60\Picodrive_reg.rss + +BuildCmds= \ + nmake -nologo -f "\picodrive\s60\picodrives60v3.SUP.MAKE"\ + "\S60V3\EPOC32\RELEASE\WINSCW\UDEB\Z\private\10003a3f\apps\PicoDrive_reg.r" + +"\S60V3\EPOC32\RELEASE\WINSCW\UDEB\Z\private\10003a3f\apps\PicoDrive_reg.rSC.dummy" : $(SOURCE) "$(INTDIR)"\ + "$(OUTDIR)" + $(BuildCmds) +# End Custom Build + +!ELSEIF "$(CFG)" == "PicoDrive - Win32 Release" + +# PROP Intermediate_Dir "\S60V3\EPOC32\BUILD\picodrive\s60\picodrives60v3\WINSCW" +# Begin Custom Build - Building resources from Picodrive_reg.rss +InputPath=\picodrive\S60\Picodrive_reg.rss + +BuildCmds= \ + nmake -nologo -f "\picodrive\s60\picodrives60v3.SUP.MAKE"\ + "\S60V3\EPOC32\RELEASE\WINSCW\UREL\Z\private\10003a3f\apps\PicoDrive_reg.r" + +"\S60V3\EPOC32\RELEASE\WINSCW\UREL\Z\private\10003a3f\apps\PicoDrive_reg.rSC.dummy" : $(SOURCE) "$(INTDIR)"\ + "$(OUTDIR)" + $(BuildCmds) +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=\picodrive\S60\Picodrive_loc.rss +USERDEP__PicoDrive_loc="\S60V3\EPOC32\include\AppInfo.rh" "\S60V3\epoc32\include\variant\Symbian_OS_v9.1.hrh" +!IF "$(CFG)" == "PicoDrive - Win32 Debug" + +# PROP Intermediate_Dir "\S60V3\EPOC32\BUILD\picodrive\s60\picodrives60v3\WINSCW" +# Begin Custom Build - Building resources from Picodrive_loc.rss +InputPath=\picodrive\S60\Picodrive_loc.rss + +BuildCmds= \ + nmake -nologo -f "\picodrive\s60\picodrives60v3.SUP.MAKE"\ + "\S60V3\EPOC32\RELEASE\WINSCW\UDEB\Z\Resource\Apps\PicoDrive_loc.r" + +"\S60V3\EPOC32\RELEASE\WINSCW\UDEB\Z\Resource\Apps\PicoDrive_loc.rSC.dummy" : $(SOURCE) "$(INTDIR)"\ + "$(OUTDIR)" + $(BuildCmds) +# End Custom Build + +!ELSEIF "$(CFG)" == "PicoDrive - Win32 Release" + +# PROP Intermediate_Dir "\S60V3\EPOC32\BUILD\picodrive\s60\picodrives60v3\WINSCW" +# Begin Custom Build - Building resources from Picodrive_loc.rss +InputPath=\picodrive\S60\Picodrive_loc.rss + +BuildCmds= \ + nmake -nologo -f "\picodrive\s60\picodrives60v3.SUP.MAKE"\ + "\S60V3\EPOC32\RELEASE\WINSCW\UREL\Z\Resource\Apps\PicoDrive_loc.r" + +"\S60V3\EPOC32\RELEASE\WINSCW\UREL\Z\Resource\Apps\PicoDrive_loc.rSC.dummy" : $(SOURCE) "$(INTDIR)"\ + "$(OUTDIR)" + $(BuildCmds) +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=\picodrive\s60\Picodrive.rss +USERDEP__PicoDrive="\S60V3\EPOC32\include\BADEF.RH" "\S60V3\EPOC32\include\BAERRRSVR.RH" "\S60V3\EPOC32\include\aknfontcategory.hrh" "\S60V3\EPOC32\include\aknfontidoffsets.hrh" "\S60V3\EPOC32\include\avkon.hrh" "\S60V3\EPOC32\include\avkon.rh" "\S60V3\EPOC32\include\avkon.rsg" "\S60V3\EPOC32\include\eikcdlg.rsg" "\S60V3\EPOC32\include\eikcoctl.rsg" "\S60V3\EPOC32\include\eikcolor.hrh" "\S60V3\EPOC32\include\eikcore.rsg" "\S60V3\EPOC32\include\eikctl.rsg" "\S60V3\EPOC32\include\eikon.hrh" "\S60V3\EPOC32\include\eikon.rh" "\S60V3\EPOC32\include\eikon.rsg" "\S60V3\EPOC32\include\gulftflg.hrh" "\S60V3\EPOC32\include\lafpublc.hrh" "\S60V3\EPOC32\include\uikon.hrh" "\S60V3\EPOC32\include\uikon.rh" "\S60V3\epoc32\include\variant\Symbian_OS_v9.1.hrh" +!IF "$(CFG)" == "PicoDrive - Win32 Debug" + +# PROP Intermediate_Dir "\S60V3\EPOC32\BUILD\picodrive\s60\picodrives60v3\WINSCW" +# Begin Custom Build - Building resources from Picodrive.rss +InputPath=\picodrive\s60\Picodrive.rss + +BuildCmds= \ + nmake -nologo -f "\picodrive\s60\picodrives60v3.SUP.MAKE"\ + "\S60V3\EPOC32\RELEASE\WINSCW\UDEB\Z\Resource\Apps\PicoDrive.r" + +"\S60V3\EPOC32\RELEASE\WINSCW\UDEB\Z\Resource\Apps\PicoDrive.rSC.dummy" : $(SOURCE) "$(INTDIR)"\ + "$(OUTDIR)" + $(BuildCmds) +# End Custom Build + +!ELSEIF "$(CFG)" == "PicoDrive - Win32 Release" + +# PROP Intermediate_Dir "\S60V3\EPOC32\BUILD\picodrive\s60\picodrives60v3\WINSCW" +# Begin Custom Build - Building resources from Picodrive.rss +InputPath=\picodrive\s60\Picodrive.rss + +BuildCmds= \ + nmake -nologo -f "\picodrive\s60\picodrives60v3.SUP.MAKE"\ + "\S60V3\EPOC32\RELEASE\WINSCW\UREL\Z\Resource\Apps\PicoDrive.r" + +"\S60V3\EPOC32\RELEASE\WINSCW\UREL\Z\Resource\Apps\PicoDrive.rSC.dummy" : $(SOURCE) "$(INTDIR)"\ + "$(OUTDIR)" + $(BuildCmds) +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=\picodrive\S60\Picodriveexe.cpp +# End Source File +# Begin Source File + +SOURCE=\picodrive\Unzip.c +# End Source File +# Begin Source File + +SOURCE=\picodrive\s60\Picodrive.uid.cpp +# End Source File +# Begin Source File + +SOURCE=\picodrive\S60\S60v3video.inl +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=\picodrive\S60\Interpolatevideo.inl +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=\picodrive\S60\Normalvideo.inl +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=\picodrive\s60\Picodrives60v3.mmp +# PROP Exclude_From_Build 1 +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mmf\common\Mmffourcc.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Mda\Common\Base.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikaufty.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknmultilinequerycontrol.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\S32buf.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknlayout2id.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Ecom\Ecomresolverparams.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikfpne.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknintermediate.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Mmf\Common\Mmfbase.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknfontidoffsets.hrh +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\libc\String.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Apmstd.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknappui.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Ecom\Ecom.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikspane.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mmf\server\Mmfbuffer.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\libc\Stdlib.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikalign.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eiklbv.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknappui.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Apgtask.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eiksrvs.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Bitdev.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikdpobs.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mmf\common\Mmfcontrollerframework.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Babitflags.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mmf\common\Mmfvideo.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Vwsdef.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\libc\Ctype.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikimage.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikdef.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikbutb.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Bitbase.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Importfile.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknpopupfader.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Akndef.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Metacontainer.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\E32cmn.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknscrlb.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Fldbase.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikscbut.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mmf\common\Mmfstandardcustomcommands.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\E32base.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikmobs.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\E32std.inl +# End Source File +# Begin Source File + +SOURCE=\picodrive\pico\Pico.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Coehelp.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\E32const.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikdialg.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Apparc.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Coemop.h +# End Source File +# Begin Source File + +SOURCE=\picodrive\s60\Picodriveexe.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Txtetext.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknquerycontrol.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Frmlaydt.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikappui.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\E32err.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mmf\server\Mmfdatabuffer.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Stringattributeset.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\libc\sys\Stdio_t.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Gulcolor.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eiklbx.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Coeview.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Mda\Common\Resource.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknlistquerycontrol.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikdoc.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Caferr.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknpopuplayout.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mmf\common\Mmfipc.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Graphicsaccelerator.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\S32file.inl +# End Source File +# Begin Source File + +SOURCE=\picodrive\s60\S60v3video.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mmf\common\Mmfipc.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Fldbltin.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Caftypes.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Tagma.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\In_sock.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Apaid.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Mda\Common\Resource.hrh +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Caf.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Txtfrmat.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\libc\Stddef.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\libc\sys\Reent.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Gulutil.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Agent.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Manager.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknlistquerydialog.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Partitions.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Gulbordr.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Virtualpathptr.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Picodrive.rsg +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Barsc.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Txtfmlyr.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\S32strm.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Linebreak.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikstart.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\S32strm.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Zconf.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Gdi.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\E32ldr.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\W32std.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eiktxlbm.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Txtfmstm.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Gulalign.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Lafmain.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Gdi.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikamnt.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\E32svr.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Mmf\Common\Mmfutilities.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Ecom\Ecomerrorcodes.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Mda\Common\Audio.hrh +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\E32cmn.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Ecom\Implementationinformation.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Gulftflg.hrh +# End Source File +# Begin Source File + +SOURCE=\S60V3\epoc32\include\variant\Symbian_os_v9.1.hrh +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikedwin.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\S32page.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eiksrv.pan +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikcmbut.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Gulicon.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknnumseced.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Txtfrmat.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Ecom\Ecomresolverparams.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikcolor.hrh +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\libc\Stdio.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikcba.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Badesca.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikcmobs.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknapp.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknmfnecommandobserver.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Baerrhan.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Fldinfo.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eiktxlbx.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikccpu.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mmf\common\Mmfcontrollerframeworkbase.h +# End Source File +# Begin Source File + +SOURCE=\picodrive\pico\Ggenie.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Avkon.hrh +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Fldset.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknpictographdrawerinterface.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Vwsappst.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mmf\common\Mmfutilities.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Content.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eiksbobs.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Bamdesca.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\D32locd.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mmf\common\Mmfaudio.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikmenub.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\S32stor.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mmf\plugin\Mmfplugininterfaceuids.hrh +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\E32std.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikbtgpc.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Ecom\Implementationinformation.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Bitdev.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Streamableptrarray.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Metadata.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Supplier.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mmf\common\Mmfbase.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Mda\Common\Port.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Basched.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Coecontrolarray.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eiksbfrm.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknenv.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\libc\machine\Types.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Mmfclntutility.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\E32keys.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Biditext.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\E32ktran.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Openfont.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mmf\server\Mmfdatasourcesink.hrh +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mmf\server\Mmfdatasource.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknquerydata.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eiklbo.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikvcurs.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknlayout.lag +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Bidi.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Supplieroutputfile.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mmf\common\Mmfbase.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikunder.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Coemain.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\E32hal.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Guldef.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknnumedwin.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Bitmap.h +# End Source File +# Begin Source File + +SOURCE=\picodrive\pico\Picoint.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Mda\Common\Base.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mda\common\Base.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknquerydialog.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\F32file.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknpanic.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknfontcategory.hrh +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Avkon.rsg +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Metadata.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Txtstyle.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eiklay.h +# End Source File +# Begin Source File + +SOURCE=\picodrive\pico\Pico.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Apaflrec.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikmfne.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Coeccntx.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\E32event.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknipfed.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Uikon.hrh +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknsconstants.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\S32std.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Embeddedobject.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknform.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Es_sock.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mm\Mmcaf.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Nifvar.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\S32mem.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\E32base.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Savenotf.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\E32capability.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Mda\Common\Base.hrh +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Coecntrl.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikfctry.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eiklbm.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\libc\Assert.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Medobsrv.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknsitemid.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Coecobs.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknutils.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Frmparam.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Metadataarray.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Lafpublc.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mmf\common\Mmfcontrollerpluginresolver.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Mda\Common\Audio.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Cafmimeheader.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Akndialog.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Attribute.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\S32stor.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Attributeset.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikspmod.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Frmvis.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\ecom\Ecom.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eiklibry.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Frmtlay.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknsconstants.hrh +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikctgrp.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Txtetext.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Akndoc.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Coeinput.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\S32share.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\F32file.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikmenup.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Akncontrol.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\E32base.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Coedef.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikcal.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Fntstore.h +# End Source File +# Begin Source File + +SOURCE=\picodrive\Unzip.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Rightsmanager.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Apacmdln.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Es_sock.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Metacontainer.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikseced.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\F32file.h +# End Source File +# Begin Source File + +SOURCE=\picodrive\zlib\Zlib.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mmf\server\Mmfdatasink.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mmf\common\Mmcaf.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Mdaaudiooutputstream.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikdgfty.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Cafpanic.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mmf\common\Mmfutilities.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\S32share.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Frmtview.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Fepbase.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Rightsinfo.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknnumed.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknsitemid.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Metadata.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Dirstreamable.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\E32des8.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Frmframe.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\S32buf.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Coeaui.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikapp.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikenv.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Fbs.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Akndef.hrh +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mmf\common\Mmfcontroller.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknscbut.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Txtstyle.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikbtgrp.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknpopup.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Akncontrol.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Mda\Common\Port.hrh +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\libc\_ansi.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Bitstd.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Mda\Common\Controller.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\E32def.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eiksrvc.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikscrlb.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mmf\server\Mmfbuffer.hrh +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Akntouchpaneobserver.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Apadef.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikbctrl.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Aknpopupheadingpane.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mmf\common\Mmfutilities.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\D32locd.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikon.hrh +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Mda\Common\Audiostream.hrh +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\S32page.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Lafpublc.hrh +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eiklbed.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\S32file.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\libc\Stdarg_e.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\ecom\Ecom.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikedwob.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\libc\Time.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\E32notif.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eikcycledef.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\E32debug.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Coetextdrawer.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Eiksrv.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\S32std.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Virtualpath.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Streamableptrarray.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\mda\client\Utility.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\S32mem.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\Txtfmlyr.inl +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\E32lmsg.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\caf\Data.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\E32des16.h +# End Source File +# Begin Source File + +SOURCE=\S60V3\EPOC32\include\libc\sys\Time.h +# End Source File +# End Group +# Begin Group "Make Files" + +# PROP Default_Filter "mak;mk" +# Begin Source File + +SOURCE=\picodrive\s60\picodrives60v3.mak +# End Source File +# End Group +# End Target +# End Project diff --git a/platform/s60/picodrives60v3.mak b/platform/s60/picodrives60v3.mak new file mode 100644 index 00000000..2c55f058 --- /dev/null +++ b/platform/s60/picodrives60v3.mak @@ -0,0 +1,854 @@ +PATH=\S60V3\epoc32\tools\;C:\Program\CSL Arm Toolchain\arm-none-symbianelf\bin;C:\Program\CSL Arm Toolchain\bin;\uiq3\epoc32\tools\;\S60V3\epoc32\tools\;\S60V3\epoc32\gcc\bin\;C:\winnt\system32;C:\winnt;C:\winnt\System32\Wbem;C:\Program Files\ATI Technologies\ATI Control Panel;C:\Program Files\Common Files\Adaptec Shared\System;C:\Perl\bin;\uiq3\epoc32\tools;c:\MSVC6\VC98\Bin;e:\UIQ3\epoc32\tools\nokia_compiler\Symbian_Tools\Command_Line_Tools;C:\Program Files\CSL Arm Toolchain\arm-none-symbianelf\bin;C:\Program Files\CSL Arm Toolchain\bin +Path=$(PATH) +COMPILER_PATH="\S60V3\epoc32\tools\nokia_compiler\Symbian_Tools\Command_Line_Tools\" + +# CWD \picodrive\s60\ +# MMPFile \picodrive\s60\picodrives60v3.MMP +# Target PicoDrive.exe +# TargetType EXE +# BasicTargetType EXE +# MakefileType GNU + +ERASE = @erase 2>>nul + +# EPOC DEFINITIONS + +EPOCBLD = \S60V3\EPOC32\BUILD\picodrive\s60\picodrives60v3\WINSCW +EPOCTRG = \S60V3\EPOC32\RELEASE\WINSCW +EPOCLIB = \S60V3\EPOC32\RELEASE\WINSCW +EPOCLINK = \S60V3\EPOC32\RELEASE\WINSCW +EPOCSTATLINK = \S60V3\EPOC32\RELEASE\WINSCW +EPOCASSPLINK = \S60V3\EPOC32\RELEASE\WINSCW +EPOCDATA = \S60V3\EPOC32\DATA +EPOCINC = \S60V3\EPOC32\INCLUDE +TRGDIR = Z\sys\bin +DATADIR = Z\System\Data + +EPOCBLDUDEB = $(EPOCBLD)\UDEB +EPOCTRGUDEB = $(EPOCTRG)\UDEB +EPOCLIBUDEB = $(EPOCLIB)\UDEB +EPOCLINKUDEB = $(EPOCLINK)\UDEB +EPOCSTATLINKUDEB = $(EPOCSTATLINK)\UDEB +EPOCASSPLINKUDEB = $(EPOCASSPLINK)\UDEB + +EPOCBLDUREL = $(EPOCBLD)\UREL +EPOCTRGUREL = $(EPOCTRG)\UREL +EPOCLIBUREL = $(EPOCLIB)\UDEB +EPOCLINKUREL = $(EPOCLINK)\UDEB +EPOCSTATLINKUREL = $(EPOCSTATLINK)\UREL +EPOCASSPLINKUREL = $(EPOCASSPLINK)\UDEB + +# EPOC PSEUDOTARGETS + +UDEB : MAKEWORKUDEB RESOURCEUDEB + +UREL : MAKEWORKUREL RESOURCEUREL + +ALL : UDEB UREL + +CLEAN CLEANALL : CLEANBUILD CLEANRELEASE CLEANLIBRARY + + + +WHAT WHATALL : WHATUDEB WHATUREL + +RESOURCE RESOURCEALL : RESOURCEUDEB RESOURCEUREL + +CLEANBUILD CLEANBUILDALL : CLEANBUILDUDEB CLEANBUILDUREL + +CLEANRELEASE CLEANRELEASEALL : CLEANRELEASEUDEB CLEANRELEASEUREL + +MAKEWORK MAKEWORKALL : MAKEWORKUDEB MAKEWORKUREL + +LISTING LISTINGALL : LISTINGUDEB LISTINGUREL + +MAKEWORK : MAKEWORKLIBRARY + +RESOURCEUDEB RESOURCEUREL : GENERIC_RESOURCE + + +MWCIncludes:=$(MWCSym2Includes) +export MWCIncludes + + +MWLibraries:=+\S60V3\epoc32\tools\nokia_compiler\Symbian_Support\Runtime\Runtime_x86\Runtime_Win32\Libs;\S60V3\epoc32\tools\nokia_compiler\Symbian_Support\Win32-x86 Support\Libraries\Win32 SDK +export MWLibraries + + +MWLibraryFiles:=gdi32.lib;user32.lib;kernel32.lib; +export MWLibraryFiles + +# EPOC DEFINITIONS + +INCDIR = -cwd source -i- \ + -i "\picodrive\pico" \ + -i "\picodrive\pico\sound" \ + -i "\picodrive\s60" \ + -i "\picodrive" \ + -i "\S60V3\EPOC32\include" \ + -i "\S60V3\EPOC32\include\libc" \ + -i "\S60V3\EPOC32\include\mmf\plugin" \ + -i "\S60V3\epoc32\include\variant"\ + -i "\S60V3\epoc32\include\variant\ " -include "Symbian_OS_v9.1.hrh" + +CWFLAGS = -wchar_t off -align 4 -warnings on -w nohidevirtual,nounusedexpr -enum int -str pool -exc ms -nostdinc + +CWDEFS = -d "__SYMBIAN32__" -d "__CW32__" -d "__WINS__" -d "__WINSCW__" -d "__EXE__" -d "S60V3" -d "__SUPPORT_CPP_EXCEPTIONS__" $(USERDEFS) + +CWUDEB = perl -S err_formatter.pl $(COMPILER_PATH)mwccsym2.exe -msgstyle parseable -sym codeview -inline off $(CWFLAGS) -d _DEBUG -d _UNICODE $(CWDEFS) $(INCDIR) +CWUREL = perl -S err_formatter.pl $(COMPILER_PATH)mwccsym2.exe -msgstyle parseable -O4,s $(CWFLAGS) -d NDEBUG -d _UNICODE $(CWDEFS) $(INCDIR) + + +UDEB : \ + $(EPOCTRGUDEB)\PicoDrive.exe + +UREL : \ + $(EPOCTRGUREL)\PicoDrive.exe + + +RESOURCEUDEB : MAKEWORKUDEB \ + $(EPOCTRGUDEB)\Z\Resource\Apps\PicoDrive.mbm \ + $(EPOCTRGUDEB)\Z\private\10003a3f\apps\PicoDrive_reg.RSC \ + $(EPOCTRGUDEB)\Z\Resource\Apps\PicoDrive_loc.RSC \ + $(EPOCTRGUDEB)\Z\Resource\Apps\PicoDrive.RSC + +RESOURCEUREL : MAKEWORKUREL \ + $(EPOCTRGUREL)\Z\Resource\Apps\PicoDrive.mbm \ + $(EPOCTRGUREL)\Z\private\10003a3f\apps\PicoDrive_reg.RSC \ + $(EPOCTRGUREL)\Z\Resource\Apps\PicoDrive_loc.RSC \ + $(EPOCTRGUREL)\Z\Resource\Apps\PicoDrive.RSC + + + +# REAL TARGET - LIBRARY + +LIBRARY : MAKEWORKLIBRARY + +FREEZE : + +CLEANLIBRARY : + +GENERIC_RESOURCE : GENERIC_MAKEWORK + +# REAL TARGET - BUILD VARIANT UDEB + +WHATUDEB : WHATGENERIC + +CLEANUDEB : CLEANBUILDUDEB CLEANRELEASEUDEB + +CLEANBUILDUDEB : + @perl -S ermdir.pl "$(EPOCBLDUDEB)" + +CLEANRELEASEUDEB : CLEANGENERIC + + +UDEB_RELEASEABLES1= \ + $(EPOCTRGUDEB)\PicoDrive.exe \ + $(EPOCTRGUDEB)\Z\Resource\Apps\PicoDrive.RSC \ + $(EPOCTRGUDEB)\Z\Resource\Apps\PicoDrive.mbm \ + $(EPOCTRGUDEB)\Z\Resource\Apps\PicoDrive_loc.RSC \ + $(EPOCTRGUDEB)\Z\private\10003a3f\apps\PicoDrive_reg.RSC + +WHATUDEB: + @echo $(UDEB_RELEASEABLES1) + +CLEANRELEASEUDEB: + -$(ERASE) $(UDEB_RELEASEABLES1) + + + +LISTINGUDEB : MAKEWORKUDEB \ + LISTINGUDEBpicodriveexe \ + LISTINGUDEBunzip \ + LISTINGUDEBPicoDrive_UID_ + +LIBSUDEB= \ + $(EPOCSTATLINKUDEB)\pico.lib \ + $(EPOCSTATLINKUDEB)\a68k.obj \ + $(EPOCSTATLINKUDEB)\mz80_asm.obj \ + $(EPOCSTATLINKUDEB)\zlib.lib \ + $(EPOCLINKUDEB)\cone.lib \ + $(EPOCLINKUDEB)\EIKCORE.lib \ + $(EPOCLINKUDEB)\MEDIACLIENTAUDIOSTREAM.LIB \ + $(EPOCLINKUDEB)\euser.lib \ + $(EPOCLINKUDEB)\apparc.lib \ + $(EPOCLINKUDEB)\efsrv.lib \ + $(EPOCLINKUDEB)\estlib.lib \ + $(EPOCLINKUDEB)\fbscli.lib \ + $(EPOCLINKUDEB)\estor.lib \ + $(EPOCLINKUDEB)\eikcoctl.lib \ + $(EPOCLINKUDEB)\ws32.lib \ + $(EPOCLINKUDEB)\AVKON.LIB \ + $(EPOCLINKUDEB)\bafl.lib \ + $(EPOCLINKUDEB)\bitgdi.lib \ + $(EPOCLINKUDEB)\gdi.lib \ + $(EPOCLINKUDEB)\eikdlg.lib + +LINK_OBJSUDEB= \ + $(EPOCBLDUDEB)\picodriveexe.o \ + $(EPOCBLDUDEB)\unzip.o \ + $(EPOCBLDUDEB)\PicoDrive_UID_.o + +COMMON_LINK_FLAGSUDEB= -stdlib "$(EPOCSTATLINKUDEB)\EEXE.LIB" -m\ + "?_E32Bootstrap@@YGXXZ" -subsystem windows -heapreserve=8000 -heapcommit=256\ + -sym codeview -lMSL_All_MSE_Symbian_D.lib + + +LINK_FLAGSUDEB= $(COMMON_LINK_FLAGSUDEB) $(LIBSUDEB) \ + -o "$(EPOCTRGUDEB)\PicoDrive.exe" -noimplib + +$(EPOCTRGUDEB)\PicoDrive.exe : $(LINK_OBJSUDEB) $(EPOCSTATLINKUDEB)\EEXE.LIB $(LIBSUDEB) + $(COMPILER_PATH)mwldsym2.exe -msgstyle gcc $(LINK_FLAGSUDEB) -l $(EPOCBLDUDEB) -search $(notdir $(LINK_OBJSUDEB)) + + +# REAL TARGET - BUILD VARIANT UREL + +WHATUREL : WHATGENERIC + +CLEANUREL : CLEANBUILDUREL CLEANRELEASEUREL + +CLEANBUILDUREL : + @perl -S ermdir.pl "$(EPOCBLDUREL)" + +CLEANRELEASEUREL : CLEANGENERIC + + +UREL_RELEASEABLES1= \ + $(EPOCTRGUREL)\PicoDrive.exe \ + $(EPOCTRGUREL)\PicoDrive.exe.map \ + $(EPOCTRGUREL)\Z\Resource\Apps\PicoDrive.RSC \ + $(EPOCTRGUREL)\Z\Resource\Apps\PicoDrive.mbm \ + $(EPOCTRGUREL)\Z\Resource\Apps\PicoDrive_loc.RSC \ + $(EPOCTRGUREL)\Z\private\10003a3f\apps\PicoDrive_reg.RSC + +WHATUREL: + @echo $(UREL_RELEASEABLES1) + +CLEANRELEASEUREL: + -$(ERASE) $(UREL_RELEASEABLES1) + + + +LISTINGUREL : MAKEWORKUREL \ + LISTINGURELpicodriveexe \ + LISTINGURELunzip \ + LISTINGURELPicoDrive_UID_ + +LIBSUREL= \ + $(EPOCSTATLINKUREL)\pico.lib \ + $(EPOCSTATLINKUREL)\a68k.obj \ + $(EPOCSTATLINKUREL)\mz80_asm.obj \ + $(EPOCSTATLINKUREL)\zlib.lib \ + $(EPOCLINKUREL)\cone.lib \ + $(EPOCLINKUREL)\EIKCORE.lib \ + $(EPOCLINKUREL)\MEDIACLIENTAUDIOSTREAM.LIB \ + $(EPOCLINKUREL)\euser.lib \ + $(EPOCLINKUREL)\apparc.lib \ + $(EPOCLINKUREL)\efsrv.lib \ + $(EPOCLINKUREL)\estlib.lib \ + $(EPOCLINKUREL)\fbscli.lib \ + $(EPOCLINKUREL)\estor.lib \ + $(EPOCLINKUREL)\eikcoctl.lib \ + $(EPOCLINKUREL)\ws32.lib \ + $(EPOCLINKUREL)\AVKON.LIB \ + $(EPOCLINKUREL)\bafl.lib \ + $(EPOCLINKUREL)\bitgdi.lib \ + $(EPOCLINKUREL)\gdi.lib \ + $(EPOCLINKUREL)\eikdlg.lib + +LINK_OBJSUREL= \ + $(EPOCBLDUREL)\picodriveexe.o \ + $(EPOCBLDUREL)\unzip.o \ + $(EPOCBLDUREL)\PicoDrive_UID_.o + +COMMON_LINK_FLAGSUREL= -stdlib "$(EPOCSTATLINKUREL)\EEXE.LIB" -m\ + "?_E32Bootstrap@@YGXXZ" -subsystem windows -heapreserve=8000 -heapcommit=256\ + -lMSL_All_MSE_Symbian.lib + + +LINK_FLAGSUREL= $(COMMON_LINK_FLAGSUREL) $(LIBSUREL) \ + -o "$(EPOCTRGUREL)\PicoDrive.exe" -map "$(EPOCTRGUREL)\PicoDrive.exe.map" -noimplib + +$(EPOCTRGUREL)\PicoDrive.exe : $(LINK_OBJSUREL) $(EPOCSTATLINKUREL)\EEXE.LIB $(LIBSUREL) + $(COMPILER_PATH)mwldsym2.exe -msgstyle gcc $(LINK_FLAGSUREL) -l $(EPOCBLDUREL) -search $(notdir $(LINK_OBJSUREL)) + + +# SOURCES + +# BitMap PicoDrive.mbm + +GENERIC_RESOURCE : $(EPOCDATA)\Z\Resource\Apps\PicoDrive.mbm + +$(EPOCDATA)\Z\Resource\Apps\PicoDrive.mbm : \ + \picodrive\s60\picos.bmp \ + \picodrive\s60\picosmi.bmp \ + \picodrive\s60\picol.bmp \ + \picodrive\s60\picolmi.bmp + perl -S epocmbm.pl -h"\S60V3\EPOC32\BUILD\picodrive\s60\picodrives60v3\WINSCW\PicoDrive.mbg" -o"$(EPOCDATA)\Z\Resource\Apps\PicoDrive.mbm" -l"\Z\Resource\Apps\:\picodrive\s60"\ + -b"\ + /c24\picodrive\s60\picos.bmp\ + /8\picodrive\s60\picosmi.bmp\ + /c24\picodrive\s60\picol.bmp\ + /8\picodrive\s60\picolmi.bmp" \ + -l"\Z\Resource\Apps\:\picodrive\s60" + +$(EPOCTRGUDEB)\Z\Resource\Apps\PicoDrive.mbm : $(EPOCDATA)\Z\Resource\Apps\PicoDrive.mbm + perl -S ecopyfile.pl $? $@ + +$(EPOCTRGUREL)\Z\Resource\Apps\PicoDrive.mbm : $(EPOCDATA)\Z\Resource\Apps\PicoDrive.mbm + perl -S ecopyfile.pl $? $@ + +# Resource Z\private\10003a3f\apps\PicoDrive_reg.RSC + +DEPEND= \ + \S60V3\EPOC32\include\AppInfo.rh \ + \S60V3\epoc32\include\variant\Symbian_OS_v9.1.hrh + +GENERIC_RESOURCE : $(EPOCDATA)\Z\private\10003a3f\apps\PicoDrive_reg.RSC + +$(EPOCDATA)\Z\private\10003a3f\apps\PicoDrive_reg.RSC : \picodrive\S60\PicoDrive_reg.rss $(DEPEND) + perl -S epocrc.pl -m045,046,047 -I "\picodrive\S60" -I "\picodrive\pico" -I "\picodrive\pico\sound" -I "\picodrive\s60" -I "\picodrive" -I- -I "\S60V3\EPOC32\include" -I "\S60V3\EPOC32\include\libc" -I "\S60V3\EPOC32\include\mmf\plugin" -I "\S60V3\epoc32\include\variant" -DLANGUAGE_SC -u "\picodrive\S60\PicoDrive_reg.rss" -o$@ -t"\S60V3\EPOC32\BUILD\picodrive\s60\picodrives60v3\WINSCW" -l"Z\private\10003a3f\apps:\picodrive\s60" + +$(EPOCTRGUDEB)\Z\private\10003a3f\apps\PicoDrive_reg.RSC : $(EPOCDATA)\Z\private\10003a3f\apps\PicoDrive_reg.RSC + perl -S ecopyfile.pl $? $@ + +$(EPOCTRGUREL)\Z\private\10003a3f\apps\PicoDrive_reg.RSC : $(EPOCDATA)\Z\private\10003a3f\apps\PicoDrive_reg.RSC + perl -S ecopyfile.pl $? $@ + +# Resource Z\Resource\Apps\PicoDrive_loc.RSC + +DEPEND= \ + \S60V3\EPOC32\include\AppInfo.rh \ + \S60V3\epoc32\include\variant\Symbian_OS_v9.1.hrh + +GENERIC_RESOURCE : $(EPOCDATA)\Z\Resource\Apps\PicoDrive_loc.RSC + +$(EPOCDATA)\Z\Resource\Apps\PicoDrive_loc.RSC : \picodrive\S60\PicoDrive_loc.rss $(DEPEND) + perl -S epocrc.pl -m045,046,047 -I "\picodrive\S60" -I "\picodrive\pico" -I "\picodrive\pico\sound" -I "\picodrive\s60" -I "\picodrive" -I- -I "\S60V3\EPOC32\include" -I "\S60V3\EPOC32\include\libc" -I "\S60V3\EPOC32\include\mmf\plugin" -I "\S60V3\epoc32\include\variant" -DLANGUAGE_SC -u "\picodrive\S60\PicoDrive_loc.rss" -o$@ -t"\S60V3\EPOC32\BUILD\picodrive\s60\picodrives60v3\WINSCW" -l"Z\Resource\Apps:\picodrive\s60" + +$(EPOCTRGUDEB)\Z\Resource\Apps\PicoDrive_loc.RSC : $(EPOCDATA)\Z\Resource\Apps\PicoDrive_loc.RSC + perl -S ecopyfile.pl $? $@ + +$(EPOCTRGUREL)\Z\Resource\Apps\PicoDrive_loc.RSC : $(EPOCDATA)\Z\Resource\Apps\PicoDrive_loc.RSC + perl -S ecopyfile.pl $? $@ + +# Resource Z\Resource\Apps\PicoDrive.RSC + +DEPEND= \ + \S60V3\EPOC32\include\BADEF.RH \ + \S60V3\EPOC32\include\BAERRRSVR.RH \ + \S60V3\EPOC32\include\aknfontcategory.hrh \ + \S60V3\EPOC32\include\aknfontidoffsets.hrh \ + \S60V3\EPOC32\include\avkon.hrh \ + \S60V3\EPOC32\include\avkon.rh \ + \S60V3\EPOC32\include\avkon.rsg \ + \S60V3\EPOC32\include\eikcdlg.rsg \ + \S60V3\EPOC32\include\eikcoctl.rsg \ + \S60V3\EPOC32\include\eikcolor.hrh \ + \S60V3\EPOC32\include\eikcore.rsg \ + \S60V3\EPOC32\include\eikctl.rsg \ + \S60V3\EPOC32\include\eikon.hrh \ + \S60V3\EPOC32\include\eikon.rh \ + \S60V3\EPOC32\include\eikon.rsg \ + \S60V3\EPOC32\include\gulftflg.hrh \ + \S60V3\EPOC32\include\lafpublc.hrh \ + \S60V3\EPOC32\include\uikon.hrh \ + \S60V3\EPOC32\include\uikon.rh \ + \S60V3\epoc32\include\variant\Symbian_OS_v9.1.hrh + +GENERIC_RESOURCE : $(EPOCDATA)\Z\Resource\Apps\PicoDrive.RSC + +$(EPOCDATA)\Z\Resource\Apps\PicoDrive.RSC : \picodrive\s60\PicoDrive.rss $(DEPEND) + perl -S epocrc.pl -m045,046,047 -I "\picodrive\s60" -I "\picodrive\pico" -I "\picodrive\pico\sound" -I "\picodrive\s60" -I "\picodrive" -I- -I "\S60V3\EPOC32\include" -I "\S60V3\EPOC32\include\libc" -I "\S60V3\EPOC32\include\mmf\plugin" -I "\S60V3\epoc32\include\variant" -DLANGUAGE_SC -u "\picodrive\s60\PicoDrive.rss" -o$@ -h"\S60V3\EPOC32\BUILD\picodrive\s60\picodrives60v3\WINSCW\PicoDrive.rsg" -t"\S60V3\EPOC32\BUILD\picodrive\s60\picodrives60v3\WINSCW" -l"Z\Resource\Apps:\picodrive\s60" + perl -S ecopyfile.pl "\S60V3\EPOC32\BUILD\picodrive\s60\picodrives60v3\WINSCW\PicoDrive.rsg" "\S60V3\EPOC32\INCLUDE\PicoDrive.RSG" + +$(EPOCTRGUDEB)\Z\Resource\Apps\PicoDrive.RSC : $(EPOCDATA)\Z\Resource\Apps\PicoDrive.RSC + perl -S ecopyfile.pl $? $@ + +$(EPOCTRGUREL)\Z\Resource\Apps\PicoDrive.RSC : $(EPOCDATA)\Z\Resource\Apps\PicoDrive.RSC + perl -S ecopyfile.pl $? $@ + +# Source picodriveexe.cpp + +$(EPOCBLDUDEB)\picodriveexe.o \ +$(EPOCBLDUREL)\picodriveexe.o \ +: \ + \S60V3\EPOC32\include\AknControl.h \ + \S60V3\EPOC32\include\AknMfneCommandObserver.h \ + \S60V3\EPOC32\include\AknPictographDrawerInterface.h \ + \S60V3\EPOC32\include\AknTouchPaneObserver.h \ + \S60V3\EPOC32\include\AknsConstants.h \ + \S60V3\EPOC32\include\AknsConstants.hrh \ + \S60V3\EPOC32\include\AknsItemID.h \ + \S60V3\EPOC32\include\AknsItemID.inl \ + \S60V3\EPOC32\include\E32Base.h \ + \S60V3\EPOC32\include\Ecom\EComErrorCodes.h \ + \S60V3\EPOC32\include\Ecom\EComResolverParams.h \ + \S60V3\EPOC32\include\Ecom\EComResolverParams.inl \ + \S60V3\EPOC32\include\Ecom\Ecom.h \ + \S60V3\EPOC32\include\Ecom\ImplementationInformation.h \ + \S60V3\EPOC32\include\Ecom\ImplementationInformation.inl \ + \S60V3\EPOC32\include\Eikspane.h \ + \S60V3\EPOC32\include\F32File.h \ + \S60V3\EPOC32\include\LineBreak.h \ + \S60V3\EPOC32\include\MdaAudioOutputStream.h \ + \S60V3\EPOC32\include\Mda\Common\Audio.h \ + \S60V3\EPOC32\include\Mda\Common\Audio.hrh \ + \S60V3\EPOC32\include\Mda\Common\AudioStream.hrh \ + \S60V3\EPOC32\include\Mda\Common\Base.h \ + \S60V3\EPOC32\include\Mda\Common\Base.h \ + \S60V3\EPOC32\include\Mda\Common\Base.hrh \ + \S60V3\EPOC32\include\Mda\Common\Base.inl \ + \S60V3\EPOC32\include\Mda\Common\Controller.h \ + \S60V3\EPOC32\include\Mda\Common\Port.h \ + \S60V3\EPOC32\include\Mda\Common\Port.hrh \ + \S60V3\EPOC32\include\Mda\Common\Resource.h \ + \S60V3\EPOC32\include\Mda\Common\Resource.hrh \ + \S60V3\EPOC32\include\MetaContainer.h \ + \S60V3\EPOC32\include\MetaContainer.inl \ + \S60V3\EPOC32\include\MetaData.h \ + \S60V3\EPOC32\include\Metadata.inl \ + \S60V3\EPOC32\include\Mmf\Common\MmfBase.h \ + \S60V3\EPOC32\include\Mmf\Common\MmfUtilities.h \ + \S60V3\EPOC32\include\Mmfclntutility.h \ + \S60V3\EPOC32\include\aknDialog.h \ + \S60V3\EPOC32\include\aknPanic.h \ + \S60V3\EPOC32\include\aknapp.h \ + \S60V3\EPOC32\include\aknappUI.h \ + \S60V3\EPOC32\include\aknappui.h \ + \S60V3\EPOC32\include\akncontrol.h \ + \S60V3\EPOC32\include\akndef.h \ + \S60V3\EPOC32\include\akndef.hrh \ + \S60V3\EPOC32\include\akndoc.h \ + \S60V3\EPOC32\include\aknenv.h \ + \S60V3\EPOC32\include\aknfontcategory.hrh \ + \S60V3\EPOC32\include\aknfontidoffsets.hrh \ + \S60V3\EPOC32\include\aknform.h \ + \S60V3\EPOC32\include\aknintermediate.h \ + \S60V3\EPOC32\include\aknipfed.h \ + \S60V3\EPOC32\include\aknlayout.lag \ + \S60V3\EPOC32\include\aknlayout2id.h \ + \S60V3\EPOC32\include\aknlistquerycontrol.h \ + \S60V3\EPOC32\include\aknlistquerydialog.h \ + \S60V3\EPOC32\include\aknmultilinequerycontrol.h \ + \S60V3\EPOC32\include\aknnumed.h \ + \S60V3\EPOC32\include\aknnumedwin.h \ + \S60V3\EPOC32\include\aknnumseced.h \ + \S60V3\EPOC32\include\aknpopup.h \ + \S60V3\EPOC32\include\aknpopupfader.h \ + \S60V3\EPOC32\include\aknpopupheadingpane.h \ + \S60V3\EPOC32\include\aknpopuplayout.h \ + \S60V3\EPOC32\include\aknquerycontrol.h \ + \S60V3\EPOC32\include\aknquerydata.h \ + \S60V3\EPOC32\include\aknquerydialog.h \ + \S60V3\EPOC32\include\aknscbut.h \ + \S60V3\EPOC32\include\aknscrlb.h \ + \S60V3\EPOC32\include\aknutils.h \ + \S60V3\EPOC32\include\apacmdln.h \ + \S60V3\EPOC32\include\apadef.h \ + \S60V3\EPOC32\include\apaflrec.h \ + \S60V3\EPOC32\include\apaid.h \ + \S60V3\EPOC32\include\apgtask.h \ + \S60V3\EPOC32\include\apmstd.h \ + \S60V3\EPOC32\include\apparc.h \ + \S60V3\EPOC32\include\avkon.hrh \ + \S60V3\EPOC32\include\avkon.rsg \ + \S60V3\EPOC32\include\babitflags.h \ + \S60V3\EPOC32\include\badesca.h \ + \S60V3\EPOC32\include\baerrhan.h \ + \S60V3\EPOC32\include\bamdesca.h \ + \S60V3\EPOC32\include\barsc.h \ + \S60V3\EPOC32\include\basched.h \ + \S60V3\EPOC32\include\bidi.h \ + \S60V3\EPOC32\include\biditext.h \ + \S60V3\EPOC32\include\bitbase.h \ + \S60V3\EPOC32\include\bitdev.h \ + \S60V3\EPOC32\include\bitdev.inl \ + \S60V3\EPOC32\include\bitmap.h \ + \S60V3\EPOC32\include\bitstd.h \ + \S60V3\EPOC32\include\caf\agent.h \ + \S60V3\EPOC32\include\caf\attribute.h \ + \S60V3\EPOC32\include\caf\attributeset.h \ + \S60V3\EPOC32\include\caf\caf.h \ + \S60V3\EPOC32\include\caf\caferr.h \ + \S60V3\EPOC32\include\caf\cafmimeheader.h \ + \S60V3\EPOC32\include\caf\cafpanic.h \ + \S60V3\EPOC32\include\caf\caftypes.h \ + \S60V3\EPOC32\include\caf\caftypes.h \ + \S60V3\EPOC32\include\caf\content.h \ + \S60V3\EPOC32\include\caf\data.h \ + \S60V3\EPOC32\include\caf\dirstreamable.h \ + \S60V3\EPOC32\include\caf\embeddedobject.h \ + \S60V3\EPOC32\include\caf\importfile.h \ + \S60V3\EPOC32\include\caf\manager.h \ + \S60V3\EPOC32\include\caf\metadata.h \ + \S60V3\EPOC32\include\caf\metadataarray.h \ + \S60V3\EPOC32\include\caf\rightsinfo.h \ + \S60V3\EPOC32\include\caf\rightsmanager.h \ + \S60V3\EPOC32\include\caf\streamableptrarray.h \ + \S60V3\EPOC32\include\caf\streamableptrarray.inl \ + \S60V3\EPOC32\include\caf\stringattributeset.h \ + \S60V3\EPOC32\include\caf\supplier.h \ + \S60V3\EPOC32\include\caf\supplieroutputfile.h \ + \S60V3\EPOC32\include\caf\virtualpath.h \ + \S60V3\EPOC32\include\caf\virtualpathptr.h \ + \S60V3\EPOC32\include\coeaui.h \ + \S60V3\EPOC32\include\coeccntx.h \ + \S60V3\EPOC32\include\coecntrl.h \ + \S60V3\EPOC32\include\coecobs.h \ + \S60V3\EPOC32\include\coecontrolarray.h \ + \S60V3\EPOC32\include\coedef.h \ + \S60V3\EPOC32\include\coehelp.h \ + \S60V3\EPOC32\include\coeinput.h \ + \S60V3\EPOC32\include\coemain.h \ + \S60V3\EPOC32\include\coemop.h \ + \S60V3\EPOC32\include\coetextdrawer.h \ + \S60V3\EPOC32\include\coeview.h \ + \S60V3\EPOC32\include\d32locd.h \ + \S60V3\EPOC32\include\d32locd.inl \ + \S60V3\EPOC32\include\e32base.h \ + \S60V3\EPOC32\include\e32base.inl \ + \S60V3\EPOC32\include\e32capability.h \ + \S60V3\EPOC32\include\e32cmn.h \ + \S60V3\EPOC32\include\e32cmn.inl \ + \S60V3\EPOC32\include\e32const.h \ + \S60V3\EPOC32\include\e32debug.h \ + \S60V3\EPOC32\include\e32def.h \ + \S60V3\EPOC32\include\e32des16.h \ + \S60V3\EPOC32\include\e32des8.h \ + \S60V3\EPOC32\include\e32err.h \ + \S60V3\EPOC32\include\e32event.h \ + \S60V3\EPOC32\include\e32hal.h \ + \S60V3\EPOC32\include\e32keys.h \ + \S60V3\EPOC32\include\e32ktran.h \ + \S60V3\EPOC32\include\e32ldr.h \ + \S60V3\EPOC32\include\e32lmsg.h \ + \S60V3\EPOC32\include\e32notif.h \ + \S60V3\EPOC32\include\e32std.h \ + \S60V3\EPOC32\include\e32std.inl \ + \S60V3\EPOC32\include\e32svr.h \ + \S60V3\EPOC32\include\ecom\ECom.h \ + \S60V3\EPOC32\include\ecom\ecom.h \ + \S60V3\EPOC32\include\eikalign.h \ + \S60V3\EPOC32\include\eikamnt.h \ + \S60V3\EPOC32\include\eikapp.h \ + \S60V3\EPOC32\include\eikappui.h \ + \S60V3\EPOC32\include\eikaufty.h \ + \S60V3\EPOC32\include\eikbctrl.h \ + \S60V3\EPOC32\include\eikbtgpc.h \ + \S60V3\EPOC32\include\eikbtgrp.h \ + \S60V3\EPOC32\include\eikbutb.h \ + \S60V3\EPOC32\include\eikcal.h \ + \S60V3\EPOC32\include\eikcba.h \ + \S60V3\EPOC32\include\eikccpu.h \ + \S60V3\EPOC32\include\eikcmbut.h \ + \S60V3\EPOC32\include\eikcmobs.h \ + \S60V3\EPOC32\include\eikcolor.hrh \ + \S60V3\EPOC32\include\eikctgrp.h \ + \S60V3\EPOC32\include\eikcycledef.h \ + \S60V3\EPOC32\include\eikdef.h \ + \S60V3\EPOC32\include\eikdgfty.h \ + \S60V3\EPOC32\include\eikdialg.h \ + \S60V3\EPOC32\include\eikdoc.h \ + \S60V3\EPOC32\include\eikdpobs.h \ + \S60V3\EPOC32\include\eikedwin.h \ + \S60V3\EPOC32\include\eikedwob.h \ + \S60V3\EPOC32\include\eikenv.h \ + \S60V3\EPOC32\include\eikfctry.h \ + \S60V3\EPOC32\include\eikfpne.h \ + \S60V3\EPOC32\include\eikimage.h \ + \S60V3\EPOC32\include\eiklay.h \ + \S60V3\EPOC32\include\eiklbed.h \ + \S60V3\EPOC32\include\eiklbm.h \ + \S60V3\EPOC32\include\eiklbo.h \ + \S60V3\EPOC32\include\eiklbv.h \ + \S60V3\EPOC32\include\eiklbx.h \ + \S60V3\EPOC32\include\eiklibry.h \ + \S60V3\EPOC32\include\eikmenub.h \ + \S60V3\EPOC32\include\eikmenup.h \ + \S60V3\EPOC32\include\eikmfne.h \ + \S60V3\EPOC32\include\eikmobs.h \ + \S60V3\EPOC32\include\eikon.hrh \ + \S60V3\EPOC32\include\eiksbfrm.h \ + \S60V3\EPOC32\include\eiksbobs.h \ + \S60V3\EPOC32\include\eikscbut.h \ + \S60V3\EPOC32\include\eikscrlb.h \ + \S60V3\EPOC32\include\eikseced.h \ + \S60V3\EPOC32\include\eikspmod.h \ + \S60V3\EPOC32\include\eiksrv.h \ + \S60V3\EPOC32\include\eiksrv.pan \ + \S60V3\EPOC32\include\eiksrvc.h \ + \S60V3\EPOC32\include\eiksrvs.h \ + \S60V3\EPOC32\include\eikstart.h \ + \S60V3\EPOC32\include\eiktxlbm.h \ + \S60V3\EPOC32\include\eiktxlbx.h \ + \S60V3\EPOC32\include\eikunder.h \ + \S60V3\EPOC32\include\eikvcurs.h \ + \S60V3\EPOC32\include\es_sock.h \ + \S60V3\EPOC32\include\es_sock.inl \ + \S60V3\EPOC32\include\f32file.h \ + \S60V3\EPOC32\include\f32file.inl \ + \S60V3\EPOC32\include\fbs.h \ + \S60V3\EPOC32\include\fepbase.h \ + \S60V3\EPOC32\include\fldbase.h \ + \S60V3\EPOC32\include\fldbltin.h \ + \S60V3\EPOC32\include\fldinfo.h \ + \S60V3\EPOC32\include\fldset.h \ + \S60V3\EPOC32\include\fntstore.h \ + \S60V3\EPOC32\include\frmframe.h \ + \S60V3\EPOC32\include\frmlaydt.h \ + \S60V3\EPOC32\include\frmparam.h \ + \S60V3\EPOC32\include\frmtlay.h \ + \S60V3\EPOC32\include\frmtview.h \ + \S60V3\EPOC32\include\frmvis.h \ + \S60V3\EPOC32\include\gdi.h \ + \S60V3\EPOC32\include\gdi.inl \ + \S60V3\EPOC32\include\graphicsaccelerator.h \ + \S60V3\EPOC32\include\gulalign.h \ + \S60V3\EPOC32\include\gulbordr.h \ + \S60V3\EPOC32\include\gulcolor.h \ + \S60V3\EPOC32\include\guldef.h \ + \S60V3\EPOC32\include\gulftflg.hrh \ + \S60V3\EPOC32\include\gulicon.h \ + \S60V3\EPOC32\include\gulutil.h \ + \S60V3\EPOC32\include\in_sock.h \ + \S60V3\EPOC32\include\lafmain.h \ + \S60V3\EPOC32\include\lafpublc.h \ + \S60V3\EPOC32\include\lafpublc.hrh \ + \S60V3\EPOC32\include\libc\_ansi.h \ + \S60V3\EPOC32\include\libc\ctype.h \ + \S60V3\EPOC32\include\libc\machine\types.h \ + \S60V3\EPOC32\include\libc\stdarg_e.h \ + \S60V3\EPOC32\include\libc\stddef.h \ + \S60V3\EPOC32\include\libc\stdio.h \ + \S60V3\EPOC32\include\libc\stdlib.h \ + \S60V3\EPOC32\include\libc\string.h \ + \S60V3\EPOC32\include\libc\sys\reent.h \ + \S60V3\EPOC32\include\libc\sys\stdio_t.h \ + \S60V3\EPOC32\include\libc\sys\time.h \ + \S60V3\EPOC32\include\libc\time.h \ + \S60V3\EPOC32\include\mda\client\utility.h \ + \S60V3\EPOC32\include\mda\common\base.h \ + \S60V3\EPOC32\include\medobsrv.h \ + \S60V3\EPOC32\include\mm\mmcaf.h \ + \S60V3\EPOC32\include\mmf\common\MmfFourCC.h \ + \S60V3\EPOC32\include\mmf\common\MmfIpc.inl \ + \S60V3\EPOC32\include\mmf\common\MmfUtilities.h \ + \S60V3\EPOC32\include\mmf\common\MmfUtilities.inl \ + \S60V3\EPOC32\include\mmf\common\Mmfbase.h \ + \S60V3\EPOC32\include\mmf\common\mmcaf.h \ + \S60V3\EPOC32\include\mmf\common\mmfaudio.h \ + \S60V3\EPOC32\include\mmf\common\mmfbase.h \ + \S60V3\EPOC32\include\mmf\common\mmfcontroller.h \ + \S60V3\EPOC32\include\mmf\common\mmfcontrollerframework.h \ + \S60V3\EPOC32\include\mmf\common\mmfcontrollerframeworkbase.h \ + \S60V3\EPOC32\include\mmf\common\mmfcontrollerpluginresolver.h \ + \S60V3\EPOC32\include\mmf\common\mmfipc.h \ + \S60V3\EPOC32\include\mmf\common\mmfstandardcustomcommands.h \ + \S60V3\EPOC32\include\mmf\common\mmfutilities.h \ + \S60V3\EPOC32\include\mmf\common\mmfvideo.h \ + \S60V3\EPOC32\include\mmf\plugin\mmfPluginInterfaceUIDs.hrh \ + \S60V3\EPOC32\include\mmf\server\mmfbuffer.h \ + \S60V3\EPOC32\include\mmf\server\mmfbuffer.hrh \ + \S60V3\EPOC32\include\mmf\server\mmfdatabuffer.h \ + \S60V3\EPOC32\include\mmf\server\mmfdatasink.h \ + \S60V3\EPOC32\include\mmf\server\mmfdatasource.h \ + \S60V3\EPOC32\include\mmf\server\mmfdatasourcesink.hrh \ + \S60V3\EPOC32\include\nifvar.h \ + \S60V3\EPOC32\include\openfont.h \ + \S60V3\EPOC32\include\partitions.h \ + \S60V3\EPOC32\include\picodrive.rsg \ + \S60V3\EPOC32\include\s32buf.h \ + \S60V3\EPOC32\include\s32buf.inl \ + \S60V3\EPOC32\include\s32file.h \ + \S60V3\EPOC32\include\s32file.inl \ + \S60V3\EPOC32\include\s32mem.h \ + \S60V3\EPOC32\include\s32mem.inl \ + \S60V3\EPOC32\include\s32page.h \ + \S60V3\EPOC32\include\s32page.inl \ + \S60V3\EPOC32\include\s32share.h \ + \S60V3\EPOC32\include\s32share.inl \ + \S60V3\EPOC32\include\s32std.h \ + \S60V3\EPOC32\include\s32std.inl \ + \S60V3\EPOC32\include\s32stor.h \ + \S60V3\EPOC32\include\s32stor.inl \ + \S60V3\EPOC32\include\s32strm.h \ + \S60V3\EPOC32\include\s32strm.inl \ + \S60V3\EPOC32\include\savenotf.h \ + \S60V3\EPOC32\include\tagma.h \ + \S60V3\EPOC32\include\txtetext.h \ + \S60V3\EPOC32\include\txtetext.inl \ + \S60V3\EPOC32\include\txtfmlyr.h \ + \S60V3\EPOC32\include\txtfmlyr.inl \ + \S60V3\EPOC32\include\txtfmstm.h \ + \S60V3\EPOC32\include\txtfrmat.h \ + \S60V3\EPOC32\include\txtfrmat.inl \ + \S60V3\EPOC32\include\txtstyle.h \ + \S60V3\EPOC32\include\txtstyle.inl \ + \S60V3\EPOC32\include\uikon.hrh \ + \S60V3\EPOC32\include\vwsappst.h \ + \S60V3\EPOC32\include\vwsdef.h \ + \S60V3\EPOC32\include\w32std.h \ + \S60V3\epoc32\include\variant\Symbian_OS_v9.1.hrh \ + \picodrive\pico\GGenie.h \ + \picodrive\pico\Pico.h \ + \picodrive\pico\PicoInt.h \ + \picodrive\pico\pico.h \ + \picodrive\s60\PicoDriveexe.h \ + \picodrive\s60\S60V3Video.inl \ + \picodrive\unzip.h + +$(EPOCBLDUDEB)\picodriveexe.o : \picodrive\S60\picodriveexe.cpp + echo picodriveexe.cpp + $(CWUDEB) -o "$@" -c "\picodrive\S60\picodriveexe.cpp" + +LISTINGUDEBpicodriveexe : $(EPOCBLDUDEB)\picodriveexe.lis + perl -S ecopyfile.pl $? \picodrive\S60\picodriveexe.WINSCW.lst + +$(EPOCBLDUREL)\picodriveexe.o : \picodrive\S60\picodriveexe.cpp + echo picodriveexe.cpp + $(CWUREL) -o "$@" -c "\picodrive\S60\picodriveexe.cpp" + +LISTINGURELpicodriveexe : $(EPOCBLDUREL)\picodriveexe.lis + perl -S ecopyfile.pl $? \picodrive\S60\picodriveexe.WINSCW.lst + + + +# Source unzip.c + +$(EPOCBLDUDEB)\unzip.o \ +$(EPOCBLDUREL)\unzip.o \ +: \ + \S60V3\EPOC32\include\libc\_ansi.h \ + \S60V3\EPOC32\include\libc\assert.h \ + \S60V3\EPOC32\include\libc\ctype.h \ + \S60V3\EPOC32\include\libc\machine\types.h \ + \S60V3\EPOC32\include\libc\stdarg_e.h \ + \S60V3\EPOC32\include\libc\stddef.h \ + \S60V3\EPOC32\include\libc\stdio.h \ + \S60V3\EPOC32\include\libc\stdlib.h \ + \S60V3\EPOC32\include\libc\string.h \ + \S60V3\EPOC32\include\libc\sys\reent.h \ + \S60V3\EPOC32\include\libc\sys\stdio_t.h \ + \S60V3\EPOC32\include\libc\time.h \ + \S60V3\EPOC32\include\zconf.h \ + \S60V3\epoc32\include\variant\Symbian_OS_v9.1.hrh \ + \picodrive\unzip.h \ + \picodrive\zlib\zlib.h + +$(EPOCBLDUDEB)\unzip.o : \picodrive\unzip.c + echo unzip.c + $(CWUDEB) -o "$@" -c "\picodrive\unzip.c" + +LISTINGUDEBunzip : $(EPOCBLDUDEB)\unzip.lis + perl -S ecopyfile.pl $? \picodrive\unzip.WINSCW.lst + +$(EPOCBLDUREL)\unzip.o : \picodrive\unzip.c + echo unzip.c + $(CWUREL) -o "$@" -c "\picodrive\unzip.c" + +LISTINGURELunzip : $(EPOCBLDUREL)\unzip.lis + perl -S ecopyfile.pl $? \picodrive\unzip.WINSCW.lst + + + +# Source PicoDrive.UID.CPP + +$(EPOCBLDUDEB)\PicoDrive_UID_.o \ +$(EPOCBLDUREL)\PicoDrive_UID_.o \ +: \ + \S60V3\EPOC32\include\e32capability.h \ + \S60V3\EPOC32\include\e32cmn.h \ + \S60V3\EPOC32\include\e32cmn.inl \ + \S60V3\EPOC32\include\e32const.h \ + \S60V3\EPOC32\include\e32def.h \ + \S60V3\EPOC32\include\e32des16.h \ + \S60V3\EPOC32\include\e32des8.h \ + \S60V3\EPOC32\include\e32err.h \ + \S60V3\epoc32\include\variant\Symbian_OS_v9.1.hrh + +$(EPOCBLDUDEB)\PicoDrive_UID_.o : \picodrive\s60\PicoDrive.UID.CPP + echo PicoDrive.UID.CPP + $(CWUDEB) -o "$@" -c "\picodrive\s60\PicoDrive.UID.CPP" + +LISTINGUDEBPicoDrive_UID_ : $(EPOCBLDUDEB)\PicoDrive_UID_.lis + perl -S ecopyfile.pl $? \picodrive\s60\PicoDrive_UID_.WINSCW.lst + +$(EPOCBLDUREL)\PicoDrive_UID_.o : \picodrive\s60\PicoDrive.UID.CPP + echo PicoDrive.UID.CPP + $(CWUREL) -o "$@" -c "\picodrive\s60\PicoDrive.UID.CPP" + +LISTINGURELPicoDrive_UID_ : $(EPOCBLDUREL)\PicoDrive_UID_.lis + perl -S ecopyfile.pl $? \picodrive\s60\PicoDrive_UID_.WINSCW.lst + + + +ROMFILE: + +# Implicit rule for generating .lis files + +.SUFFIXES : .lis .o + +.o.lis: + $(COMPILER_PATH)mwldsym2.exe -msgstyle gcc -S -show source,unmangled,comments $< -o $@ + + + +GENERIC_RELEASEABLES1= \ + $(EPOCDATA)\Z\Resource\Apps\PicoDrive.RSC \ + $(EPOCDATA)\Z\Resource\Apps\PicoDrive.mbm \ + $(EPOCDATA)\Z\Resource\Apps\PicoDrive_loc.RSC \ + $(EPOCDATA)\Z\private\10003a3f\apps\PicoDrive_reg.RSC \ + $(EPOCINC)\PicoDrive.RSG \ + \S60V3\EPOC32\LOCALISATION\GROUP\PICODRIVE.INFO \ + \S60V3\EPOC32\LOCALISATION\GROUP\PICODRIVE_LOC.INFO \ + \S60V3\EPOC32\LOCALISATION\GROUP\PICODRIVE_REG.INFO \ + \S60V3\EPOC32\LOCALISATION\PICODRIVE_LOC\RSC\PICODRIVE_LOC.RPP \ + \S60V3\EPOC32\LOCALISATION\PICODRIVE_REG\RSC\PICODRIVE_REG.RPP \ + \S60V3\EPOC32\LOCALISATION\\MBM\PICOL.BMP \ + \S60V3\EPOC32\LOCALISATION\\MBM\PICOLMI.BMP \ + \S60V3\EPOC32\LOCALISATION\\MBM\PICOS.BMP \ + \S60V3\EPOC32\LOCALISATION\\MBM\PICOSMI.BMP \ + \S60V3\EPOC32\LOCALISATION\\RSC\PICODRIVE.RPP + +WHATGENERIC: + @echo $(GENERIC_RELEASEABLES1) + +CLEANGENERIC: + -$(ERASE) $(GENERIC_RELEASEABLES1) + +# Rules to create all necessary directories + +GENERIC_MAKEWORK : \ + \S60V3\EPOC32\BUILD\picodrive\s60\picodrives60v3\WINSCW \ + \S60V3\EPOC32\DATA\Z\Resource\Apps \ + \S60V3\EPOC32\DATA\Z\private\10003a3f\apps \ + \S60V3\EPOC32\INCLUDE +MAKEWORKLIBRARY : \ + \S60V3\EPOC32\RELEASE\WINSCW\UDEB +MAKEWORKUDEB : \ + \S60V3\EPOC32\BUILD\picodrive\s60\picodrives60v3\WINSCW\UDEB \ + \S60V3\EPOC32\RELEASE\WINSCW\UDEB \ + \S60V3\EPOC32\RELEASE\WINSCW\UDEB\Z\Resource\Apps \ + \S60V3\EPOC32\RELEASE\WINSCW\UDEB\Z\private\10003a3f\apps +MAKEWORKUREL : \ + \S60V3\EPOC32\BUILD\picodrive\s60\picodrives60v3\WINSCW\UREL \ + \S60V3\EPOC32\RELEASE\WINSCW\UREL \ + \S60V3\EPOC32\RELEASE\WINSCW\UREL\Z\Resource\Apps \ + \S60V3\EPOC32\RELEASE\WINSCW\UREL\Z\private\10003a3f\apps + +\S60V3\EPOC32\BUILD\picodrive\s60\picodrives60v3\WINSCW \ +\S60V3\EPOC32\BUILD\picodrive\s60\picodrives60v3\WINSCW\UDEB \ +\S60V3\EPOC32\BUILD\picodrive\s60\picodrives60v3\WINSCW\UREL \ +\S60V3\EPOC32\DATA\Z\Resource\Apps \ +\S60V3\EPOC32\DATA\Z\private\10003a3f\apps \ +\S60V3\EPOC32\INCLUDE \ +\S60V3\EPOC32\RELEASE\WINSCW\UDEB \ +\S60V3\EPOC32\RELEASE\WINSCW\UDEB\Z\Resource\Apps \ +\S60V3\EPOC32\RELEASE\WINSCW\UDEB\Z\private\10003a3f\apps \ +\S60V3\EPOC32\RELEASE\WINSCW\UREL \ +\S60V3\EPOC32\RELEASE\WINSCW\UREL\Z\Resource\Apps \ +\S60V3\EPOC32\RELEASE\WINSCW\UREL\Z\private\10003a3f\apps \ +: + perl -S emkdir.pl $@ + diff --git a/platform/s60/picodrives60v3_UDEB.mak b/platform/s60/picodrives60v3_UDEB.mak new file mode 100644 index 00000000..3b947db1 --- /dev/null +++ b/platform/s60/picodrives60v3_UDEB.mak @@ -0,0 +1,6 @@ + +BLD: UDEB +REBUILD : CLEANUDEB UDEB + +include picodrives60v3.mak + diff --git a/platform/s60/picodrives60v3_UREL.mak b/platform/s60/picodrives60v3_UREL.mak new file mode 100644 index 00000000..bd06ccea --- /dev/null +++ b/platform/s60/picodrives60v3_UREL.mak @@ -0,0 +1,6 @@ + +BLD: UREL +REBUILD : CLEANUREL UREL + +include picodrives60v3.mak + diff --git a/platform/uiq2/ClientServer.h b/platform/uiq2/ClientServer.h new file mode 100644 index 00000000..b320bce9 --- /dev/null +++ b/platform/uiq2/ClientServer.h @@ -0,0 +1,69 @@ +// protocol used to talk between exe and it's launcher + +#ifndef __CLIENTSERVER_H +#define __CLIENTSERVER_H + +#include + +// names +_LIT(KServerName, "PicodriveNServ"); +_LIT(KServerWGName, "Picosmall"); // window group name +_LIT(KClientName, "PicodriveN"); +_LIT(KClientFind, "PicodriveN*"); // client search mask (for TFindLibrary) + + +// opcodes used in message passing between client and server +enum TPicoServRqst { + PicoMsgLoadState, + PicoMsgSaveState, + PicoMsgLoadROM, + PicoMsgResume, + PicoMsgReset, + PicoMsgKeys, + PicoMsgPause, + PicoMsgQuit, + PicoMsgConfigChange, // launcher -> emu + PicoMsgRetrieveConfig, // emu -> launcher + PicoMsgRetrieveDebugStr,// fixed to 512 bytes 4 now + kDefaultMessageSlots // this is how many messages we need :) +}; + + +// event messages to launcher +enum TPicoLauncherEvents { + EEventKeyCfgDone = EEventUser + 1, + EEventGamePaused, +}; + + +// configuration data to be sent between server and client +struct TPicoConfig { + enum TPicoScreenRotation { + PRot0, + PRot90, + PRot180, + PRot270 + }; + enum TPicoScreenMode { + PMCenter, + PMFit, + PMFit2 + }; + enum TPicoFrameSkip { + PFSkipAuto = -1, + PFSkip0 + }; + TInt32 iScreenRotation; + TInt32 iScreenMode; + TUint32 iFlags; // LSb->MSb: use_sram, show_fps, enable_sound, sound_rate(3bits), gzip_saves{=0x40}, dont_use_mot_vol + // enable_ym2612&dac, enable_sn76496, enable_z80, stereo_sound; + // alt_renderer, 6button_gamepad, accurate_timing + TInt32 iPicoOpt; + TInt32 iFrameskip; + TUint32 iKeyBinds[32]; + TUint32 iAreaBinds[19]; + TInt32 PicoRegion; +}; + + +#endif // __CLIENTSERVER_H diff --git a/platform/uiq2/Makefile b/platform/uiq2/Makefile new file mode 100644 index 00000000..3b96009e --- /dev/null +++ b/platform/uiq2/Makefile @@ -0,0 +1,321 @@ +# environmental vars required: +# EPOCROOT2 - root of your SDK with slash at the end + +# settings +#dprint = 1 +#mz80 = 1 +#debug_cyclone = 1 +asm_memory = 1 +#asm_render = 1 +#use_musashi = 1 + +EPOCBLDUREL = _BUILD +EPOCTRGUREL = $(EPOCROOT2)EPOC32\RELEASE\ARMI\UREL +EPOCLINKUREL = $(EPOCTRGUREL) +EPOCSTATLINKUREL = $(EPOCTRGUREL) + + +# must set both PATH and Path to make it work correctly (?) +Path:=$(EPOCROOT2)EPOC32\gcc\bin;$(Path) +PATH:=$(Path) +ERASE = @erase 2>>nul + + +ALL : UREL +UREL : CHECKENV MAKEDIRS +UREL : $(EPOCTRGUREL)\PICOSMALL.EXE + +CLEAN : + @perl -S ermdir.pl "$(EPOCBLDUREL)" + @del *.o 2> NUL + +CLEANZ : + del ..\..\zlib\*.o 2> NUL + +CLEANM : + del ..\..\musashi\*.o 2> NUL + +CLEANALL : CLEAN CLEANZ CLEANM + + +# check for EPOCROOT2 +CHECKENV : $(EPOCROOT2)epoc32 + +$(EPOCROOT2)epoc32 : + @echo Please set EPOCROOT2 environmental variable to full path to your SDK + @echo with ending slash (something like C:\Uiq_21\) + @cd : 2> NUL # do something stupid to make it silently fail + + +# GCC +INCDIR = -I. -I "..\..\" -I "$(EPOCROOT2)EPOC32\INCLUDE" -I "$(EPOCROOT2)EPOC32\INCLUDE\LIBC" + +GCCFLAGS = -nostdinc -Wall -Wno-ctor-dtor-privacy -Wno-unknown-pragmas -march=armv4t -mthumb-interwork -pipe -O3 -fomit-frame-pointer + +GCCDEFS = -D__SYMBIAN32__ -D__GCC32__ -D__EPOC32__ -D__MARM__ -D__MARM_ARMI__ -D__EXE__ -DNDEBUG -D_UNICODE -DARM + +# dprint +ifeq "$(dprint)" "1" +GCCDEFS += -D__DEBUG_PRINT +endif +# drz80/mz80 +ifeq "$(mz80)" "1" +GCCDEFS += -D_USE_MZ80 +else +GCCDEFS += -D_USE_DRZ80 +endif +# debug_cyclone +ifeq "$(debug_cyclone)" "1" +use_musashi := 1 +GCCDEFS += -DEMU_C68K +asm_memory := 0 +endif +# musashi +ifeq "$(use_musashi)" "1" +GCCDEFS += -DEMU_M68K +else +GCCDEFS += -DEMU_C68K +endif + + +GCC = gcc -c $(GCCFLAGS) $(GCCDEFS) $(INCDIR) + + +LIBSUREL = \ + $(EPOCSTATLINKUREL)\EGCC.LIB \ + $(EPOCLINKUREL)\ESTLIB.LIB \ + $(EPOCLINKUREL)\WS32.LIB \ + $(EPOCLINKUREL)\HAL.LIB \ + $(EPOCLINKUREL)\EUSER.LIB \ + $(EPOCLINKUREL)\EFSRV.LIB \ + $(EPOCLINKUREL)\EZLIB.LIB + +$(EPOCTRGUREL)\PICOSMALL.EXE : $(EPOCBLDUREL)\PICOSMALL.in $(EPOCSTATLINKUREL)\EEXE.LIB $(LIBSUREL) + @echo * linking and finishing + @ld -s -e _E32Startup -u _E32Startup \ + --base-file "$(EPOCBLDUREL)\PICOSMALL.bas" -o "$(EPOCBLDUREL)\PICOSMALL.EXE" \ + "$(EPOCSTATLINKUREL)\EEXE.LIB" --whole-archive "$(EPOCBLDUREL)\PICOSMALL.in" \ + --no-whole-archive $(LIBSUREL) $(USERLDFLAGS) + -$(ERASE) "$(EPOCBLDUREL)\PICOSMALL.EXE" + @dlltool -m arm_interwork \ + --base-file "$(EPOCBLDUREL)\PICOSMALL.bas" \ + --output-exp "$(EPOCBLDUREL)\PICOSMALL.exp" + -$(ERASE) "$(EPOCBLDUREL)\PICOSMALL.bas" + @ld -s -e _E32Startup -u _E32Startup \ + "$(EPOCBLDUREL)\PICOSMALL.exp" \ + -Map "$(EPOCBLDUREL)\PICOSMALL.EXE.map" -o "$(EPOCBLDUREL)\PICOSMALL.EXE" \ + "$(EPOCSTATLINKUREL)\EEXE.LIB" --whole-archive "$(EPOCBLDUREL)\PICOSMALL.in" \ + --no-whole-archive $(LIBSUREL) $(USERLDFLAGS) + -$(ERASE) "$(EPOCBLDUREL)\PICOSMALL.exp" +ifeq "$(noecompxl)" "1" + @petran "$(EPOCBLDUREL)\PICOSMALL.EXE" "$@" \ + -nocall -uid1 0x1000007a -uid2 0x00000000 -uid3 0x00000000 \ + -heap 0x00000001 0x00800000 +else + @petran_ "$(EPOCBLDUREL)\PICOSMALL.EXE" "$@" \ + -nocall -uid1 0x1000007a -uid2 0x00000000 -uid3 0x00000000 \ + -heap 0x00000001 0x00800000 -stack 0x80000000 +endif +# -$(ERASE) "$(EPOCBLDUREL)\PICOSMALL.EXE" + @perl -S ecopyfile.pl "$@" "PICOSMALL.EXE" +ifeq "$(up)" "1" + @quploadpico.cmd +endif + + +OBJECTSUREL= \ + $(EPOCBLDUREL)\debug.o \ + $(EPOCBLDUREL)\CART.o \ + $(EPOCBLDUREL)\DRAW.o \ + $(EPOCBLDUREL)\DRAW2.o \ + $(EPOCBLDUREL)\MAIN.o \ + $(EPOCBLDUREL)\MEMORY.o \ + $(EPOCBLDUREL)\PICO.o \ + $(EPOCBLDUREL)\SEK.o \ + $(EPOCBLDUREL)\VIDEOPORT.o \ + $(EPOCBLDUREL)\SIMPLESERVER.o \ + $(EPOCBLDUREL)\VID.o \ + $(EPOCBLDUREL)\Utils.o \ + $(EPOCBLDUREL)\Area.o \ + $(EPOCBLDUREL)\Misc.o \ + $(EPOCBLDUREL)\unzip.o \ + ..\..\zlib\gzio_symb.o \ + $(EPOCBLDUREL)\sound.o \ + $(EPOCBLDUREL)\sn76496.o \ + $(EPOCBLDUREL)\ym2612.o \ + $(EPOCBLDUREL)\blit.o + +ifeq "$(debug_cyclone)" "1" +OBJECTSUREL += $(EPOCBLDUREL)\Cyclone.o $(EPOCBLDUREL)\_cyclone_debug.o +endif +# the MUSASHI core +ifeq "$(use_musashi)" "1" +OBJECTSUREL += \ + ..\..\musashi\m68kcpu.o \ + ..\..\musashi\m68kops.o \ + ..\..\musashi\m68kopac.o \ + ..\..\musashi\m68kopdm.o \ + ..\..\musashi\m68kopnz.o \ + ..\..\musashi\m68kdasm.o +else +OBJECTSUREL += $(EPOCBLDUREL)\Cyclone.o +endif + +ifeq "$(mz80)" "1" +OBJECTSUREL := $(OBJECTSUREL) $(EPOCBLDUREL)\mz80.o +else +OBJECTSUREL := $(OBJECTSUREL) $(EPOCBLDUREL)\DrZ80.o +endif + +ifeq "$(asm_memory)" "1" +ASMDEFINES += -D_ASM_MEMORY_C +OBJECTSUREL := $(OBJECTSUREL) $(EPOCBLDUREL)\memory_asm.o +endif + +ifeq "$(asm_render)" "1" +ASMDEFINES += -D_ASM_DRAW_C +OBJECTSUREL := $(OBJECTSUREL) $(EPOCBLDUREL)\draw_asm.o $(EPOCBLDUREL)\draw2_asm.o +endif + +$(EPOCBLDUREL)\PICOSMALL.in : $(OBJECTSUREL) + @echo * ar + @if exist "$@" del "$@" + @ar cr $@ $^ + +..\..\Cyclone\proj\Cyclone.s : + @echo You need to build Cyclone first. See Cyclone.txt in cyclone directory. + @cd : 2> NUL # do something stupid to make it silently fail + +$(EPOCBLDUREL)\Cyclone.o : ..\..\Cyclone\proj\Cyclone.s + @echo * assembling Cyclone.. + @as -marmv4t -mthumb-interwork -o $@ $^ + +$(EPOCBLDUREL)\DrZ80.o : ..\..\pico\sound\DrZ80.s ..\..\pico\sound\DrZ80.h + @echo * assembling DrZ80.. + @as -marmv4t -mthumb-interwork -o $@ ..\..\pico\sound\DrZ80.s + + +# Source + +$(EPOCBLDUREL)\debug.o : debug.cpp debug.h + @echo * debug.cpp + @$(GCC) -o $@ debug.cpp + +$(EPOCBLDUREL)\MAIN.o : Main.cpp ..\..\pico\picoInt.h vid.h SimpleServer.h ClientServer.h audio.h debug.h + @echo * Main.cpp + @$(GCC) -o $@ "Main.cpp" + +$(EPOCBLDUREL)\VID.o : VID.cpp vid.h ClientServer.h ..\..\pico\picoInt.h + @echo * Vid.cpp + @$(GCC) -o $@ "VID.cpp" + +$(EPOCBLDUREL)\SIMPLESERVER.o : SIMPLESERVER.cpp version.h ClientServer.h SimpleServer.h ..\..\pico\picoInt.h debug.h + @echo * SimpleServer.cpp + @$(GCC) -o $@ "SIMPLESERVER.cpp" + +$(EPOCBLDUREL)\CART.o : ..\..\pico\Cart.c ..\..\pico\picoInt.h ..\..\pico\Pico.h ..\..\unzip\unzip.h + @echo * Cart.c + @$(GCC) -D_UNZIP_SUPPORT -o $@ "..\..\pico\Cart.c" + +$(EPOCBLDUREL)\DRAW.o : ..\..\pico\Draw.c ..\..\pico\picoInt.h ..\..\pico\Pico.h + @echo * Draw.c + @$(GCC) $(ASMDEFINES) -o $@ "..\..\pico\Draw.c" +# + +$(EPOCBLDUREL)\DRAW2.o : ..\..\pico\Draw2.c ..\..\pico\picoInt.h ..\..\pico\Pico.h + @echo * Draw2.c + @$(GCC) $(ASMDEFINES) -o $@ "..\..\pico\Draw2.c" + +$(EPOCBLDUREL)\MEMORY.o : ..\..\pico\Memory.c ..\..\pico\picoInt.h ..\..\pico\Pico.h + @echo * Memory.c + @$(GCC) $(ASMDEFINES) -o $@ "..\..\pico\Memory.c" + +$(EPOCBLDUREL)\PICO.o : ..\..\pico\Pico.c ..\..\pico\picoInt.h ..\..\pico\Pico.h + @echo * Pico.c + @$(GCC) -o $@ "..\..\pico\Pico.c" + +$(EPOCBLDUREL)\SEK.o : ..\..\pico\Sek.c ..\..\pico\picoInt.h ..\..\pico\Pico.h + @echo * Sek.c + @$(GCC) -o $@ "..\..\pico\Sek.c" + +$(EPOCBLDUREL)\VIDEOPORT.o : ..\..\pico\Videoport.c ..\..\pico\picoInt.h ..\..\pico\Pico.h + @echo * Videoport.c + @$(GCC) -o $@ "..\..\pico\Videoport.c" + +$(EPOCBLDUREL)\Utils.o : ..\..\pico\Utils.c ..\..\pico\picoInt.h ..\..\pico\Pico.h + @echo * Utils.c + @$(GCC) -o $@ "..\..\pico\Utils.c" + +$(EPOCBLDUREL)\Area.o : ..\..\pico\Area.c ..\..\pico\picoInt.h ..\..\pico\Pico.h + @echo * Area.c + @$(GCC) -o $@ "..\..\pico\Area.c" + +$(EPOCBLDUREL)\Misc.o : ..\..\pico\Misc.c ..\..\pico\picoInt.h ..\..\pico\Pico.h + @echo * Misc.c + @$(GCC) -o $@ "..\..\pico\Misc.c" + +$(EPOCBLDUREL)\unzip.o : ..\..\unzip\unzip.c ..\..\unzip\unzip.h + @echo * unzip.c + @$(GCC) -o $@ "..\..\unzip\unzip.c" + +# assembly "optimized" stuff +$(EPOCBLDUREL)\blit.o : blit.s + @echo * blit.s + @as -marmv4t -mthumb-interwork -o $@ blit.s + +$(EPOCBLDUREL)\draw_asm.o : ..\..\pico\draw.s + @echo * draw.s + @as -marmv4t -mthumb-interwork -o $@ ..\..\pico\draw.s + +$(EPOCBLDUREL)\draw2_asm.o : ..\..\pico\draw2.s + @echo * draw2.s + @as -marmv4t -mthumb-interwork -o $@ ..\..\pico\draw2.s + +$(EPOCBLDUREL)\memory_asm.o : ..\..\pico\memory.s + @echo * memory.s + @as -marmv4t -mthumb-interwork -o $@ ..\..\pico\memory.s + +# sound stuff +$(EPOCBLDUREL)\sound.o : ..\..\pico\sound\sound.c ..\..\pico\sound\sound.h + @echo * sound.c + @$(GCC) -o $@ "..\..\pico\sound\sound.c" + +$(EPOCBLDUREL)\ym2612.o : ..\..\pico\sound\ym2612.c ..\..\pico\sound\ym2612.h ..\..\pico\sound\driver.h + @echo * ym2612.c + @$(GCC) -o $@ "..\..\pico\sound\ym2612.c" + +$(EPOCBLDUREL)\sn76496.o : ..\..\pico\sound\sn76496.c ..\..\pico\sound\sn76496.h ..\..\pico\sound\driver.h + @echo * sn76496.c + @$(GCC) -o $@ "..\..\pico\sound\sn76496.c" + +$(EPOCBLDUREL)\mz80.o : ..\..\pico\sound\mz80.c ..\..\pico\sound\mz80.h + @echo * mz80.c + @$(GCC) -o $@ "..\..\pico\sound\mz80.c" + +# -D__DEBUG_PRINT_SND + +# misc + +$(EPOCBLDUREL)\_cyclone_debug.o : ..\..\pico\_cyclone_debug.c + @echo * _cyclone_debug.c + @$(GCC) -o $@ "..\..\pico\_cyclone_debug.c" + +# generic rule for generic C stuff + +.c.o: + @echo * $< + @$(GCC) $< -o $@ + + + +# --- SRCFILES END --- + + +# Rules to create all necessary directories + +MAKEDIRS : \ + _build + +_build : + @echo * making build dir + @perl -S emkdir.pl $@ diff --git a/platform/uiq2/SimpleServer.cpp b/platform/uiq2/SimpleServer.cpp new file mode 100644 index 00000000..6a58306d --- /dev/null +++ b/platform/uiq2/SimpleServer.cpp @@ -0,0 +1,430 @@ +// SimpleServer.cpp + +#include +#include +#include + +#include + +#include "debug.h" + +#include "version.h" +#include "ClientServer.h" +#include "SimpleServer.h" +#include "pico\picoInt.h" + +extern TInt machineUid; +extern int gamestate, gamestate_prev; +extern TPicoConfig currentConfig; +extern TPicoKeyConfigEntry keyConfigMotA[]; +extern const char *actionNames[]; +const char *RomFileName = 0; +int pico_was_reset = 0; + + +// utility +unsigned int bigend(unsigned int l) +{ + return (l>>24)|((l>>8)&0xff00)|((l<<8)&0xff0000)|(l<<24); +} + + +//********************************** +//CPicoServServer +//********************************** + + +CPicoServServer::CPicoServServer(TInt aPriority) + : CServer(aPriority) +{ +} + + +// Create and start a new count server. +void CPicoServServer::New() +{ + CPicoServServer *pS=new CPicoServServer(EPriority); + __ASSERT_ALWAYS(pS!=NULL,PanicServer(ESvrCreateServer)); + pS->StartL(KServerName); +} + + +// Create a new server session. +CSharableSession *CPicoServServer::NewSessionL(const TVersion &aVersion) const +{ + // check we're the right version + TVersion v(KPicoMajorVersionNumber,KPicoMinorVersionNumber,0); + if (!User::QueryVersionSupported(v,aVersion)) + User::Leave(KErrNotSupported); + // make new session + RThread aClient = Message().Client(); + return CPicoServSession::NewL(aClient, (CPicoServServer*)this); +} + + +//********************************** +//CPicoServSession +//********************************** + + +// constructor - must pass client to CSession +CPicoServSession::CPicoServSession(RThread &aClient, CPicoServServer *aServer) +: CSession(aClient), rom_data(0) +{ +// iPicoSvr=aServer; +} + +CPicoServSession* CPicoServSession::NewL(RThread &aClient, CPicoServServer * aServer) +{ + return new(ELeave) CPicoServSession(aClient,aServer); +} + + +void CPicoServSession::ServiceL(const RMessage& aMessage) +{ + TRAPD(err,DispatchMessageL(aMessage)); + aMessage.Complete(err); +} + + + +// service a client request; test the opcode and then do appropriate servicing +void CPicoServSession::DispatchMessageL(const RMessage &aMessage) +{ + switch (aMessage.Function()) { + case PicoMsgLoadState: + if(!rom_data) User::Leave(-1); // no ROM + User::LeaveIfError(saveLoadGame(1)); + gamestate = PGS_Running; + return; + + case PicoMsgSaveState: + if(!rom_data) User::Leave(-1); + User::LeaveIfError(saveLoadGame(0)); + gamestate = PGS_Running; + return; + + case PicoMsgLoadROM: + loadROM(); + return; + + case PicoMsgResume: + if(rom_data) gamestate = PGS_Running; + return; + + case PicoMsgReset: + if(rom_data) { + PicoReset(0); + pico_was_reset = 1; + gamestate = PGS_Running; + } + return; + + case PicoMsgKeys: + gamestate = PGS_KeyConfig; + return; + + case PicoMsgPause: + gamestate = PGS_Paused; + return; + + case PicoMsgQuit: + DEBUGPRINT(_L("got quit msg.")); + gamestate = PGS_Quit; + return; + + // config change + case PicoMsgConfigChange: // launcher -> emu + changeConfig(); + return; + + case PicoMsgRetrieveConfig: // emu -> launcher + sendConfig(); + return; + + case PicoMsgRetrieveDebugStr: // emu -> launcher + sendDebug(); + return; + + // requests we don't understand at all are a different thing, + // so panic the client here, this function also completes the message + default: + PanicClient(EBadRequest); + return; + } +} + + +void CPicoServSession::loadROM() +{ + TInt res; + + const TAny* pD=Message().Ptr0(); + + // TInt desLen=Message().Client().GetDesLength(pD); + + if(rom_data) { + // save SRAM for previous ROM + if(currentConfig.iFlags & 1) + saveLoadGame(0, 1); + } + + RomFileName = 0; + if(rom_data) { + free(rom_data); + rom_data = 0; + } + + // read the contents of the client pointer into a TPtr. + static TBuf8 writeBuf; + TRAP(res,Message().ReadL(pD,writeBuf)); + if (res!=KErrNone) { + PanicClient(EBadDescriptor); + return; + } + + // detect wrong extensions (.srm and .mds) + TBuf8<5> ext; + ext.Copy(writeBuf.Right(4)); + ext.LowerCase(); + if(!strcmp((char *)ext.PtrZ(), ".srm") || !strcmp((char *)ext.PtrZ(), "s.gz") || // .mds.gz + !strcmp((char *)ext.PtrZ(), ".mds")) { + User::Leave(3); + return; + } + + FILE *rom = fopen((char *) writeBuf.PtrZ(), "rb"); + if(!rom) { + DEBUGPRINT(_L("failed to open rom.")); + User::Leave(1); + return; + } + + + unsigned int rom_size = 0; + // zipfile support + if(!strcmp((char *)ext.PtrZ(), ".zip")) { + fclose(rom); + res = CartLoadZip((const char *) writeBuf.PtrZ(), &rom_data, &rom_size); + if(res) { + User::Leave(res); + return; + } + } else { + if( (res = PicoCartLoad(rom, &rom_data, &rom_size)) ) { + DEBUGPRINT(_L("PicoCartLoad() failed.")); + fclose(rom); + User::Leave(2); + return; + } + fclose(rom); + } + + // detect wrong files (Pico crashes on very small files), also see if ROM EP is good + if(rom_size <= 0x200 || strncmp((char *)rom_data, "Pico", 4) == 0 || + ((*(TUint16 *)(rom_data+4)<<16)|(*(TUint16 *)(rom_data+6))) >= (int)rom_size) { + free(rom_data); + rom_data = 0; + User::Leave(3); // not a ROM + } + + DEBUGPRINT(_L("PicoCartInsert(0x%08X, %d);"), rom_data, rom_size); + if(PicoCartInsert(rom_data, rom_size)) { + User::Leave(2); + return; + } + + pico_was_reset = 1; + + // global ROM file name for later use + RomFileName = (const char *) writeBuf.PtrZ(); + + // load SRAM for this ROM + if(currentConfig.iFlags & 1) + saveLoadGame(1, 1); + + // debug + #ifdef __DEBUG_PRINT + TInt cells = User::CountAllocCells(); + TInt mem; + User::AllocSize(mem); + DEBUGPRINT(_L("comm: cels=%d, size=%d KB"), cells, mem/1024); + gamestate = PGS_DebugHeap; + gamestate_prev = PGS_Running; + #else + gamestate = PGS_Running; + #endif +} + + +void CPicoServSession::changeConfig() +{ + DEBUGPRINT(_L("got new config.")); + + // receve it + const TAny* pD=Message().Ptr0(); + TPtr8 descr((TUint8*) ¤tConfig, sizeof(currentConfig)); + TRAPD(res,Message().ReadL(pD, descr)); + if (res!=KErrNone) { + PanicClient(EBadDescriptor); + return; + } + + // Motorola: enable experimental volume control + if((machineUid&0xfffffff0) == 0x101f6b20) { // Motorolas + if(currentConfig.iFlags & 0x40) { + currentConfig.iKeyBinds[11] = 0x00100000; // vol up + currentConfig.iKeyBinds[12] = 0x00200000; // vol down + keyConfigMotA[11].flags |= 0x40; // add "not configurable" flag + keyConfigMotA[12].flags |= 0x40; + } else { + currentConfig.iKeyBinds[11] &= ~0x00100000; // remove vol actions + currentConfig.iKeyBinds[12] &= ~0x00200000; + keyConfigMotA[11].flags &= ~0x40; // remove "not configurable" flag + keyConfigMotA[12].flags &= ~0x40; + } + } + + // set region, PicoOpt and rate + PicoRegionOverride = currentConfig.PicoRegion; + PicoOpt = currentConfig.iPicoOpt; + switch((currentConfig.iFlags>>3)&3) { + case 1: PsndRate=11025; break; + case 2: PsndRate=16000; break; + case 3: PsndRate=22050; break; + default: PsndRate= 8000; break; + } + + // 6 button pad, enable XYZM config if needed + if(PicoOpt & 0x20) { + actionNames[8] = "Z"; + actionNames[9] = "Y"; + actionNames[10] = "X"; + actionNames[11] = "MODE"; + } else { + actionNames[8] = actionNames[9] = actionNames[10] = actionNames[11] = 0; + } + + // if we are in center 90||270 modes, we can bind renderer switcher + if(currentConfig.iScreenMode == TPicoConfig::PMCenter && + (currentConfig.iScreenRotation == TPicoConfig::PRot90 || currentConfig.iScreenRotation == TPicoConfig::PRot270)) + actionNames[25] = "RENDERER"; + else actionNames[25] = 0; +} + + +void CPicoServSession::sendConfig() +{ + // send current config to client + currentConfig.iPicoOpt = PicoOpt; + TPtrC8 descr((TUint8*) ¤tConfig, sizeof(currentConfig)); + Write(Message().Ptr0(), descr); +} + +#ifdef __DEBUG_PRINT +extern "C" char *debugString(); +#endif + +void CPicoServSession::sendDebug() +{ +#ifdef __DEBUG_PRINT + char *str = debugString(); + // send current config to client + currentConfig.iPicoOpt = PicoOpt; + TPtrC8 descr((TUint8*) str, 1024); + Write(Message().Ptr0(), descr); +#endif +} + +// panic the client +void CPicoServSession::PanicClient(TInt aPanic) const +{ + Panic(_L("PicoN client"), aPanic); + // client screwed up - there is nothing for us to do now + RProcess me; + me.Terminate(1); +} + + +// write to the client thread; if unsuccessful, panic the client +void CPicoServSession::Write(const TAny* aPtr,const TDesC8& aDes,TInt anOffset) +{ + TRAPD(ret,WriteL(aPtr,aDes,anOffset);) + if (ret!=KErrNone) + PanicClient(EBadDescriptor); +} + + + +//********************************** +//Global functions +//********************************** + + +// The server thread. +TInt CPicoServServer::ThreadFunction(TAny* anArg) +{ + // install our exception hanler first + RThread().SetExceptionHandler(&ExceptionHandler, -1); + + // convert argument into semaphore reference +// RSemaphore& semaphore=*(RSemaphore *)anArg; + + // start scheduler and server + CActiveScheduler *pA=new CActiveScheduler; + __ASSERT_ALWAYS(pA!=NULL,PanicServer(EMainSchedulerError)); + CActiveScheduler::Install(pA); + //CTrapCleanup::New(); // docs say this is created automatically, but I somehow got E32USER-CBase 69 panic + CPicoServServer::New(); + // signal that we've started +// semaphore.Signal(); + // start fielding requests from clients + CActiveScheduler::Start(); + // finished + return(KErrNone); +} + + +// Panic the server +//GLDEF_C +void PanicServer(TPicoServPanic aPanic) +{ + User::Panic(_L("PicoN server"),aPanic); +} + + +// Create the server thread +// This function is exported from the DLL and called from the client +//EXPORT_C +TInt StartThread() +{ + TInt res=KErrNone; + // create server - if one of this name does not already exist + TFindServer findPicoServer(KServerName); + TFullName name; + if(findPicoServer.Next(name) == KErrNone) return -1; // we already exist + + RThread thread; +// RSemaphore semaphore; +// semaphore.CreateLocal(0); // create a semaphore so we know when thread finished + res=thread.Create(KServerName, // create new server thread + CPicoServServer::ThreadFunction, // thread's main function + KDefaultStackSize, + KMinHeapSize, + KPicoMaxHeapSize, +// &semaphore // passed as TAny* argument to thread function + 0 + ); + + if(res==KErrNone) { // thread created ok - now start it going + thread.SetPriority(EPriorityNormal); + thread.Resume(); // start it going +// semaphore.Wait(); // wait until it's initialized + thread.Close(); // we're no longer interested in the other thread + } + +// semaphore.Close(); + + return res; +} + diff --git a/platform/uiq2/SimpleServer.h b/platform/uiq2/SimpleServer.h new file mode 100644 index 00000000..b88e4d7e --- /dev/null +++ b/platform/uiq2/SimpleServer.h @@ -0,0 +1,121 @@ +// SimpleServer.h + +#ifndef __SIMPLESERVER_H +#define __SIMPLESERVER_H + +#include + + +TInt StartThread(); + + +// engine states +enum TPicoGameState { + PGS_Running, + PGS_Paused, + PGS_Quit, + PGS_KeyConfig, + PGS_DebugHeap, +}; + +// needed for creating server thread. +const TUint KPicoMaxHeapSize=0x00800000; + +// reasons for server panic +enum TPicoServPanic +{ + EBadRequest, + EBadDescriptor, + EMainSchedulerError, + ESvrCreateServer, + ESvrStartServer, + ECreateTrapCleanup, + ENotImplementedYet, +}; + + +// key config entry (touchpad areas) +struct TPicoAreaConfigEntry { + TRect rect; + //unsigned long actions; +}; + +struct TPicoKeyConfigEntry +{ + unsigned short keyCode; + unsigned char scanCode; + unsigned char flags; // lsb->msb: key_down, pulse_only, ?, ?, ?, ?, not_configurable, disabled + TInt32 handle1; // for CancelCaptureKeyUpAndDowns() + TInt32 handle2; // for CancelCaptureKey() + char *name; +}; + + +//********************************** +//CPicoServServer +//********************************** +//The server class; an active object. +//Contains an instance of RServer; a handle to the kernel server representation which is used +//to receive messages. + +class CPicoServServer : public CServer +{ +public: + enum {EPriority=950}; +public: + static void New(); + virtual CSharableSession *NewSessionL(const TVersion &aVersion) const; + static TInt ThreadFunction(TAny* aStarted); +protected: + CPicoServServer(TInt aPriority); +private: + TInt iActive; +}; + + +//********************************** +//CPicoServSession +//********************************** +//This class represents a session in the server. +//CSession::Client() returns the client thread. +//Functions are provided to respond appropriately to client messages. + + +class CPicoServSession : public CSession +{ +public: + // construct/destruct + CPicoServSession(RThread &aClient, CPicoServServer * aServer); + static CPicoServSession* NewL(RThread &aClient, CPicoServServer * aServer); + //service request + virtual void ServiceL(const RMessage &aMessage); + void DispatchMessageL(const RMessage &aMessage); + + // services available + void loadROM(); + void changeConfig(); + void sendConfig(); + void sendDebug(); + +protected: + // panic the client + void PanicClient(TInt aPanic) const; + // safewrite between client and server + void Write(const TAny* aPtr,const TDesC8& aDes,TInt anOffset=0); +private: + //CPicoServServer *iPicoSvr; + + unsigned char *rom_data; +}; + + + +//********************************** +//global functions +//********************************** + +// function to panic the server +GLREF_C void PanicServer(TPicoServPanic aPanic); +int saveLoadGame(int load, int sram=0); + +#endif // __SIMPLESERVER_H diff --git a/platform/uiq2/_out/PicodriveN.pkg b/platform/uiq2/_out/PicodriveN.pkg new file mode 100644 index 00000000..74bf4fdf --- /dev/null +++ b/platform/uiq2/_out/PicodriveN.pkg @@ -0,0 +1,24 @@ +#{"PicodriveN"},(0x1000C193),0,93,0 + +; +; For the UIQ? +(0x101F617B), 2, 0, 0, {"UIQ20ProductID"} + +; +; PicodriveN (Frontend) +; +"..\..\..\..\..\epoc32\release\armi\urel\PicodriveN.app"-"!:\system\apps\PicodriveN\PicodriveN.app" +"..\..\..\..\..\epoc32\data\z\system\apps\PicodriveN\PicodriveN.rsc"-"!:\system\apps\PicodriveN\PicodriveN.rsc" +"..\..\..\..\..\epoc32\data\z\system\apps\PicodriveN\PicodriveN.aif"-"!:\system\apps\PicodriveN\PicodriveN.aif" +"..\audio\audio_mediaserver.dll"-"!:\system\apps\PicodriveN\audio_mediaserver.dll" +"..\audio\audio_motorola.dll"-"!:\system\apps\PicodriveN\audio_motorola.dll" + +; +; Picosmall +; +"..\PICOSMALL.EXE"-"!:\system\apps\PicodriveN\PICOSMALL.EXE" + +; +; Text to show during installation, not copied to destination +; +".\install.txt"-"!:\system\apps\PicodriveN\install.txt",FILETEXT diff --git a/platform/uiq2/_out/install.txt b/platform/uiq2/_out/install.txt new file mode 100644 index 00000000..e646d049 --- /dev/null +++ b/platform/uiq2/_out/install.txt @@ -0,0 +1,16 @@ +Be sure to configure keys before loading your first ROM, because there is no default config. You need to configure 'pause emu' function to exit game. + +Key configuration tutorial: +http://notaz.atspace.com/pico_tut/ + +You can also hold power button to exit (PXXX only). +(Motorola users, try the 'end' button). + +Some quick sound related notes: +* You must use auto frameskip or you will get stuttering sound. +* Sound needs a lot of CPU power, so it is best to use "fit 0" or "fit 180" display modes and to exit all other apps. +* if you change sound settings AFTER loading a ROM, you may need to reset game to get sound (this depends on a ROM itself). + +Enabling Z80 in sound settings will improve compatibility (you don't have to enable anything else, only Z80), because some games need it to run. But it slows emulation down, so turn it off if the game doesn't need it. + +See readme for more details. diff --git a/platform/uiq2/_out/readme.txt b/platform/uiq2/_out/readme.txt new file mode 100644 index 00000000..ea5e6e43 --- /dev/null +++ b/platform/uiq2/_out/readme.txt @@ -0,0 +1,347 @@ + +About +----- + +PicodriveN is another port of PicoDrive, Dave's Megadrive / Genesis +emulator for Pocket PC. This version is based on PicoDrive 0.030 and is +made for Symbian UIQ devices. It is alternative version to another port by +AnotherGuest / Someone and is not based on it (so it has a little +different name). It also has full sound support (starting +from version 0.70) . + + +Features +-------- + +* Good compatibility (> 90%) +* Improved Cyclone 68000 core. +* Zipped ROMs and savestates. +* SRAM support, including serial SRAM. +* Game screen rotation with many render modes (like 'centered' and 'fit'). +* Selectable frameskip. +* Configurable keys and touchpad. +* Flip-closed mode for SE phones. +* Full sound support. + + +Problems / limitations +---------------------- + +* 32x, Sega CD, SVP are not emulated. +* Various VDP quirks (window bug, scroll size 2, etc.) are not emulated, + as very few games use this. +* Some games don't work or have glitches because of inaccurate sync. + + +Configuration +------------- + +1. Keys: + +If it looks confusing to you, check this tutorial first: +http://notaz.atspace.com/pico_tut/ + +There are no default settings. +When you start key configuration mode, black screen with dark-red squares will +appear. Also there will be little 'control' on the right with the function +name in it, and arrows on the corners of it. You can tap on these corners to +select a function. You can also tap on these squares to bind that function to +them. This way you can associate touchpad areas with game-controls or functions. +I also made a small square in every corner of the screen to be used as a virtual +button for some function, like save state. You can bind it as you like. To +bind phone buttons, simply select the function you need, and press a button +you want. To unbind any key or touchpad area, simply push or tap it again. +To configure flip-closed mode, enter configuration mode and close flip. + +When finished, select 'done' and press any key. You can also hold 'Power' +button for a while to exit (seems to work on PXXX only). + +You need to bind 'pause emu' function to be able exit game when ROM is loaded. +You can also exit game by holding 'power' button (possibly 'end' for motorola +users (?)). + +2. Main Settings: + +Here you can set the orientation of screen and the drawing mode. The "fit" +option will scale the image so it fully fits in the screen, but some detail +will be lost. "center" displays the game at the center of the screen, but +non-fitting parts are not visible then (better for RPG games with lots of +text, which becomes unreadable in 'fit' mode). "fit2" was meant for Pxxx FC +gaming and will always use 208x146 for P800 and 208x208 for all other phones. + +"Fast renderer" enables faster rendering method, but it works only with some +games (some other have serious glitches or even hang). + +"Accurate timing" is needed for some games to run (like Red Zone). It should +be kept off for all other games, because it slows emulation down. Some games +also need this option for proper sound, so enable this if game has any +glitches. + +"Accurate sprites" fixes sprite priority problems, for example if game +character is in front of or behind some object it should not be, this option +should fix it. This option does not work in "Fast renderer" mode. + +"Show FPS" shows game frames per second in format XX/YY, where XX is the +number of frames shown per previous second, and YY is the number of frames +emulated, but not necessarily shown. By calculating YY-XX you get the number +of skipped frames per second. + +3. Sound settings: + +Sound emulation is very picky on CPU power (in most cases sound alone uses +more CPU power than everything else altogether), but it is still possible to +play some games. When using sound, the recommended display modes are "fit 0" +and "fit 180", because these are the fastest ones. Also try "Alternative +renderer", but it might cause graphical glitches. You must use auto frameskip +when using sound, or else you will get stuttering sound. Also, it is +recommended to exit all other non-vital apps (you can use SMan for this), +disable bluetooth and any other devices your phone may have. I also noticed +that simply connecting the phone battery charger strangely slows everything +down. + +"Enable sound" tries to enable sound output on your device, but that alone is +not enough to get sound. You need to enable the sound chips below: +"Z80" is secondary CPU in genesis and is mostly used to control the other 2 +sound chips. So if you disable Z80, sound will be lost in most games, with +some exceptions like Sonic1. It is possible to use Z80 for other things, +some games do that and Z80 must be enabled to run them at all. +"YM2612" is a fairly complex Frequency Modulation (FM) sound synthesis chip. +It was the main sound output device in genesis and is horrible CPU hog when +is tried to be emulated in software. Disabling it gives large speed +improvement, but most of the sound is lost. +"SN76496" is programmable sound generator (PSG) chip, used for various sound +effects and music elements. +The lowest setting is audio quality setting, which should be left set to +"8000Hz mono", because other choces slow everything down terribly and +are left for testing and possibly for use in other ports to faster future +devices with faster CPUs. + +Note: if you change sound settings AFTER loading a ROM, you may need to reset +game to get sound. This is because most games initialize sound chips on +startup, and this data is lost when sound chips are being enabled/disabled. + +4. Misc: + +"6 button pad" will enable 6 button gamepad emulation and will add additional +X, Y, Z and MODE actions to key configuration. +Note: if you enable this, games may detect that and use different button +configuration, for example A ("high punch") will change to "low punch" in +Mortal Kombat and you will need to bind X for "high punch". + +"gzip save states" enables gzip (similar to ordinary zip, but a little +different) compression on your save states to save space. The compression +ratio is 50-90%, so it's worth to enable this. + +"Use SRAM saves" option enables emulation of batery-backed save RAM some game +cartridges had. RPG games used it alot, but there were some others too, like +Sonic 3. If this is enabled, .srm files are generated when you exit +the emulator or load another ROM. Format is compatible with other popular +emulators (like Gens and Fusion). + + +5. Frameskip: + +"Auto" option tries to run the game in it's original speed by skipping next + frame if the previous was rendered too slow. +"0" displays every frame, thus game runs very slow. +"1" skips every other frame. Use this for a game which is smoother, but a bit + too slow (actually depends on display mode you use). +"2" also makes the game smoother, but it will be too fast in most areas. +"4","8" is way too fast and is useful for skiping intros, etc. + + + +Credits +------- + +This emulator uses code from these people/projects: + +Dave +Cyclone 68000 core, Pico emulation library +Homepage: http://www.finalburn.com/ +E-mail: david(atsymbol)finalburn.com + +notaz +UIQ port, Cyclone 68000 hacks, some additional coding (see changelog). +Homepage: http://notaz.atspace.com/ +E-mail: notasas(atsymbol)gmail.com + +Reesy & FluBBa +DrZ80, the Z80 emulator written in ARM assembly. +Homepage: http://reesy.gp32x.de/ +E-mail: drsms_reesy(atsymbol)yahoo.co.uk + +Tatsuyuki Satoh, Jarek Burczynski, MultiArcadeMachineEmulator development +software implementation of Yamaha FM sound generator + +MultiArcadeMachineEmulator (MAME) development +Texas Instruments SN76489 / SN76496 programmable tone /noise generator +Homepage: http://www.mame.net/ + + +Additional thanks +----------------- + +* Peter van Sebille for ECompXL and his various open-source Symbian projects + to learn from. +* Steve Fischer for his open-source Motorola projects. +* Charles MacDonald (http://cgfm2.emuviews.com/) for old but still very useful + info about genesis hardware. +* Stéphane Dallongeville for creating Gens and making it open-source. +* Steve Snake for all that he has done for Genesis emulation scene. +* Bart Trzynadlowski for his SSFII and 68000 docs. +* Haze for his research (http://haze.mameworld.info). +* The development team behind "Symbian GCC Improvement Project" + (http://www.inf.u-szeged.hu/symbian-gcc/) for their updated compile tools. +* Mark and Jean-loup for zlib library. +* Reesy for also finding some Cyclone bugs. +* Inder for the icons. + + +Changelog +--------- +0.94 + * Improved interrupt timing, Mazin Saga and Burning Force now works. + * Rewritten renderer code to better suit gp2x, should be faster on other + ports too. + + Added support for banking used by 12-in-1 and 4-in-1 ROMs (thanks Haze). + + Added some protection device faking, used by some unlicensed games like + Super Bubble Bobble, King of Fighters, Elf Wor, ... + + Added primitive Virtua Racing SVP faking, so menus can be seen now. + +0.93 + * Fixed a problem with P900/P910 key configuration in FC mode. + * Improved shadow/hilight mode emulation. Still not perfect, but should be + enough for most games. + + Save state slots added. + + Region selector added. + +0.92 + VDP changes: + * VDP emulation is now more accurate (fixes flickering in Chase HQ II, + Super Hang-On and some other problems in other games). + * HV counter emulation is now much more accurate. Fixes the Asterix games, + line in Road Rash 3, etc. + * Minnor sprite and layer scroll masking bugs fixed. + + Added partial interlace mode renderer (Sonic 2 vs mode) + * Fixed a crash in both renderers when certain size window layers were used. + + Added emulation of shadow/hilight operator sprites. Other shadow/hilight + effects are still unemulated. + + Sprite emulation is more accurate, sprite limit is emulated. + + Added "accurate sprites" option, which always draws sprites in correct + order and emulates sprite collision bit, but is significantly slower. + + Emulation changes: + * Improved interrupt handling, added deferred interrupt emulation + (Lemmings, etc). + + Added serial EEPROM SRAM support (Wonder Boy in Monster World, + Megaman - The Wily Wars and many EA sports games like NBA Jam). + + Implemented ROM banking for Super Street Fighter II - The New Challengers + * Updated to the latest version of DrZ80 core, integrated memory handlers + in it for better performance. A noticeable performance increase, but save + states may not work from the previous version (you can only use them with + sound disabled in that case). + + SRAM word read handler was using incorrect byte order, fixed. + + Changes in Cyclone 0.0086: + + Added missing CHK opcode handler (used by SeaQuest DSV). + + Added missing TAS opcode handler (Gargoyles,Bubba N Stix,...). As in real genesis, + memory write-back phase is ignored (but can be enabled in config.h if needed). + + Added missing NBCD and TRAPV opcode handlers. + + Added missing addressing mode for CMP/EOR. + + Added some minor optimizations. + - Removed 216 handlers for 2927 opcodes which were generated for invalid addressing modes. + + Fixed flags for ASL, NEG, NEGX, DIVU, ADDX, SUBX, ROXR. + + Bugs fixed in MOVEP, LINK, ADDQ, DIVS handlers. + * Undocumented flags for CHK, ABCD, SBCD and NBCD are now emulated the same way as in Musashi. + + Added Uninitialized Interrupt emulation. + + Altered timing for about half of opcodes to match Musashi's. + +0.80 + * Nearly all VDP code was rewritten in ARM asm. Gives ~10-25% performance + increase (depends on game). + * Optimized 32-column renderer not to render tiles offscreen, games which + use 32-column display (like Shining Force) run ~50% faster. + + Added new "Alternative renderer", which gives another ~30-45% performance + increase (in addition to mentioned above), but works only with some games, + because it is missing some features (it uses tile-based renderering + instead of default line-based and disables H-ints). + + Added "fit2" display mode for all FC gamers. It always uses 208x146 for + P800 and 208x208 for all other phones. + + Added volume control for Motorolas (experimental). + + VDP changes: + + Added support for vertical window (used by Vapor Trail, Mercs, GRIND + Stormer and others). + + Added sprite masking (hiding), adds some speed. + + Added preliminary H counter emulation. Comix Zone and Sonic 3D Blast + special stage are now playable. + + Added column based vertical scrolling (Gunstar Heroes battleship level, + Sonic and Knuckles lava boss, etc). + + Emulation changes: + + Re-added and improved Z80 faking when Z80 is disabled. Many games now can + be played without enabling Z80 (Lost Vikings, Syndicate, etc), but some + still need it (International Superstar Soccer Deluxe). + * Improved ym2612 timers, Outrun music plays at correct speed, voices in + Earthworm Jim play better, more games play sound. + * I/O registers now remember their values (needed for Pirates! Gold) + + Added support for 6 button pad. + + Changes in Cyclone 0.0083wip: + + Added missing CHK opcode (used by SeaQuest DSV). + + Added missing TAS opcode (Gargoyles). As in real genesis, write-back phase + is ignored (but is enabled for other systems). + + Backported stuff from Snes9x: + * Fixed Pxxx jog up/down which were not working in game. + + Added an option to gzip save states to save space. + + The emulator now pauses whenever it is loosing focus, so it will now pause + when alarm/ponecall/battery low/... windows come up. + - Removed 'pause on phonecall' feature, as it is no longer needed. + + Video fix for asian A1000s. + +0.70 + * Started using tools from "Symbian GCC Improvement Project", which give + considerable speed increase (~4fps in "center 90" mode). + * Rewrote some drawing routines in ARM assembly (gives ~6 more fps in + "center 90" mode). + * Minor improvement to 0 and 180 "fit" modes. Now they look slightly better + and are faster. + * Minor stability improvements (emulator is less likely to crash). + + Added some background for OSD text for better readability. + + Added Pal/NTSC detection. This is needed for proper sound speed. + + Implemented Reesy's DrZ80 Z80 emu. Made some changes to it with hope to make + it faster. + + Implemented ym2612 emu from the MAME project. Runs well but sometimes sounds + a bit weird. Could be a little faster, so made some changes too. + + Implemented SN76489 emu from the MAME project. + + Added two separate sound output methods (mediaserver and cmaudiofb) with + autodetection (needs testing). + * Fixed VDP DMA fill emulation (as described in Charles MacDonald's docs), + fixes Contra and some other games. + +0.301 + Launcher: + * Launcher now starts emulation process from current directory, + not from hardcoded paths. + * Improved 'pause on call' feature, should hopefully work with Motorola phones. + +0.30 + Initial release. + + +Disclaimer +---------- + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/platform/uiq2/audio.h b/platform/uiq2/audio.h new file mode 100644 index 00000000..0b1ae38f --- /dev/null +++ b/platform/uiq2/audio.h @@ -0,0 +1,24 @@ +// audio interface, used in picodriveN + +#ifndef __AUDIO_H +#define __AUDIO_H + +#include + + +class IGameAudio : public CBase +{ +public: + virtual TInt16 *NextFrameL() = 0; + virtual TInt16 *DupeFrameL(TInt &aUnderflowed) = 0; + virtual TInt16 *ResumeL() = 0; + virtual void Pause() = 0; + virtual void ChangeVolume(TInt aUp) = 0; // for Motorolas (experimental) +}; + + +// our audio object maker type +typedef IGameAudio *(*_gameAudioNew)(TInt aRate, TBool aStereo, TInt aPcmFrames, TInt aBufferedFrames); + + +#endif /* __AUDIO_H */ diff --git a/platform/uiq2/audio/AUDIO_MEDIASERVER.DLL b/platform/uiq2/audio/AUDIO_MEDIASERVER.DLL new file mode 100644 index 00000000..38172c48 Binary files /dev/null and b/platform/uiq2/audio/AUDIO_MEDIASERVER.DLL differ diff --git a/platform/uiq2/audio/AUDIO_MOTOROLA.DLL b/platform/uiq2/audio/AUDIO_MOTOROLA.DLL new file mode 100644 index 00000000..c510a228 Binary files /dev/null and b/platform/uiq2/audio/AUDIO_MOTOROLA.DLL differ diff --git a/platform/uiq2/audio/mediaserver/AUDIO_MEDIASERVER.ARMI b/platform/uiq2/audio/mediaserver/AUDIO_MEDIASERVER.ARMI new file mode 100644 index 00000000..ab9cb647 --- /dev/null +++ b/platform/uiq2/audio/mediaserver/AUDIO_MEDIASERVER.ARMI @@ -0,0 +1,402 @@ + +# CWD \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\ +# MMPFile \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\AUDIO_MEDIASERVER.MMP +# Target AUDIO_MEDIASERVER.DLL +# TargetType DLL +# BasicTargetType DLL +# MakefileType GNU + +ERASE = @erase 2>>nul + +# EPOC DEFINITIONS + +EPOCBLD = ..\..\..\..\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\AUDIO_MEDIASERVER\ARMI +EPOCTRG = ..\..\..\..\EPOC32\RELEASE\ARMI +EPOCLIB = ..\..\..\..\EPOC32\RELEASE\ARMI +EPOCLINK = ..\..\..\..\EPOC32\RELEASE\ARMI +EPOCSTATLINK = ..\..\..\..\EPOC32\RELEASE\ARMI +EPOCASSPLINK = ..\..\..\..\EPOC32\RELEASE\MARM +EPOCDATA = \DEV\UIQ21\EPOC32\DATA +EPOCINC = \DEV\UIQ21\EPOC32\INCLUDE +TRGDIR = +DATADIR = Z\SYSTEM\DATA + +EPOCBLDUREL = $(EPOCBLD)\UREL +EPOCTRGUREL = $(EPOCTRG)\UREL +EPOCLIBUREL = $(EPOCLIB)\UREL +EPOCLINKUREL = $(EPOCLINK)\UREL +EPOCSTATLINKUREL = $(EPOCSTATLINK)\UREL +EPOCASSPLINKUREL = $(EPOCASSPLINK)\UREL + +EPOCBLDUDEB = $(EPOCBLD)\UDEB +EPOCTRGUDEB = $(EPOCTRG)\UDEB +EPOCLIBUDEB = $(EPOCLIB)\UREL +EPOCLINKUDEB = $(EPOCLINK)\UREL +EPOCSTATLINKUDEB = $(EPOCSTATLINK)\UDEB +EPOCASSPLINKUDEB = $(EPOCASSPLINK)\UREL + +# EPOC PSEUDOTARGETS + +UREL : MAKEWORKUREL RESOURCEUREL + +UDEB : MAKEWORKUDEB RESOURCEUDEB + +ALL : UREL UDEB + +CLEAN CLEANALL : CLEANBUILD CLEANRELEASE CLEANLIBRARY + + + +WHAT WHATALL : WHATUREL WHATUDEB + +RESOURCE RESOURCEALL : RESOURCEUREL RESOURCEUDEB + +CLEANBUILD CLEANBUILDALL : CLEANBUILDUREL CLEANBUILDUDEB + +CLEANRELEASE CLEANRELEASEALL : CLEANRELEASEUREL CLEANRELEASEUDEB + +MAKEWORK MAKEWORKALL : MAKEWORKUREL MAKEWORKUDEB + +LISTING LISTINGALL : LISTINGUREL LISTINGUDEB + +MAKEWORK : MAKEWORKLIBRARY + +RESOURCEUREL RESOURCEUDEB : GENERIC_RESOURCE + + +# must set both PATH and Path to make it work correctly +Path:=X:\DEV\UIQ21\EPOC32\gcc\bin;$(Path) +PATH:=$(Path) + +INCDIR = -I "." -I "..\.." -I "..\..\..\..\EPOC32\INCLUDE" + +GCCFLAGS=-march=armv4t -mthumb-interwork \ + -pipe -c -nostdinc -Wall -Wno-ctor-dtor-privacy -Wno-unknown-pragmas + +GCCDEFS = -D__SYMBIAN32__ -D__GCC32__ -D__EPOC32__ -D__MARM__ -D__MARM_ARMI__ -D__DLL__ $(USERDEFS) + +GCCUREL = gcc -s -fomit-frame-pointer -O $(GCCFLAGS) -DNDEBUG -D_UNICODE $(GCCDEFS) +GCCUDEB = gcc -g -O $(GCCFLAGS) -D_DEBUG -D_UNICODE $(GCCDEFS) + + +UREL : \ + $(EPOCTRGUREL)\AUDIO_MEDIASERVER.DLL \ + LIBRARY + + +UDEB : \ + $(EPOCTRGUDEB)\AUDIO_MEDIASERVER.DLL \ + LIBRARY + + + +RESOURCEUREL : MAKEWORKUREL +RESOURCEUDEB : MAKEWORKUDEB + +LIBRARY : MAKEWORKLIBRARY $(EPOCLIB)\UREL\AUDIO_MEDIASERVER.LIB \DEV\UIQ21\EPOC32\RELEASE\ARM4\UREL\AUDIO_MEDIASERVER.LIB \DEV\UIQ21\EPOC32\RELEASE\THUMB\UREL\AUDIO_MEDIASERVER.LIB + + +# REAL TARGET - LIBRARY + +$(EPOCLIB)\UREL\AUDIO_MEDIASERVER.LIB : \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\AUDIO_MEDIASERVER.DEF + dlltool -m arm_interwork --output-lib "$(EPOCLIB)\UREL\AUDIO_MEDIASERVER.LIB" \ + --def ".\AUDIO_MEDIASERVER.DEF" \ + --dllname "AUDIO_MEDIASERVER[1000c196].DLL" + +\DEV\UIQ21\EPOC32\RELEASE\ARM4\UREL\AUDIO_MEDIASERVER.LIB : \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\AUDIO_MEDIASERVER.DEF + dlltool -m arm --output-lib "..\..\..\..\EPOC32\RELEASE\ARM4\UREL\AUDIO_MEDIASERVER.LIB" \ + --def ".\AUDIO_MEDIASERVER.DEF" \ + --dllname "AUDIO_MEDIASERVER[1000c196].DLL" + +\DEV\UIQ21\EPOC32\RELEASE\THUMB\UREL\AUDIO_MEDIASERVER.LIB : \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\AUDIO_MEDIASERVER.DEF + dlltool -m thumb --output-lib "..\..\..\..\EPOC32\RELEASE\THUMB\UREL\AUDIO_MEDIASERVER.LIB" \ + --def ".\AUDIO_MEDIASERVER.DEF" \ + --dllname "AUDIO_MEDIASERVER[1000c196].DLL" + + +FREEZE : + perl -S efreeze.pl "\DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\AUDIO_MEDIASERVER.DEF" "$(EPOCBLD)\AUDIO_MEDIASERVER.def" + +CLEANLIBRARY : + -$(ERASE) "$(EPOCLIB)\UREL\AUDIO_MEDIASERVER.LIB" + -$(ERASE) "\DEV\UIQ21\EPOC32\RELEASE\ARM4\UREL\AUDIO_MEDIASERVER.LIB" + -$(ERASE) "\DEV\UIQ21\EPOC32\RELEASE\THUMB\UREL\AUDIO_MEDIASERVER.LIB" + + +GENERIC_RESOURCE : GENERIC_MAKEWORK + +# REAL TARGET - BUILD VARIANT UREL + +WHATUREL : WHATGENERIC + +CLEANUREL : CLEANBUILDUREL CLEANRELEASEUREL + +CLEANBUILDUREL : + @perl -S ermdir.pl "$(EPOCBLDUREL)" + +CLEANRELEASEUREL : CLEANGENERIC + + +UREL_RELEASEABLES1= \ + \DEV\UIQ21\EPOC32\RELEASE\ARM4\UREL\AUDIO_MEDIASERVER.LIB \ + \DEV\UIQ21\EPOC32\RELEASE\ARMI\UREL\AUDIO_MEDIASERVER.DLL \ + \DEV\UIQ21\EPOC32\RELEASE\ARMI\UREL\AUDIO_MEDIASERVER.DLL.MAP \ + \DEV\UIQ21\EPOC32\RELEASE\ARMI\UREL\AUDIO_MEDIASERVER.LIB \ + \DEV\UIQ21\EPOC32\RELEASE\THUMB\UREL\AUDIO_MEDIASERVER.LIB + +WHATUREL: + @echo $(UREL_RELEASEABLES1) + +CLEANRELEASEUREL: + -$(ERASE) $(UREL_RELEASEABLES1) + +LISTINGUREL : MAKEWORKUREL \ + LISTINGURELAUDIO_MEDIASERVER \ + LISTINGURELPOLLEDAS + +LIBSUREL= \ + $(EPOCSTATLINKUREL)\EDLLSTUB.LIB \ + $(EPOCSTATLINKUREL)\EGCC.LIB \ + $(EPOCLINKUREL)\EUSER.LIB \ + $(EPOCLINKUREL)\MEDIACLIENTAUDIOSTREAM.LIB \ + $(EPOCLINKUREL)\MEDIACLIENT.LIB + +$(EPOCTRGUREL)\AUDIO_MEDIASERVER.DLL : $(EPOCBLDUREL)\AUDIO_MEDIASERVER.in \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\AUDIO_MEDIASERVER.DEF $(EPOCSTATLINKUREL)\EDLL.LIB $(LIBSUREL) + dlltool -m arm_interwork --output-def "$(EPOCBLDUREL)\AUDIO_MEDIASERVER.inf" "$(EPOCBLDUREL)\AUDIO_MEDIASERVER.in" + perl -S makedef.pl -Deffile "$(EPOCBLDUREL)\AUDIO_MEDIASERVER.inf" -Frzfile "\DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\AUDIO_MEDIASERVER.DEF" "$(EPOCBLD)\AUDIO_MEDIASERVER.def" + -$(ERASE) "$(EPOCBLDUREL)\AUDIO_MEDIASERVER.inf" + dlltool -m arm_interwork --def "$(EPOCBLD)\AUDIO_MEDIASERVER.def" \ + --output-exp "$(EPOCBLDUREL)\AUDIO_MEDIASERVER.exp" \ + --dllname "AUDIO_MEDIASERVER[1000c196].DLL" + ld -s -e _E32Dll -u _E32Dll "$(EPOCBLDUREL)\AUDIO_MEDIASERVER.exp" --dll \ + --base-file "$(EPOCBLDUREL)\AUDIO_MEDIASERVER.bas" -o "$(EPOCBLDUREL)\AUDIO_MEDIASERVER.DLL" \ + "$(EPOCSTATLINKUREL)\EDLL.LIB" --whole-archive "$(EPOCBLDUREL)\AUDIO_MEDIASERVER.in" \ + --no-whole-archive $(LIBSUREL) $(USERLDFLAGS) + -$(ERASE) "$(EPOCBLDUREL)\AUDIO_MEDIASERVER.exp" + -$(ERASE) "$(EPOCBLDUREL)\AUDIO_MEDIASERVER.DLL" + dlltool -m arm_interwork \ + --def "$(EPOCBLD)\AUDIO_MEDIASERVER.def" \ + --dllname "AUDIO_MEDIASERVER[1000c196].DLL" \ + --base-file "$(EPOCBLDUREL)\AUDIO_MEDIASERVER.bas" \ + --output-exp "$(EPOCBLDUREL)\AUDIO_MEDIASERVER.exp" + -$(ERASE) "$(EPOCBLDUREL)\AUDIO_MEDIASERVER.bas" + ld -s -e _E32Dll -u _E32Dll --dll \ + "$(EPOCBLDUREL)\AUDIO_MEDIASERVER.exp" \ + -Map "$(EPOCTRGUREL)\AUDIO_MEDIASERVER.DLL.map" -o "$(EPOCBLDUREL)\AUDIO_MEDIASERVER.DLL" \ + "$(EPOCSTATLINKUREL)\EDLL.LIB" --whole-archive "$(EPOCBLDUREL)\AUDIO_MEDIASERVER.in" \ + --no-whole-archive $(LIBSUREL) $(USERLDFLAGS) + -$(ERASE) "$(EPOCBLDUREL)\AUDIO_MEDIASERVER.exp" + petran "$(EPOCBLDUREL)\AUDIO_MEDIASERVER.DLL" "$@" \ + -nocall -uid1 0x10000079 -uid2 0x100039ce -uid3 0x1000c196 + -$(ERASE) "$(EPOCBLDUREL)\AUDIO_MEDIASERVER.DLL" + +OBJECTSUREL= \ + $(EPOCBLDUREL)\AUDIO_MEDIASERVER.o \ + $(EPOCBLDUREL)\POLLEDAS.o + +$(EPOCBLDUREL)\AUDIO_MEDIASERVER.in : $(OBJECTSUREL) + if exist "$@" del "$@" + ar cr $@ $^ + + +# REAL TARGET - BUILD VARIANT UDEB + +WHATUDEB : WHATGENERIC + +CLEANUDEB : CLEANBUILDUDEB CLEANRELEASEUDEB + +CLEANBUILDUDEB : + @perl -S ermdir.pl "$(EPOCBLDUDEB)" + +CLEANRELEASEUDEB : CLEANGENERIC + + +UDEB_RELEASEABLES1= \ + \DEV\UIQ21\EPOC32\RELEASE\ARM4\UREL\AUDIO_MEDIASERVER.LIB \ + \DEV\UIQ21\EPOC32\RELEASE\ARMI\UDEB\AUDIO_MEDIASERVER.DLL \ + \DEV\UIQ21\EPOC32\RELEASE\ARMI\UDEB\AUDIO_MEDIASERVER.DLL.MAP \ + \DEV\UIQ21\EPOC32\RELEASE\ARMI\UREL\AUDIO_MEDIASERVER.LIB \ + \DEV\UIQ21\EPOC32\RELEASE\THUMB\UREL\AUDIO_MEDIASERVER.LIB + +WHATUDEB: + @echo $(UDEB_RELEASEABLES1) + +CLEANRELEASEUDEB: + -$(ERASE) $(UDEB_RELEASEABLES1) + +LISTINGUDEB : MAKEWORKUDEB \ + LISTINGUDEBAUDIO_MEDIASERVER \ + LISTINGUDEBPOLLEDAS + +LIBSUDEB= \ + $(EPOCSTATLINKUDEB)\EDLLSTUB.LIB \ + $(EPOCSTATLINKUDEB)\EGCC.LIB \ + $(EPOCLINKUDEB)\EUSER.LIB \ + $(EPOCLINKUDEB)\MEDIACLIENTAUDIOSTREAM.LIB \ + $(EPOCLINKUDEB)\MEDIACLIENT.LIB + +$(EPOCTRGUDEB)\AUDIO_MEDIASERVER.DLL : $(EPOCBLDUDEB)\AUDIO_MEDIASERVER.in \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\AUDIO_MEDIASERVER.DEF $(EPOCSTATLINKUDEB)\EDLL.LIB $(LIBSUDEB) + dlltool -m arm_interwork --output-def "$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.inf" "$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.in" + perl -S makedef.pl -Deffile "$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.inf" -Frzfile "\DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\AUDIO_MEDIASERVER.DEF" "$(EPOCBLD)\AUDIO_MEDIASERVER.def" + -$(ERASE) "$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.inf" + dlltool -m arm_interwork --def "$(EPOCBLD)\AUDIO_MEDIASERVER.def" \ + --output-exp "$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.exp" \ + --dllname "AUDIO_MEDIASERVER[1000c196].DLL" + ld -s -e _E32Dll -u _E32Dll "$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.exp" --dll \ + --base-file "$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.bas" -o "$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.DLL" \ + "$(EPOCSTATLINKUDEB)\EDLL.LIB" --whole-archive "$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.in" \ + --no-whole-archive $(LIBSUDEB) $(USERLDFLAGS) + -$(ERASE) "$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.exp" + -$(ERASE) "$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.DLL" + dlltool -m arm_interwork \ + --def "$(EPOCBLD)\AUDIO_MEDIASERVER.def" \ + --dllname "AUDIO_MEDIASERVER[1000c196].DLL" \ + --base-file "$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.bas" \ + --output-exp "$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.exp" + -$(ERASE) "$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.bas" + ld -e _E32Dll -u _E32Dll --dll \ + "$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.exp" \ + -Map "$(EPOCTRGUDEB)\AUDIO_MEDIASERVER.DLL.map" -o "$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.DLL" \ + "$(EPOCSTATLINKUDEB)\EDLL.LIB" --whole-archive "$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.in" \ + --no-whole-archive $(LIBSUDEB) $(USERLDFLAGS) + -$(ERASE) "$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.exp" + objcopy -X "$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.DLL" "$(EPOCTRGUDEB)\AUDIO_MEDIASERVER.sym" + petran "$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.DLL" "$@" \ + -nocall -uid1 0x10000079 -uid2 0x100039ce -uid3 0x1000c196 + -$(ERASE) "$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.DLL" + +OBJECTSUDEB= \ + $(EPOCBLDUDEB)\AUDIO_MEDIASERVER.o \ + $(EPOCBLDUDEB)\POLLEDAS.o + +$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.in : $(OBJECTSUDEB) + if exist "$@" del "$@" + ar cr $@ $^ + + +# SOURCES + +# Source AUDIO_MEDIASERVER.CPP + +$(EPOCBLDUREL)\AUDIO_MEDIASERVER.lis $(EPOCBLDUREL)\AUDIO_MEDIASERVER.o \ +$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.lis $(EPOCBLDUDEB)\AUDIO_MEDIASERVER.o \ +: \ + \DEV\UIQ21\EPOC32\INCLUDE\E32BASE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32BASE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\E32DEF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32DES16.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32DES8.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32HAL.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32KEYS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32PCCD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32STD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32STD.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\E32SVR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\MDAAUDIOOUTPUTSTREAM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\MDA\CLIENT\BASE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\MDA\CLIENT\BASE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\MDA\CLIENT\CONTROLLER.H \ + \DEV\UIQ21\EPOC32\INCLUDE\MDA\CLIENT\PORT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\MDA\CLIENT\UTILITY.H \ + \DEV\UIQ21\EPOC32\INCLUDE\MDA\COMMON\AUDIO.H \ + \DEV\UIQ21\EPOC32\INCLUDE\MDA\COMMON\AUDIO.HRH \ + \DEV\UIQ21\EPOC32\INCLUDE\MDA\COMMON\AUDIOSTREAM.HRH \ + \DEV\UIQ21\EPOC32\INCLUDE\MDA\COMMON\BASE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\MDA\COMMON\BASE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\MDA\COMMON\BASE.HRH \ + \DEV\UIQ21\EPOC32\INCLUDE\MDA\COMMON\BASE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\MDA\COMMON\CONTROLLER.H \ + \DEV\UIQ21\EPOC32\INCLUDE\MDA\COMMON\CONTROLLER.H \ + \DEV\UIQ21\EPOC32\INCLUDE\MDA\COMMON\CONTROLLER.HRH \ + \DEV\UIQ21\EPOC32\INCLUDE\MDA\COMMON\PORT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\MDA\COMMON\PORT.HRH \ + \DEV\UIQ21\EPOC32\INCLUDE\MDA\COMMON\RESOURCE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\MDA\COMMON\RESOURCE.HRH \ + \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO.H \ + \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\AUDIO_MEDIASERVER.H \ + \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\POLLEDAS.H + +$(EPOCBLDUREL)\AUDIO_MEDIASERVER.o : \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\Audio_mediaserver.cpp + $(GCCUREL) -I "." $(INCDIR) -o $@ ".\Audio_mediaserver.cpp" + +LISTINGURELAUDIO_MEDIASERVER : $(EPOCBLDUREL)\AUDIO_MEDIASERVER.lis + perl -S ecopyfile.pl $? \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\AUDIO_MEDIASERVER.lst.ARMI + +$(EPOCBLDUREL)\AUDIO_MEDIASERVER.lis : \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\Audio_mediaserver.cpp + $(GCCUREL) -Wa,-adln -I "." $(INCDIR) -o nul: ".\Audio_mediaserver.cpp" > $@ + +$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.o : \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\Audio_mediaserver.cpp + $(GCCUDEB) -I "." $(INCDIR) -o $@ ".\Audio_mediaserver.cpp" + +LISTINGUDEBAUDIO_MEDIASERVER : $(EPOCBLDUDEB)\AUDIO_MEDIASERVER.lis + perl -S ecopyfile.pl $? \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\AUDIO_MEDIASERVER.lst.ARMI + +$(EPOCBLDUDEB)\AUDIO_MEDIASERVER.lis : \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\Audio_mediaserver.cpp + $(GCCUDEB) -Wa,-adln -I "." $(INCDIR) -o nul: ".\Audio_mediaserver.cpp" > $@ + + + +# Source POLLEDAS.CPP + +$(EPOCBLDUREL)\POLLEDAS.lis $(EPOCBLDUREL)\POLLEDAS.o \ +$(EPOCBLDUDEB)\POLLEDAS.lis $(EPOCBLDUDEB)\POLLEDAS.o \ +: \ + \DEV\UIQ21\EPOC32\INCLUDE\E32DEF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32DES16.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32DES8.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32STD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32STD.INL \ + \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\POLLEDAS.H + +$(EPOCBLDUREL)\POLLEDAS.o : \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\Polledas.cpp + $(GCCUREL) -I "." $(INCDIR) -o $@ ".\Polledas.cpp" + +LISTINGURELPOLLEDAS : $(EPOCBLDUREL)\POLLEDAS.lis + perl -S ecopyfile.pl $? \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\POLLEDAS.lst.ARMI + +$(EPOCBLDUREL)\POLLEDAS.lis : \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\Polledas.cpp + $(GCCUREL) -Wa,-adln -I "." $(INCDIR) -o nul: ".\Polledas.cpp" > $@ + +$(EPOCBLDUDEB)\POLLEDAS.o : \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\Polledas.cpp + $(GCCUDEB) -I "." $(INCDIR) -o $@ ".\Polledas.cpp" + +LISTINGUDEBPOLLEDAS : $(EPOCBLDUDEB)\POLLEDAS.lis + perl -S ecopyfile.pl $? \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\POLLEDAS.lst.ARMI + +$(EPOCBLDUDEB)\POLLEDAS.lis : \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\Polledas.cpp + $(GCCUDEB) -Wa,-adln -I "." $(INCDIR) -o nul: ".\Polledas.cpp" > $@ + + + +ROMFILE: + @echo file=\DEV\UIQ21\EPOC32\RELEASE\ARMI\##BUILD##\AUDIO_MEDIASERVER.DLL System\Libs\AUDIO_MEDIASERVER.DLL + + +WHATGENERIC CLEANGENERIC : + @rem none + +# Rules to create all necessary directories + +GENERIC_MAKEWORK : \ + \DEV\UIQ21\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\AUDIO_MEDIASERVER\ARMI +MAKEWORKLIBRARY : \ + \DEV\UIQ21\EPOC32\RELEASE\ARM4\UREL \ + \DEV\UIQ21\EPOC32\RELEASE\ARMI\UREL \ + \DEV\UIQ21\EPOC32\RELEASE\THUMB\UREL +MAKEWORKUDEB : \ + \DEV\UIQ21\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\AUDIO_MEDIASERVER\ARMI\UDEB \ + \DEV\UIQ21\EPOC32\RELEASE\ARMI\UDEB +MAKEWORKUREL : \ + \DEV\UIQ21\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\AUDIO_MEDIASERVER\ARMI\UREL \ + \DEV\UIQ21\EPOC32\RELEASE\ARMI\UREL + +\DEV\UIQ21\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\AUDIO_MEDIASERVER\ARMI \ +\DEV\UIQ21\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\AUDIO_MEDIASERVER\ARMI\UDEB \ +\DEV\UIQ21\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MEDIASERVER\AUDIO_MEDIASERVER\ARMI\UREL \ +\DEV\UIQ21\EPOC32\RELEASE\ARM4\UREL \ +\DEV\UIQ21\EPOC32\RELEASE\ARMI\UDEB \ +\DEV\UIQ21\EPOC32\RELEASE\ARMI\UREL \ +\DEV\UIQ21\EPOC32\RELEASE\THUMB\UREL \ +: + perl -S emkdir.pl $@ + diff --git a/platform/uiq2/audio/mediaserver/PolledAS.h b/platform/uiq2/audio/mediaserver/PolledAS.h new file mode 100644 index 00000000..f360c897 --- /dev/null +++ b/platform/uiq2/audio/mediaserver/PolledAS.h @@ -0,0 +1,32 @@ +/******************************************************************* + * + * File: PolledAS.h + * + * Author: Peter van Sebille (peter@yipton.net) + * + * (c) Copyright 2001, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +#ifndef __POLLED_AS_H +#define __POLLED_AS_H + +class CPrivatePolledActiveScheduler; + +class CPolledActiveScheduler : public CBase +{ +public: + ~CPolledActiveScheduler(); + static CPolledActiveScheduler* NewL(); + //static CPolledActiveScheduler* Instance(); + void Schedule(); +protected: + CPolledActiveScheduler(){}; + void ConstructL(); + CPrivatePolledActiveScheduler* iPrivatePolledActiveScheduler; +}; + + +#endif /* __POLLED_AS_H */ + diff --git a/platform/uiq2/audio/mediaserver/audio_mediaserver.cpp b/platform/uiq2/audio/mediaserver/audio_mediaserver.cpp new file mode 100644 index 00000000..6655205b --- /dev/null +++ b/platform/uiq2/audio/mediaserver/audio_mediaserver.cpp @@ -0,0 +1,321 @@ +/******************************************************************* + * + * File: Audio_mediaserver.cpp + * + * Author: Peter van Sebille (peter@yipton.net) + * + * Modified/adapted for picodriveN by notaz, 2006 + * + * (c) Copyright 2006, notaz + * (c) Copyright 2001, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +#include "audio_mediaserver.h" + +//#define __DEBUG_PRINT_SND + +#ifdef __DEBUG_PRINT_SND + #include // RDebug + #define DEBUGPRINT(x...) RDebug::Print(x) +#else + #define DEBUGPRINT(x...) +#endif + + +GLDEF_C TInt E32Dll(TDllReason) +{ + return KErrNone; +} + + +/******************************************* + * + * CGameAudioMS + * + *******************************************/ + +CGameAudioMS::CGameAudioMS(TInt aRate, TBool aStereo, TInt aPcmFrames, TInt aBufferedFrames) +: iRate(aRate), iStereo(aStereo), iBufferedFrames(aBufferedFrames), iPcmFrames(aPcmFrames) +{ +} + + +CGameAudioMS* CGameAudioMS::NewL(TInt aRate, TBool aStereo, TInt aPcmFrames, TInt aBufferedFrames) +{ + DEBUGPRINT(_L("CGameAudioMS::NewL(%i, %i, %i, %i)"),aRate, aStereo, aPcmFrames, aBufferedFrames); + CGameAudioMS* self = new(ELeave) CGameAudioMS(aRate, aStereo, aPcmFrames, aBufferedFrames); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); // self + return self; +} + + +CGameAudioMS::~CGameAudioMS() +{ + DEBUGPRINT(_L("CGameAudioMS::~CGameAudioMS()")); + if(iMdaAudioOutputStream) { + iScheduler->Schedule(); // let it finish it's stuff + iMdaAudioOutputStream->Stop(); + delete iMdaAudioOutputStream; + } + if(iServer) delete iServer; + + for (TInt i=0 ; iDes().FillZ (bytesPerFrame * iBufferedFrames); + } + // because feeding 2 buffers after an underflow is a little too much, but feeding 1 may be not enough, + // prepare this ~50ms empty buffer to additionaly feed after every underflow. + // Another strange thing here: if we try to make and odd-length sound buffer here, + // system then outputs horrible noise! (this happened on 22050 mono and when there + // were no parenthesis around iBufferedFrames / 4. + iSoundBuffers[KSoundBuffers] = HBufC8::NewL(bytesPerFrame * (iBufferedFrames / 4)); + iSoundBuffers[KSoundBuffers]->Des().FillZ (bytesPerFrame * (iBufferedFrames / 4)); + + iCurrentBuffer = 0; + + // here we actually test if we can create and open CMdaAudioOutputStream at all, but really create and use it later. + iMdaAudioOutputStream = CMdaAudioOutputStream::NewL(iListener, iServer); + if(iMdaAudioOutputStream) { + delete iMdaAudioOutputStream; + iMdaAudioOutputStream = 0; + } +} + +/* currently unused +TInt CGameAudioMS::Write(TInt16* aBuffer, TInt aSize) +{ + TInt byteSize = iStereo ? aSize << 2 : aSize << 1; + Mem::Copy(iCurrentPosition, aBuffer, byteSize); + iCurrentPosition += aSize; + + if (++iFrameCount == iBufferedFrames) + { + WriteBlock(); + } + + CPolledActiveScheduler::Instance()->Schedule(); + if(iListener.iUnderflowed) Underflowed(); // oh no, CMdaAudioOutputStream underflowed! + + return aSize; +} +*/ + +// returns a pointer to buffer for next frame, +// to be used when iSoundBuffers are used directly +TInt16 *CGameAudioMS::NextFrameL() +{ + iCurrentPosition += iPcmFrames << (iStereo?1:0); + + if (++iFrameCount == iBufferedFrames) + { + WriteBlockL(); + } + + iScheduler->Schedule(); + + if(iListener.iUnderflowed) { + if(iListener.iUnderflowed > KMaxUnderflows) { + delete iMdaAudioOutputStream; + iMdaAudioOutputStream = 0; + return 0; + } + UnderflowedL(); // not again! + } + + return iCurrentPosition; +} + +TInt16 *CGameAudioMS::DupeFrameL(TInt &aUnderflowed) +{ + TInt shorts = iStereo ? (iPcmFrames << 1) : iPcmFrames; + if(iFrameCount) + Mem::Copy(iCurrentPosition, iCurrentPosition-shorts, shorts<<1); + else { + TInt lastBuffer = iCurrentBuffer; + if(--lastBuffer < 0) lastBuffer = KSoundBuffers - 1; + Mem::Copy(iCurrentPosition, ((TInt16*) (iSoundBuffers[lastBuffer]->Ptr()))+shorts*(iBufferedFrames-1), shorts<<1); + } + iCurrentPosition += shorts; + + if (++iFrameCount == iBufferedFrames) + { + WriteBlockL(); + } + + iScheduler->Schedule(); + + if((aUnderflowed = iListener.iUnderflowed)) { // not again! + if(iListener.iUnderflowed > KMaxUnderflows) { + delete iMdaAudioOutputStream; + iMdaAudioOutputStream = 0; + return 0; + } + UnderflowedL(); // not again! + } + + return iCurrentPosition; +} + +void CGameAudioMS::WriteBlockL() +{ + iScheduler->Schedule(); + // do not write until stream is open + if(!iListener.iIsOpen) WaitForOpenToCompleteL(); + //if(!iListener.iHasCopied) WaitForCopyToCompleteL(); // almost never happens anyway and sometimes even deadlocks? + //iListener.iHasCopied = EFalse; + + + if(!iListener.iUnderflowed) { + // don't write if sound is lagging too much + if(iTime - iMdaAudioOutputStream->Position().Int64() <= TInt64(0, KMaxLag)) { + //RDebug::Print(_L("delta: %i"), iTime.Low() - iMdaAudioOutputStream->Position().Int64().Low()); + iMdaAudioOutputStream->WriteL(*iSoundBuffers[iCurrentBuffer]); + iTime += KBlockTime; + } + } + + iFrameCount = 0; + if (++iCurrentBuffer == KSoundBuffers) + iCurrentBuffer = 0; + iCurrentPosition = (TInt16*) iSoundBuffers[iCurrentBuffer]->Ptr(); +} + +void CGameAudioMS::Pause() +{ + if(!iMdaAudioOutputStream) return; + + iScheduler->Schedule(); // let it finish it's stuff + iMdaAudioOutputStream->Stop(); + delete iMdaAudioOutputStream; + iMdaAudioOutputStream = 0; +} + +// call this before doing any playback! +TInt16 *CGameAudioMS::ResumeL() +{ + DEBUGPRINT(_L("CGameAudioMS::Resume()")); + iScheduler->Schedule(); + + // we act a bit strange here: simulate buffer underflow, which actually starts audio + iListener.iIsOpen = ETrue; + iListener.iUnderflowed = 1; + iFrameCount = 0; + iCurrentPosition = (TInt16*) iSoundBuffers[iCurrentBuffer]->Ptr(); + return iCurrentPosition; +} + +// handles underflow condition +void CGameAudioMS::UnderflowedL() +{ + // recreate the stream + //iMdaAudioOutputStream->Stop(); + if(iMdaAudioOutputStream) delete iMdaAudioOutputStream; + iMdaAudioOutputStream = CMdaAudioOutputStream::NewL(iListener, iServer); + iMdaAudioOutputStream->Open(&iMdaAudioDataSettings); + iListener.iIsOpen = EFalse; // wait for it to open + //iListener.iHasCopied = ETrue; // but don't wait for last copy to complete + // let it open and feed some stuff to make it happy + User::After(0); + TInt lastBuffer = iCurrentBuffer; + if(--lastBuffer < 0) lastBuffer = KSoundBuffers - 1; + iScheduler->Schedule(); + if(!iListener.iIsOpen) WaitForOpenToCompleteL(); + iMdaAudioOutputStream->WriteL(*iSoundBuffers[KSoundBuffers]); // special empty fill-up + iMdaAudioOutputStream->WriteL(*iSoundBuffers[lastBuffer]); + iTime = TInt64(0, KBlockTime/4 + KBlockTime); +} + +/* +void CGameAudioMS::WaitForCopyToCompleteL() +{ + DEBUGPRINT(_L("CGameAudioMS::WaitForCopyToCompleteL")); + while (!iListener.iHasCopied) { + //User::After(0); + iScheduler->Schedule(); + } +} +*/ + +void CGameAudioMS::WaitForOpenToCompleteL() +{ + DEBUGPRINT(_L("CGameAudioMS::WaitForOpenToCompleteL")); + TInt count = 20; // 2 seconds + TInt waitPeriod = 100 * 1000; + + if(!iListener.iIsOpen) { + // it is often enough to do this + User::After(0); + iScheduler->Schedule(); + } + while (!iListener.iIsOpen && --count) + { + User::After(waitPeriod); + iScheduler->Schedule(); + } + if (!iListener.iIsOpen) + User::LeaveIfError(KErrNotSupported); +} + +void CGameAudioMS::ChangeVolume(TInt aUp) +{ + // do nothing + DEBUGPRINT(_L("CGameAudioMS::ChangeVolume(%i)"), aUp); +} + +void TGameAudioEventListener::MaoscOpenComplete(TInt aError) +{ + DEBUGPRINT(_L("CGameAudioMS::MaoscOpenComplete, error=%d"), aError); + + iIsOpen = ETrue; + if(aError) iUnderflowed++; + else iUnderflowed = 0; +} + +void TGameAudioEventListener::MaoscBufferCopied(TInt aError, const TDesC8& aBuffer) +{ + DEBUGPRINT(_L("CGameAudioMS::MaoscBufferCopied, error=%d"), aError); + +// iHasCopied = ETrue; + + if(aError) // shit! + iUnderflowed++; +} + +void TGameAudioEventListener::MaoscPlayComplete(TInt aError) +{ + DEBUGPRINT(_L("CGameAudioMS::MaoscPlayComplete: %i"), aError); + if(aError) + iUnderflowed++; // never happened to me while testing, but just in case +} + diff --git a/platform/uiq2/audio/mediaserver/audio_mediaserver.def b/platform/uiq2/audio/mediaserver/audio_mediaserver.def new file mode 100644 index 00000000..c55290bb --- /dev/null +++ b/platform/uiq2/audio/mediaserver/audio_mediaserver.def @@ -0,0 +1,3 @@ +EXPORTS +; NEW: + NewL__12CGameAudioMSiiii @ 1 NONAME ; static CGameAudioMS* NewL(TInt aRate, TBool aStereo, TInt aPcmFrames, TInt aBufferedFrames); diff --git a/platform/uiq2/audio/mediaserver/audio_mediaserver.h b/platform/uiq2/audio/mediaserver/audio_mediaserver.h new file mode 100644 index 00000000..6937a484 --- /dev/null +++ b/platform/uiq2/audio/mediaserver/audio_mediaserver.h @@ -0,0 +1,87 @@ +/******************************************************************* + * + * File: Audio_mediaserver.h + * + * Author: Peter van Sebille (peter@yipton.net) + * + * Modified/adapted for picodriveN by notaz, 2006 + * + * (c) Copyright 2006, notaz + * (c) Copyright 2001, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +#ifndef __AUDIO_MEDIASERVER_H +#define __AUDIO_MEDIASERVER_H + +#include +#include + +#include "audio.h" +#include "polledas.h" + +const TInt KSoundBuffers = 4; +const TInt KBlockTime = 1000000 / 5; // hardcoded: 5 updates/sec +const TInt KMaxLag = 260000; // max sound lag, lower values increase chanse of underflow +const TInt KMaxUnderflows = 50; // max underflows/API errors we are going allow in a row (to prevent lockups) + + +class TGameAudioEventListener : public MMdaAudioOutputStreamCallback +{ +public: // implements MMdaAudioOutputStreamCallback + void MaoscOpenComplete(TInt aError); + void MaoscBufferCopied(TInt aError, const TDesC8& ); + void MaoscPlayComplete(TInt aError); + + TBool iIsOpen; +// TBool iHasCopied; + TInt iUnderflowed; +}; + + +class CGameAudioMS : public IGameAudio // IGameAudio MUST be specified first! +{ +public: // implements IGameAudio + TInt16 *NextFrameL(); + TInt16 *DupeFrameL(TInt &aUnderflowed); + TInt16 *ResumeL(); + void Pause(); + void ChangeVolume(TInt aUp); + +public: + ~CGameAudioMS(); + CGameAudioMS(TInt aRate, TBool aStereo, TInt aPcmFrames, TInt aBufferedFrames); + void ConstructL(); + EXPORT_C static CGameAudioMS* NewL(TInt aRate, TBool aStereo, TInt aPcmFrames, TInt aBufferedFrames); + +protected: + void WriteBlockL(); + void UnderflowedL(); + +protected: + void WaitForOpenToCompleteL(); +// void WaitForCopyToCompleteL(); + + TInt iRate; + TBool iStereo; + + CMdaAudioOutputStream *iMdaAudioOutputStream; + TMdaAudioDataSettings iMdaAudioDataSettings; + + TGameAudioEventListener iListener; + + CPolledActiveScheduler *iScheduler; + + HBufC8* iSoundBuffers[KSoundBuffers+1]; + TInt iBufferedFrames; + TInt16* iCurrentPosition; + TInt iCurrentBuffer; + TInt iFrameCount; + TInt iPcmFrames; + CMdaServer* iServer; + + TInt64 iTime; +}; + +#endif /* __AUDIO_MEDIASERVER_H */ diff --git a/platform/uiq2/audio/mediaserver/audio_mediaserver.mmp b/platform/uiq2/audio/mediaserver/audio_mediaserver.mmp new file mode 100644 index 00000000..3c3a6dbb --- /dev/null +++ b/platform/uiq2/audio/mediaserver/audio_mediaserver.mmp @@ -0,0 +1,18 @@ +TARGET audio_mediaserver.dll +TARGETTYPE dll +UID 0x100039CE 0x1000C196 + +USERINCLUDE . +USERINCLUDE ..\..\ + +SYSTEMINCLUDE \epoc32\include + +SOURCEPATH . +SOURCE audio_mediaserver.cpp +SOURCE polledas.cpp + +LIBRARY EUSER.LIB mediaclientaudiostream.lib mediaclient.lib + +deffile .\audio_mediaserver.def + +nostrictdef diff --git a/platform/uiq2/audio/mediaserver/polledas.cpp b/platform/uiq2/audio/mediaserver/polledas.cpp new file mode 100644 index 00000000..8650c335 --- /dev/null +++ b/platform/uiq2/audio/mediaserver/polledas.cpp @@ -0,0 +1,213 @@ +/******************************************************************* + * + * File: PolledAS.cpp + * + * Author: Peter van Sebille (peter@yipton.net) + * + * (c) Copyright 2002, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +/* + * Oh Lord, forgive me for I have sinned. + * In their infinite wisdom, Symbian Engineers have decided that + * the Active Scheduler's queue of Active Objects is private + * and no getters are provided... sigh. + * This mere mortal will have to excercise the power of C pre-processor + * once more to circumvent the will of the gods. + */ + + +#include + +// from e32base.h +class CBase + { +public: + IMPORT_C virtual ~CBase(); + inline TAny* operator new(TUint aSize,TAny *aBase) {Mem::FillZ(aBase,aSize);return(aBase);} + IMPORT_C TAny* operator new(TUint aSize); + inline TAny* operator new(TUint aSize, TLeave) {return newL(aSize);} + IMPORT_C TAny* operator new(TUint aSize,TUint anExtraSize); +protected: + IMPORT_C CBase(); +private: + CBase(const CBase&); + CBase& operator=(const CBase&); + IMPORT_C static TAny* newL(TUint aSize); + }; + +class CActive : public CBase + { +public: +enum TPriority + { + EPriorityIdle=-100, + EPriorityLow=-20, + EPriorityStandard=0, + EPriorityUserInput=10, + EPriorityHigh=20, + }; +public: + IMPORT_C ~CActive(); + IMPORT_C void Cancel(); + IMPORT_C void Deque(); + IMPORT_C void SetPriority(TInt aPriority); + inline TBool IsActive() const {return(iActive);} + inline TBool IsAdded() const {return(iLink.iNext!=NULL);} + inline TInt Priority() const {return iLink.iPriority;} +protected: + IMPORT_C CActive(TInt aPriority); + IMPORT_C void SetActive(); +// Pure virtual + virtual void DoCancel() =0; + virtual void RunL() =0; + IMPORT_C virtual TInt RunError(TInt aError); +public: + TRequestStatus iStatus; +private: + TBool iActive; + TPriQueLink iLink; + friend class CActiveScheduler; +// friend class CServer; + friend class CPrivatePolledActiveScheduler; // added + }; + +class CActiveScheduler : public CBase + { +public: + IMPORT_C CActiveScheduler(); + IMPORT_C ~CActiveScheduler(); + IMPORT_C static void Install(CActiveScheduler* aScheduler); + IMPORT_C static CActiveScheduler* Current(); + IMPORT_C static void Add(CActive* anActive); + IMPORT_C static void Start(); + IMPORT_C static void Stop(); + IMPORT_C static TBool RunIfReady(TInt& aError, TInt aMinimumPriority); + IMPORT_C static CActiveScheduler* Replace(CActiveScheduler* aNewActiveScheduler); + IMPORT_C virtual void WaitForAnyRequest(); + IMPORT_C virtual void Error(TInt anError) const; +private: + void DoStart(); + void OwnedStartLoop(TInt& aRunning); + IMPORT_C virtual void OnStarting(); + IMPORT_C virtual void OnStopping(); + IMPORT_C virtual void Reserved_1(); + IMPORT_C virtual void Reserved_2(); + friend class CPrivatePolledActiveScheduler; // added +private: + // private interface used through by CActiveSchedulerWait objects + friend class CActiveSchedulerWait; + static void OwnedStart(CActiveSchedulerWait& aOwner); +protected: + inline TInt Level() const {return(iLevel);} +private: + TInt iLevel; + TPriQue iActiveQ; + }; + +class TCleanupItem; +class CleanupStack + { +public: + IMPORT_C static void PushL(TAny* aPtr); + IMPORT_C static void PushL(CBase* aPtr); + IMPORT_C static void PushL(TCleanupItem anItem); + IMPORT_C static void Pop(); + IMPORT_C static void Pop(TInt aCount); + IMPORT_C static void PopAndDestroy(); + IMPORT_C static void PopAndDestroy(TInt aCount); + IMPORT_C static void Check(TAny* aExpectedItem); + inline static void Pop(TAny* aExpectedItem); + inline static void Pop(TInt aCount, TAny* aLastExpectedItem); + inline static void PopAndDestroy(TAny* aExpectedItem); + inline static void PopAndDestroy(TInt aCount, TAny* aLastExpectedItem); + }; + + +/* + * This will declare CPrivatePolledActiveScheduler as a friend + * of all classes that define a friend. CPrivatePolledActiveScheduler needs to + * be a friend of CActive + */ +//#define friend friend class CPrivatePolledActiveScheduler; friend + + +/* + * This will change the: + * void DoStart(); + * method in CActiveScheduler to: + * void DoStart(); friend class CPrivatePolledActiveScheduler; + * We need this to access the private datamembers in CActiveScheduler. + */ +//#define DoStart() DoStart(); friend class CPrivatePolledActiveScheduler; +//#include +#include "PolledAS.h" + + +class CPrivatePolledActiveScheduler : public CActiveScheduler +{ +public: + void Schedule(); +}; + + + +void CPrivatePolledActiveScheduler::Schedule() +{ + TDblQueIter q(iActiveQ); + q.SetToFirst(); + FOREVER + { + CActive *pR=q++; + if (pR) + { + if (pR->IsActive() && pR->iStatus!=KRequestPending) + { + pR->iActive=EFalse; + TRAPD(r,pR->RunL()); + break; + } + } + else + break; + } +} + + +CPolledActiveScheduler::~CPolledActiveScheduler() +{ + delete iPrivatePolledActiveScheduler; +} + +//static CPolledActiveScheduler* sPolledActiveScheduler = NULL; +CPolledActiveScheduler* CPolledActiveScheduler::NewL() +{ + //sPolledActiveScheduler = + CPolledActiveScheduler* self = new(ELeave)CPolledActiveScheduler; + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return self; +} + +void CPolledActiveScheduler::ConstructL() +{ + iPrivatePolledActiveScheduler = new(ELeave) CPrivatePolledActiveScheduler; + iPrivatePolledActiveScheduler->Install(iPrivatePolledActiveScheduler); +} + + +void CPolledActiveScheduler::Schedule() +{ + iPrivatePolledActiveScheduler->Schedule(); +} + +/* +CPolledActiveScheduler* CPolledActiveScheduler::Instance() +{ +// return (CPolledActiveScheduler*) CActiveScheduler::Current(); + return sPolledActiveScheduler; +} +*/ diff --git a/platform/uiq2/audio/mediaserver/retr.cmd b/platform/uiq2/audio/mediaserver/retr.cmd new file mode 100644 index 00000000..f8e35742 --- /dev/null +++ b/platform/uiq2/audio/mediaserver/retr.cmd @@ -0,0 +1,2 @@ +copy %EPOCROOT%\epoc32\release\armi\urel\audio_mediaserver.dll ..\ +..\..\..\qconsole-1.52\qtty\release\qtty --qc-addr P800 --qc-channel 5 --user qconsole --pass server --cmds "put d:\system\apps\picodriven\audio_mediaserver.dll ..\audio_mediaserver.dll" exit diff --git a/platform/uiq2/audio/mediaserver/retr2.cmd b/platform/uiq2/audio/mediaserver/retr2.cmd new file mode 100644 index 00000000..766733bf --- /dev/null +++ b/platform/uiq2/audio/mediaserver/retr2.cmd @@ -0,0 +1 @@ +copy %EPOCROOT%\epoc32\release\armi\urel\audio_mediaserver.dll ..\ diff --git a/platform/uiq2/audio/motorola/AUDIO_MOTOROLA.ARMI b/platform/uiq2/audio/motorola/AUDIO_MOTOROLA.ARMI new file mode 100644 index 00000000..3180600f --- /dev/null +++ b/platform/uiq2/audio/motorola/AUDIO_MOTOROLA.ARMI @@ -0,0 +1,418 @@ + +# CWD \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\ +# MMPFile \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\AUDIO_MOTOROLA.MMP +# Target AUDIO_MOTOROLA.DLL +# TargetType DLL +# BasicTargetType DLL +# MakefileType GNU + +ERASE = @erase 2>>nul + +# EPOC DEFINITIONS + +EPOCBLD = ..\..\..\..\..\A925SDK\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\AUDIO_MOTOROLA\ARMI +EPOCTRG = ..\..\..\..\..\A925SDK\EPOC32\RELEASE\ARMI +EPOCLIB = ..\..\..\..\..\A925SDK\EPOC32\RELEASE\ARMI +EPOCLINK = ..\..\..\..\..\A925SDK\EPOC32\RELEASE\ARMI +EPOCSTATLINK = ..\..\..\..\..\A925SDK\EPOC32\RELEASE\ARMI +EPOCASSPLINK = ..\..\..\..\..\A925SDK\EPOC32\RELEASE\MARM +EPOCDATA = \DEV\A925SDK\EPOC32\DATA +EPOCINC = \DEV\A925SDK\EPOC32\INCLUDE +TRGDIR = +DATADIR = Z\SYSTEM\DATA + +EPOCBLDUREL = $(EPOCBLD)\UREL +EPOCTRGUREL = $(EPOCTRG)\UREL +EPOCLIBUREL = $(EPOCLIB)\UREL +EPOCLINKUREL = $(EPOCLINK)\UREL +EPOCSTATLINKUREL = $(EPOCSTATLINK)\UREL +EPOCASSPLINKUREL = $(EPOCASSPLINK)\UREL + +EPOCBLDUDEB = $(EPOCBLD)\UDEB +EPOCTRGUDEB = $(EPOCTRG)\UDEB +EPOCLIBUDEB = $(EPOCLIB)\UREL +EPOCLINKUDEB = $(EPOCLINK)\UREL +EPOCSTATLINKUDEB = $(EPOCSTATLINK)\UDEB +EPOCASSPLINKUDEB = $(EPOCASSPLINK)\UREL + +# EPOC PSEUDOTARGETS + +UREL : MAKEWORKUREL RESOURCEUREL + +UDEB : MAKEWORKUDEB RESOURCEUDEB + +ALL : UREL UDEB + +CLEAN CLEANALL : CLEANBUILD CLEANRELEASE CLEANLIBRARY + + + +WHAT WHATALL : WHATUREL WHATUDEB + +RESOURCE RESOURCEALL : RESOURCEUREL RESOURCEUDEB + +CLEANBUILD CLEANBUILDALL : CLEANBUILDUREL CLEANBUILDUDEB + +CLEANRELEASE CLEANRELEASEALL : CLEANRELEASEUREL CLEANRELEASEUDEB + +MAKEWORK MAKEWORKALL : MAKEWORKUREL MAKEWORKUDEB + +LISTING LISTINGALL : LISTINGUREL LISTINGUDEB + +MAKEWORK : MAKEWORKLIBRARY + +RESOURCEUREL RESOURCEUDEB : GENERIC_RESOURCE + + +# must set both PATH and Path to make it work correctly +Path:=X:\DEV\A925SDK\EPOC32\gcc\bin;$(Path) +PATH:=$(Path) + +INCDIR = -I "." -I "..\.." -I "..\..\..\..\..\A925SDK\EPOC32\INCLUDE" + +GCCFLAGS=-march=armv4t -mthumb-interwork \ + -pipe -c -nostdinc -Wall -Wno-ctor-dtor-privacy -Wno-unknown-pragmas + +GCCDEFS = -D__SYMBIAN32__ -D__GCC32__ -D__EPOC32__ -D__MARM__ -D__MARM_ARMI__ -D__DLL__ $(USERDEFS) + +GCCUREL = gcc -s -fomit-frame-pointer -O $(GCCFLAGS) -DNDEBUG -D_UNICODE $(GCCDEFS) +GCCUDEB = gcc -g -O $(GCCFLAGS) -D_DEBUG -D_UNICODE $(GCCDEFS) + + +UREL : \ + $(EPOCTRGUREL)\AUDIO_MOTOROLA.DLL \ + LIBRARY + + +UDEB : \ + $(EPOCTRGUDEB)\AUDIO_MOTOROLA.DLL \ + LIBRARY + + + +RESOURCEUREL : MAKEWORKUREL +RESOURCEUDEB : MAKEWORKUDEB + +LIBRARY : MAKEWORKLIBRARY $(EPOCLIB)\UREL\AUDIO_MOTOROLA.LIB \DEV\A925SDK\EPOC32\RELEASE\ARM4\UREL\AUDIO_MOTOROLA.LIB \DEV\A925SDK\EPOC32\RELEASE\THUMB\UREL\AUDIO_MOTOROLA.LIB + + +# REAL TARGET - LIBRARY + +$(EPOCLIB)\UREL\AUDIO_MOTOROLA.LIB : \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\AUDIO_MOTOROLA.DEF + @echo AUDIO_MOTOROLA.LIB: dlltool + @dlltool -m arm_interwork --output-lib "$(EPOCLIB)\UREL\AUDIO_MOTOROLA.LIB" \ + --def ".\AUDIO_MOTOROLA.DEF" \ + --dllname "AUDIO_MOTOROLA[1000c197].DLL" + +\DEV\A925SDK\EPOC32\RELEASE\ARM4\UREL\AUDIO_MOTOROLA.LIB : \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\AUDIO_MOTOROLA.DEF + @echo AUDIO_MOTOROLA.LIB: dlltool + @dlltool -m arm --output-lib "..\..\..\..\..\A925SDK\EPOC32\RELEASE\ARM4\UREL\AUDIO_MOTOROLA.LIB" \ + --def ".\AUDIO_MOTOROLA.DEF" \ + --dllname "AUDIO_MOTOROLA[1000c197].DLL" + +\DEV\A925SDK\EPOC32\RELEASE\THUMB\UREL\AUDIO_MOTOROLA.LIB : \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\AUDIO_MOTOROLA.DEF + @echo AUDIO_MOTOROLA.LIB: dlltool + @dlltool -m thumb --output-lib "..\..\..\..\..\A925SDK\EPOC32\RELEASE\THUMB\UREL\AUDIO_MOTOROLA.LIB" \ + --def ".\AUDIO_MOTOROLA.DEF" \ + --dllname "AUDIO_MOTOROLA[1000c197].DLL" + + +FREEZE : + perl -S efreeze.pl "\DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\AUDIO_MOTOROLA.DEF" "$(EPOCBLD)\AUDIO_MOTOROLA.def" + +CLEANLIBRARY : + -$(ERASE) "$(EPOCLIB)\UREL\AUDIO_MOTOROLA.LIB" + -$(ERASE) "\DEV\A925SDK\EPOC32\RELEASE\ARM4\UREL\AUDIO_MOTOROLA.LIB" + -$(ERASE) "\DEV\A925SDK\EPOC32\RELEASE\THUMB\UREL\AUDIO_MOTOROLA.LIB" + + +GENERIC_RESOURCE : GENERIC_MAKEWORK + +# REAL TARGET - BUILD VARIANT UREL + +WHATUREL : WHATGENERIC + +CLEANUREL : CLEANBUILDUREL CLEANRELEASEUREL + +CLEANBUILDUREL : + @perl -S ermdir.pl "$(EPOCBLDUREL)" + +CLEANRELEASEUREL : CLEANGENERIC + + +UREL_RELEASEABLES1= \ + \DEV\A925SDK\EPOC32\RELEASE\ARM4\UREL\AUDIO_MOTOROLA.LIB \ + \DEV\A925SDK\EPOC32\RELEASE\ARMI\UREL\AUDIO_MOTOROLA.DLL \ + \DEV\A925SDK\EPOC32\RELEASE\ARMI\UREL\AUDIO_MOTOROLA.DLL.MAP \ + \DEV\A925SDK\EPOC32\RELEASE\ARMI\UREL\AUDIO_MOTOROLA.LIB \ + \DEV\A925SDK\EPOC32\RELEASE\THUMB\UREL\AUDIO_MOTOROLA.LIB + +WHATUREL: + @echo $(UREL_RELEASEABLES1) + +CLEANRELEASEUREL: + -$(ERASE) $(UREL_RELEASEABLES1) + +LISTINGUREL : MAKEWORKUREL \ + LISTINGURELAUDIO_MOTOROLA \ + LISTINGURELPOLLEDAS + +LIBSUREL= \ + $(EPOCSTATLINKUREL)\EDLLSTUB.LIB \ + $(EPOCSTATLINKUREL)\EGCC.LIB \ + $(EPOCLINKUREL)\EUSER.LIB \ + $(EPOCLINKUREL)\MAUDIOFB.LIB \ + $(EPOCLINKUREL)\MAUDIOAC.LIB + +$(EPOCTRGUREL)\AUDIO_MOTOROLA.DLL : $(EPOCBLDUREL)\AUDIO_MOTOROLA.in \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\AUDIO_MOTOROLA.DEF $(EPOCSTATLINKUREL)\EDLL.LIB $(LIBSUREL) + @echo AUDIO_MOTOROLA.DLL: dlltool + @dlltool -m arm_interwork --output-def "$(EPOCBLDUREL)\AUDIO_MOTOROLA.inf" "$(EPOCBLDUREL)\AUDIO_MOTOROLA.in" + @echo AUDIO_MOTOROLA.DLL: perl -S makedef.pl + @perl -S makedef.pl -Deffile "$(EPOCBLDUREL)\AUDIO_MOTOROLA.inf" -Frzfile "\DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\AUDIO_MOTOROLA.DEF" "$(EPOCBLD)\AUDIO_MOTOROLA.def" + -$(ERASE) "$(EPOCBLDUREL)\AUDIO_MOTOROLA.inf" + @echo AUDIO_MOTOROLA.DLL: dlltool + @dlltool -m arm_interwork --def "$(EPOCBLD)\AUDIO_MOTOROLA.def" \ + --output-exp "$(EPOCBLDUREL)\AUDIO_MOTOROLA.exp" \ + --dllname "AUDIO_MOTOROLA[1000c197].DLL" + @echo AUDIO_MOTOROLA.DLL: ld + @ld -s -e _E32Dll -u _E32Dll "$(EPOCBLDUREL)\AUDIO_MOTOROLA.exp" --dll \ + --base-file "$(EPOCBLDUREL)\AUDIO_MOTOROLA.bas" -o "$(EPOCBLDUREL)\AUDIO_MOTOROLA.DLL" \ + "$(EPOCSTATLINKUREL)\EDLL.LIB" --whole-archive "$(EPOCBLDUREL)\AUDIO_MOTOROLA.in" \ + --no-whole-archive $(LIBSUREL) $(USERLDFLAGS) + -$(ERASE) "$(EPOCBLDUREL)\AUDIO_MOTOROLA.exp" + -$(ERASE) "$(EPOCBLDUREL)\AUDIO_MOTOROLA.DLL" + @echo AUDIO_MOTOROLA.DLL: dlltool + @dlltool -m arm_interwork \ + --def "$(EPOCBLD)\AUDIO_MOTOROLA.def" \ + --dllname "AUDIO_MOTOROLA[1000c197].DLL" \ + --base-file "$(EPOCBLDUREL)\AUDIO_MOTOROLA.bas" \ + --output-exp "$(EPOCBLDUREL)\AUDIO_MOTOROLA.exp" + -$(ERASE) "$(EPOCBLDUREL)\AUDIO_MOTOROLA.bas" + @echo AUDIO_MOTOROLA.DLL: ld + @ld -s -e _E32Dll -u _E32Dll --dll \ + "$(EPOCBLDUREL)\AUDIO_MOTOROLA.exp" \ + -Map "$(EPOCTRGUREL)\AUDIO_MOTOROLA.DLL.map" -o "$(EPOCBLDUREL)\AUDIO_MOTOROLA.DLL" \ + "$(EPOCSTATLINKUREL)\EDLL.LIB" --whole-archive "$(EPOCBLDUREL)\AUDIO_MOTOROLA.in" \ + --no-whole-archive $(LIBSUREL) $(USERLDFLAGS) + -$(ERASE) "$(EPOCBLDUREL)\AUDIO_MOTOROLA.exp" + @echo AUDIO_MOTOROLA.DLL: petran + @petran "$(EPOCBLDUREL)\AUDIO_MOTOROLA.DLL" "$@" \ + -nocall -uid1 0x10000079 -uid2 0x100039ce -uid3 0x1000c197 + -$(ERASE) "$(EPOCBLDUREL)\AUDIO_MOTOROLA.DLL" + +OBJECTSUREL= \ + $(EPOCBLDUREL)\AUDIO_MOTOROLA.o \ + $(EPOCBLDUREL)\POLLEDAS.o + +$(EPOCBLDUREL)\AUDIO_MOTOROLA.in : $(OBJECTSUREL) + @echo AUDIO_MOTOROLA.in: if exist (del?) + @if exist "$@" del "$@" + @echo AUDIO_MOTOROLA.in: ar + @ar cr $@ $^ + + +# REAL TARGET - BUILD VARIANT UDEB + +WHATUDEB : WHATGENERIC + +CLEANUDEB : CLEANBUILDUDEB CLEANRELEASEUDEB + +CLEANBUILDUDEB : + @perl -S ermdir.pl "$(EPOCBLDUDEB)" + +CLEANRELEASEUDEB : CLEANGENERIC + + +UDEB_RELEASEABLES1= \ + \DEV\A925SDK\EPOC32\RELEASE\ARM4\UREL\AUDIO_MOTOROLA.LIB \ + \DEV\A925SDK\EPOC32\RELEASE\ARMI\UDEB\AUDIO_MOTOROLA.DLL \ + \DEV\A925SDK\EPOC32\RELEASE\ARMI\UDEB\AUDIO_MOTOROLA.DLL.MAP \ + \DEV\A925SDK\EPOC32\RELEASE\ARMI\UREL\AUDIO_MOTOROLA.LIB \ + \DEV\A925SDK\EPOC32\RELEASE\THUMB\UREL\AUDIO_MOTOROLA.LIB + +WHATUDEB: + @echo $(UDEB_RELEASEABLES1) + +CLEANRELEASEUDEB: + -$(ERASE) $(UDEB_RELEASEABLES1) + +LISTINGUDEB : MAKEWORKUDEB \ + LISTINGUDEBAUDIO_MOTOROLA \ + LISTINGUDEBPOLLEDAS + +LIBSUDEB= \ + $(EPOCSTATLINKUDEB)\EDLLSTUB.LIB \ + $(EPOCSTATLINKUDEB)\EGCC.LIB \ + $(EPOCLINKUDEB)\EUSER.LIB \ + $(EPOCLINKUDEB)\MAUDIOFB.LIB \ + $(EPOCLINKUDEB)\MAUDIOAC.LIB + +$(EPOCTRGUDEB)\AUDIO_MOTOROLA.DLL : $(EPOCBLDUDEB)\AUDIO_MOTOROLA.in \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\AUDIO_MOTOROLA.DEF $(EPOCSTATLINKUDEB)\EDLL.LIB $(LIBSUDEB) + @echo AUDIO_MOTOROLA.DLL: dlltool + @dlltool -m arm_interwork --output-def "$(EPOCBLDUDEB)\AUDIO_MOTOROLA.inf" "$(EPOCBLDUDEB)\AUDIO_MOTOROLA.in" + @echo AUDIO_MOTOROLA.DLL: perl -S makedef.pl + @perl -S makedef.pl -Deffile "$(EPOCBLDUDEB)\AUDIO_MOTOROLA.inf" -Frzfile "\DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\AUDIO_MOTOROLA.DEF" "$(EPOCBLD)\AUDIO_MOTOROLA.def" + -$(ERASE) "$(EPOCBLDUDEB)\AUDIO_MOTOROLA.inf" + @echo AUDIO_MOTOROLA.DLL: dlltool + @dlltool -m arm_interwork --def "$(EPOCBLD)\AUDIO_MOTOROLA.def" \ + --output-exp "$(EPOCBLDUDEB)\AUDIO_MOTOROLA.exp" \ + --dllname "AUDIO_MOTOROLA[1000c197].DLL" + @echo AUDIO_MOTOROLA.DLL: ld + @ld -s -e _E32Dll -u _E32Dll "$(EPOCBLDUDEB)\AUDIO_MOTOROLA.exp" --dll \ + --base-file "$(EPOCBLDUDEB)\AUDIO_MOTOROLA.bas" -o "$(EPOCBLDUDEB)\AUDIO_MOTOROLA.DLL" \ + "$(EPOCSTATLINKUDEB)\EDLL.LIB" --whole-archive "$(EPOCBLDUDEB)\AUDIO_MOTOROLA.in" \ + --no-whole-archive $(LIBSUDEB) $(USERLDFLAGS) + -$(ERASE) "$(EPOCBLDUDEB)\AUDIO_MOTOROLA.exp" + -$(ERASE) "$(EPOCBLDUDEB)\AUDIO_MOTOROLA.DLL" + @echo AUDIO_MOTOROLA.DLL: dlltool + @dlltool -m arm_interwork \ + --def "$(EPOCBLD)\AUDIO_MOTOROLA.def" \ + --dllname "AUDIO_MOTOROLA[1000c197].DLL" \ + --base-file "$(EPOCBLDUDEB)\AUDIO_MOTOROLA.bas" \ + --output-exp "$(EPOCBLDUDEB)\AUDIO_MOTOROLA.exp" + -$(ERASE) "$(EPOCBLDUDEB)\AUDIO_MOTOROLA.bas" + @echo AUDIO_MOTOROLA.DLL: ld + @ld -e _E32Dll -u _E32Dll --dll \ + "$(EPOCBLDUDEB)\AUDIO_MOTOROLA.exp" \ + -Map "$(EPOCTRGUDEB)\AUDIO_MOTOROLA.DLL.map" -o "$(EPOCBLDUDEB)\AUDIO_MOTOROLA.DLL" \ + "$(EPOCSTATLINKUDEB)\EDLL.LIB" --whole-archive "$(EPOCBLDUDEB)\AUDIO_MOTOROLA.in" \ + --no-whole-archive $(LIBSUDEB) $(USERLDFLAGS) + -$(ERASE) "$(EPOCBLDUDEB)\AUDIO_MOTOROLA.exp" + objcopy -X "$(EPOCBLDUDEB)\AUDIO_MOTOROLA.DLL" "$(EPOCTRGUDEB)\AUDIO_MOTOROLA.sym" + @echo AUDIO_MOTOROLA.DLL: petran + @petran "$(EPOCBLDUDEB)\AUDIO_MOTOROLA.DLL" "$@" \ + -nocall -uid1 0x10000079 -uid2 0x100039ce -uid3 0x1000c197 + -$(ERASE) "$(EPOCBLDUDEB)\AUDIO_MOTOROLA.DLL" + +OBJECTSUDEB= \ + $(EPOCBLDUDEB)\AUDIO_MOTOROLA.o \ + $(EPOCBLDUDEB)\POLLEDAS.o + +$(EPOCBLDUDEB)\AUDIO_MOTOROLA.in : $(OBJECTSUDEB) + @echo AUDIO_MOTOROLA.in: if exist (del?) + @if exist "$@" del "$@" + @echo AUDIO_MOTOROLA.in: ar + @ar cr $@ $^ + + +# SOURCES + +# Source AUDIO_MOTOROLA.CPP + +$(EPOCBLDUREL)\AUDIO_MOTOROLA.lis $(EPOCBLDUREL)\AUDIO_MOTOROLA.o \ +$(EPOCBLDUDEB)\AUDIO_MOTOROLA.lis $(EPOCBLDUDEB)\AUDIO_MOTOROLA.o \ +: \ + \DEV\A925SDK\EPOC32\INCLUDE\CMAUDIOAC.H \ + \DEV\A925SDK\EPOC32\INCLUDE\CMAUDIOFB.H \ + \DEV\A925SDK\EPOC32\INCLUDE\CMAUDIOFBFORMAT.H \ + \DEV\A925SDK\EPOC32\INCLUDE\E32BASE.H \ + \DEV\A925SDK\EPOC32\INCLUDE\E32BASE.INL \ + \DEV\A925SDK\EPOC32\INCLUDE\E32DEF.H \ + \DEV\A925SDK\EPOC32\INCLUDE\E32DES16.H \ + \DEV\A925SDK\EPOC32\INCLUDE\E32DES8.H \ + \DEV\A925SDK\EPOC32\INCLUDE\E32HAL.H \ + \DEV\A925SDK\EPOC32\INCLUDE\E32KEYS.H \ + \DEV\A925SDK\EPOC32\INCLUDE\E32PCCD.H \ + \DEV\A925SDK\EPOC32\INCLUDE\E32STD.H \ + \DEV\A925SDK\EPOC32\INCLUDE\E32STD.INL \ + \DEV\A925SDK\EPOC32\INCLUDE\E32SVR.H \ + \DEV\A925SDK\EPOC32\INCLUDE\F32FILE.H \ + \DEV\A925SDK\EPOC32\INCLUDE\F32FILE.INL \ + \DEV\A925SDK\EPOC32\INCLUDE\MAUDIOGLOBAL.H \ + \DEV\A925SDK\EPOC32\INCLUDE\RPFILE.H \ + \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO.H \ + \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\AUDIO_MOTOROLA.H \ + \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\POLLEDAS.H + +$(EPOCBLDUREL)\AUDIO_MOTOROLA.o : \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\Audio_motorola.cpp + @echo AUDIO_MOTOROLA.o: gcc + @$(GCCUREL) -I "." $(INCDIR) -o $@ ".\Audio_motorola.cpp" + +LISTINGURELAUDIO_MOTOROLA : $(EPOCBLDUREL)\AUDIO_MOTOROLA.lis + @echo ISTINGURELAUDIO_MOTOROLA: perl -S ecopyfile.pl + @perl -S ecopyfile.pl $? \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\AUDIO_MOTOROLA.lst.ARMI + +$(EPOCBLDUREL)\AUDIO_MOTOROLA.lis : \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\Audio_motorola.cpp + $(GCCUREL) -Wa,-adln -I "." $(INCDIR) -o nul: ".\Audio_motorola.cpp" > $@ + +$(EPOCBLDUDEB)\AUDIO_MOTOROLA.o : \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\Audio_motorola.cpp + $(GCCUDEB) -I "." $(INCDIR) -o $@ ".\Audio_motorola.cpp" + +LISTINGUDEBAUDIO_MOTOROLA : $(EPOCBLDUDEB)\AUDIO_MOTOROLA.lis + @echo ISTINGUDEBAUDIO_MOTOROLA: perl -S ecopyfile.pl + @perl -S ecopyfile.pl $? \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\AUDIO_MOTOROLA.lst.ARMI + +$(EPOCBLDUDEB)\AUDIO_MOTOROLA.lis : \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\Audio_motorola.cpp + $(GCCUDEB) -Wa,-adln -I "." $(INCDIR) -o nul: ".\Audio_motorola.cpp" > $@ + + + +# Source POLLEDAS.CPP + +$(EPOCBLDUREL)\POLLEDAS.lis $(EPOCBLDUREL)\POLLEDAS.o \ +$(EPOCBLDUDEB)\POLLEDAS.lis $(EPOCBLDUDEB)\POLLEDAS.o \ +: \ + \DEV\A925SDK\EPOC32\INCLUDE\E32DEF.H \ + \DEV\A925SDK\EPOC32\INCLUDE\E32DES16.H \ + \DEV\A925SDK\EPOC32\INCLUDE\E32DES8.H \ + \DEV\A925SDK\EPOC32\INCLUDE\E32STD.H \ + \DEV\A925SDK\EPOC32\INCLUDE\E32STD.INL \ + \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\POLLEDAS.H + +$(EPOCBLDUREL)\POLLEDAS.o : \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\Polledas.cpp + @echo POLLEDAS.o: gcc + @$(GCCUREL) -I "." $(INCDIR) -o $@ ".\Polledas.cpp" + +LISTINGURELPOLLEDAS : $(EPOCBLDUREL)\POLLEDAS.lis + @echo ISTINGURELPOLLEDAS: perl -S ecopyfile.pl + @perl -S ecopyfile.pl $? \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\POLLEDAS.lst.ARMI + +$(EPOCBLDUREL)\POLLEDAS.lis : \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\Polledas.cpp + $(GCCUREL) -Wa,-adln -I "." $(INCDIR) -o nul: ".\Polledas.cpp" > $@ + +$(EPOCBLDUDEB)\POLLEDAS.o : \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\Polledas.cpp + $(GCCUDEB) -I "." $(INCDIR) -o $@ ".\Polledas.cpp" + +LISTINGUDEBPOLLEDAS : $(EPOCBLDUDEB)\POLLEDAS.lis + @echo ISTINGUDEBPOLLEDAS: perl -S ecopyfile.pl + @perl -S ecopyfile.pl $? \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\POLLEDAS.lst.ARMI + +$(EPOCBLDUDEB)\POLLEDAS.lis : \DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\Polledas.cpp + $(GCCUDEB) -Wa,-adln -I "." $(INCDIR) -o nul: ".\Polledas.cpp" > $@ + + + +ROMFILE: + @echo file=\DEV\A925SDK\EPOC32\RELEASE\ARMI\##BUILD##\AUDIO_MOTOROLA.DLL System\Libs\AUDIO_MOTOROLA.DLL + + +WHATGENERIC CLEANGENERIC : + @rem none + +# Rules to create all necessary directories + +GENERIC_MAKEWORK : \ + \DEV\A925SDK\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\AUDIO_MOTOROLA\ARMI +MAKEWORKLIBRARY : \ + \DEV\A925SDK\EPOC32\RELEASE\ARM4\UREL \ + \DEV\A925SDK\EPOC32\RELEASE\ARMI\UREL \ + \DEV\A925SDK\EPOC32\RELEASE\THUMB\UREL +MAKEWORKUDEB : \ + \DEV\A925SDK\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\AUDIO_MOTOROLA\ARMI\UDEB \ + \DEV\A925SDK\EPOC32\RELEASE\ARMI\UDEB +MAKEWORKUREL : \ + \DEV\A925SDK\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\AUDIO_MOTOROLA\ARMI\UREL \ + \DEV\A925SDK\EPOC32\RELEASE\ARMI\UREL + +\DEV\A925SDK\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\AUDIO_MOTOROLA\ARMI \ +\DEV\A925SDK\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\AUDIO_MOTOROLA\ARMI\UDEB \ +\DEV\A925SDK\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\AUDIO\MOTOROLA\AUDIO_MOTOROLA\ARMI\UREL \ +\DEV\A925SDK\EPOC32\RELEASE\ARM4\UREL \ +\DEV\A925SDK\EPOC32\RELEASE\ARMI\UDEB \ +\DEV\A925SDK\EPOC32\RELEASE\ARMI\UREL \ +\DEV\A925SDK\EPOC32\RELEASE\THUMB\UREL \ +: + @echo UREL: perl -S emkdir.pl + @perl -S emkdir.pl $@ + + diff --git a/platform/uiq2/audio/motorola/PolledAS.h b/platform/uiq2/audio/motorola/PolledAS.h new file mode 100644 index 00000000..f360c897 --- /dev/null +++ b/platform/uiq2/audio/motorola/PolledAS.h @@ -0,0 +1,32 @@ +/******************************************************************* + * + * File: PolledAS.h + * + * Author: Peter van Sebille (peter@yipton.net) + * + * (c) Copyright 2001, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +#ifndef __POLLED_AS_H +#define __POLLED_AS_H + +class CPrivatePolledActiveScheduler; + +class CPolledActiveScheduler : public CBase +{ +public: + ~CPolledActiveScheduler(); + static CPolledActiveScheduler* NewL(); + //static CPolledActiveScheduler* Instance(); + void Schedule(); +protected: + CPolledActiveScheduler(){}; + void ConstructL(); + CPrivatePolledActiveScheduler* iPrivatePolledActiveScheduler; +}; + + +#endif /* __POLLED_AS_H */ + diff --git a/platform/uiq2/audio/motorola/audio_motorola.cpp b/platform/uiq2/audio/motorola/audio_motorola.cpp new file mode 100644 index 00000000..b4ed4013 --- /dev/null +++ b/platform/uiq2/audio/motorola/audio_motorola.cpp @@ -0,0 +1,363 @@ +/******************************************************************* + * + * File: Audio_motorola.cpp + * + * Author: Peter van Sebille (peter@yipton.net) + * + * Modified/adapted for picodriveN by notaz, 2006 + * + * (c) Copyright 2006, notaz + * (c) Copyright 2001, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +// if only I had Motorola to test this on.. + + +#include "audio_motorola.h" + +#ifdef __DEBUG_PRINT_SND + #include // RDebug + #define DEBUGPRINT(x...) RDebug::Print(x) +#else + #define DEBUGPRINT(x...) +#endif + + +GLDEF_C TInt E32Dll(TDllReason) +{ + return KErrNone; +} + + +/******************************************* + * + * CGameAudioMot + * + *******************************************/ + +CGameAudioMot::CGameAudioMot(TInt aRate, TBool aStereo, TInt aPcmFrames, TInt aBufferedFrames) +: iRate(aRate), iStereo(aStereo), iBufferedFrames(aBufferedFrames), iPcmFrames(aPcmFrames) +{ + DEBUGPRINT(_L("CGameAudioMot::CGameAudioMot")); +} + + +CGameAudioMot* CGameAudioMot::NewL(TInt aRate, TBool aStereo, TInt aPcmFrames, TInt aBufferedFrames) +{ + DEBUGPRINT(_L("CGameAudioMot::NewL(%i, %i, %i, %i)"),aRate, aStereo, aPcmFrames, aBufferedFrames); + CGameAudioMot* self = new(ELeave) CGameAudioMot(aRate, aStereo, aPcmFrames, aBufferedFrames); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); // self + return self; +} + + +CGameAudioMot::~CGameAudioMot() +{ + DEBUGPRINT(_L("CGameAudioMot::~CGameAudioMot()")); + if(iAudioOutputStream) { + iScheduler->Schedule(); // let it finish it's stuff + //iAudioOutputStream->Stop(); + delete iAudioOutputStream; + } + + if(iAudioControl) delete iAudioControl; + + for (TInt i=0 ; i < KSoundBuffers+1; i++) { + delete iSoundBufferPtrs[i]; + delete iSoundBuffers[i]; + } + + // Polled AS + if(iScheduler) delete iScheduler; +} + + +void CGameAudioMot::ConstructL() +{ + iScheduler = CPolledActiveScheduler::NewL(); + + iSettings.iPCMSettings.iSamplingFreq = (TMSampleRate) iRate; + iSettings.iPCMSettings.iStereo = iStereo; + + TInt bytesPerFrame = iStereo ? iPcmFrames << 2 : iPcmFrames << 1; + for (TInt i=0 ; iDes().FillZ (bytesPerFrame * iBufferedFrames); + iSoundBufferPtrs[i] = new TPtr8( iSoundBuffers[i]->Des() ); + } + // because feeding 2 buffers after an underflow is a little too much, but feeding 1 may be not enough, + // prepare this ~50ms empty buffer to additionaly feed after every underflow. + iSoundBuffers[KSoundBuffers] = HBufC8::NewL(bytesPerFrame * (iBufferedFrames / 4)); + iSoundBuffers[KSoundBuffers]->Des().FillZ (bytesPerFrame * (iBufferedFrames / 4)); + iSoundBufferPtrs[KSoundBuffers] = new TPtr8( iSoundBuffers[KSoundBuffers]->Des() ); + + iCurrentBuffer = 0; + iListener.iFatalError = iListener.iIsOpen = iListener.iIsCtrlOpen = EFalse; + + // here we actually test if we can create and open CMdaAudioOutputStream at all, but really create and use it later. + iAudioOutputStream = CMAudioFB::NewL(EMAudioFBRequestTypeDecode, EMAudioFBFormatPCM, iSettings, iListener); + if(iAudioOutputStream) { + delete iAudioOutputStream; + iAudioOutputStream = 0; + } + + // ceate audio control object + iAudioControl = CMAudioAC::NewL(iListener); +} + + +// returns a pointer to buffer for next frame, +// to be used when iSoundBuffers are used directly +TInt16 *CGameAudioMot::NextFrameL() +{ + iCurrentPosition += iPcmFrames << (iStereo?1:0); + + if (++iFrameCount == iBufferedFrames) + { + WriteBlockL(); + } + + iScheduler->Schedule(); + + if(iListener.iFatalError || iListener.iUnderflowed > KMaxUnderflows) { + if(iAudioOutputStream) delete iAudioOutputStream; + iAudioOutputStream = 0; + return 0; + } + else if(iListener.iUnderflowed) UnderflowedL(); + + return iCurrentPosition; +} + +TInt16 *CGameAudioMot::DupeFrameL(TInt &aUnderflowed) +{ + TInt shorts = iStereo ? (iPcmFrames << 1) : iPcmFrames; + if(iFrameCount) + Mem::Copy(iCurrentPosition, iCurrentPosition-shorts, shorts<<1); + else { + TInt lastBuffer = iCurrentBuffer; + if(--lastBuffer < 0) lastBuffer = KSoundBuffers - 1; + Mem::Copy(iCurrentPosition, ((TInt16*) (iSoundBuffers[lastBuffer]->Ptr()))+shorts*(iBufferedFrames-1), shorts<<1); + } + iCurrentPosition += shorts; + + if (++iFrameCount == iBufferedFrames) + { + WriteBlockL(); + } + + iScheduler->Schedule(); + + if(iListener.iFatalError || iListener.iUnderflowed > KMaxUnderflows) { + if(iAudioOutputStream) delete iAudioOutputStream; + iAudioOutputStream = 0; + return 0; + } + else if((aUnderflowed = iListener.iUnderflowed)) UnderflowedL(); // not again! + + return iCurrentPosition; +} + +void CGameAudioMot::WriteBlockL() +{ + iScheduler->Schedule(); + + // do not write until stream is open + if(!iListener.iIsOpen) WaitForOpenToCompleteL(); + //if(!iListener.iHasCopied) WaitForCopyToCompleteL(); // almost never happens anyway and sometimes even deadlocks? + //iListener.iHasCopied = EFalse; + + + if(!iListener.iUnderflowed) { + iAudioOutputStream->QueueBufferL(iSoundBufferPtrs[iCurrentBuffer]); + // it is certain we already Queued at least 2 buffers (one just after underflow, another above) + if(!iDecoding) { + iAudioOutputStream->DecodeL(); + iDecoding = ETrue; + } + } + + iFrameCount = 0; + if (++iCurrentBuffer == KSoundBuffers) + iCurrentBuffer = 0; + iCurrentPosition = (TInt16*) iSoundBuffers[iCurrentBuffer]->Ptr(); +} + +void CGameAudioMot::Pause() +{ + if(!iAudioOutputStream) return; + + iScheduler->Schedule(); + // iAudioOutputStream->Stop(); // may be this breaks everything in A925? + delete iAudioOutputStream; + iAudioOutputStream = 0; +} + +// call this before doing any playback! +TInt16 *CGameAudioMot::ResumeL() +{ + DEBUGPRINT(_L("CGameAudioMot::Resume()")); + iScheduler->Schedule(); + + // we act a bit strange here: simulate buffer underflow, which actually starts audio + iListener.iIsOpen = ETrue; + iListener.iUnderflowed = 1; + iListener.iFatalError = EFalse; + iFrameCount = 0; + iCurrentPosition = (TInt16*) iSoundBuffers[iCurrentBuffer]->Ptr(); + return iCurrentPosition; +} + +// handles underflow condition +void CGameAudioMot::UnderflowedL() +{ + // recreate the stream + if(iAudioOutputStream) delete iAudioOutputStream; + if(iListener.iUnderflowed > 4) { + // HACK: A925 user said sound works for the first time, but fails after pause/resume, etc. + // at the very beginning we create and delete CMAudioFB object, maybe we should do this every time? + iAudioOutputStream = CMAudioFB::NewL(EMAudioFBRequestTypeDecode, EMAudioFBFormatPCM, iSettings, iListener); + if(iAudioOutputStream) delete iAudioOutputStream; + } + + iAudioOutputStream = CMAudioFB::NewL(EMAudioFBRequestTypeDecode, EMAudioFBFormatPCM, iSettings, iListener); + iListener.iIsOpen = EFalse; // wait for it to open + iDecoding = EFalse; + //iListener.iHasCopied = ETrue; // but don't wait for last copy to complete + // let it open and feed some stuff to make it happy + User::After(0); + //TInt lastBuffer = iCurrentBuffer; + //if(--lastBuffer < 0) lastBuffer = KSoundBuffers - 1; + iScheduler->Schedule(); + if(!iListener.iIsOpen) WaitForOpenToCompleteL(); + if(iListener.iUnderflowed) { + // something went wrong again. May be it needs time? Trying to fix something without ability to test is hell. + if(iAudioOutputStream) delete iAudioOutputStream; + iAudioOutputStream = 0; + User::After(50*000); + iScheduler->Schedule(); + return; + } + + iAudioOutputStream->QueueBufferL(iSoundBufferPtrs[KSoundBuffers]); // try a short buffer with hope to reduce lag +} + + +void CGameAudioMot::ChangeVolume(TInt aUp) +{ + if(iAudioControl && iListener.iIsCtrlOpen) + { + TInt vol = iAudioControl->GetMasterVolume(); + TInt max = iAudioControl->GetMaxMasterVolume(); + + if(aUp) vol++; // adjust volume + else vol--; + + if(vol >= 0 && vol <= max) + { + iAudioControl->SetMasterVolume(vol); + } + } +} + + +void CGameAudioMot::WaitForOpenToCompleteL() +{ + DEBUGPRINT(_L("CGameAudioMot::WaitForOpenToCompleteL")); + TInt count = 20; // 2 seconds + TInt waitPeriod = 100 * 1000; + + if(!iListener.iIsOpen) { + // it is often enough to do this + User::After(0); + iScheduler->Schedule(); + } + while (!iListener.iIsOpen && --count) + { + User::After(waitPeriod); + iScheduler->Schedule(); + } + if (!iListener.iIsOpen) + User::LeaveIfError(KErrNotSupported); +} + + + +void TGameAudioEventListener::OnEvent(TMAudioFBCallbackState aState, TInt aError) +{ + switch ( aState ) + { + case EMAudioFBCallbackStateReady: + iIsOpen = ETrue; + iUnderflowed = 0; + break; + + case EMAudioFBCallbackStateDecodeCompleteStopped: + break; + + //case EMAudioFBCallbackStateDecodeFileSystemError: + case EMAudioFBCallbackStateDecodeError: + switch( aError ) + { + case EMAudioFBCallbackErrorBufferFull: + case EMAudioFBCallbackErrorForcedStop: + case EMAudioFBCallbackErrorForcedClose: + //case EMAudioFBCallbackErrorForcedPause: + case EMAudioFBCallbackErrorPriorityRejection: + case EMAudioFBCallbackErrorAlertModeRejection: + case EMAudioFBCallbackErrorResourceRejection: + case EMAudioFBCallbackErrorUnknown: + iUnderflowed++; + break; + + // these look like really bad errors + case EMAudioFBCallbackErrorInvalidParameter: + case EMAudioFBCallbackErrorWrongState: + case EMAudioFBCallbackErrorFormatNotSupported: + case EMAudioFBCallbackErrorFunctionNotSupported: + case EMAudioFBCallbackErrorNoBuffer: + case EMAudioFBCallbackErrorSampleOrBitRateNotSupported: + //case EMAudioFBCallbackErrorPriorityOrPreferenceNotSupported: + //case EMAudioFBCallbackErrorFileSystemFull: + //iFatalError = ETrue; + // who cares, just keep retrying + iUnderflowed++; + break; + + default: + iUnderflowed++; + break; + } + // in error condition we also set to open, so that the + // framework would not leave, catch the error and retry + iIsOpen = ETrue; + break; + + default: + break; + } +} + +void TGameAudioEventListener::OnEvent(TMAudioFBCallbackState aState, TInt aError, TDes8* aBuffer) +{ + switch( aState ) + { + case EMAudioFBCallbackStateDecodeBufferDecoded: + break; + + default: + OnEvent( aState, aError ); + break; + } +} + +void TGameAudioEventListener::OnEvent(TMAudioACCallbackState aState, TInt aError) +{ + if(aState == EMAudioACCallbackStateReady) iIsCtrlOpen = ETrue; +} + diff --git a/platform/uiq2/audio/motorola/audio_motorola.def b/platform/uiq2/audio/motorola/audio_motorola.def new file mode 100644 index 00000000..6098f2a6 --- /dev/null +++ b/platform/uiq2/audio/motorola/audio_motorola.def @@ -0,0 +1,3 @@ +EXPORTS +; NEW: + NewL__13CGameAudioMotiiii @ 1 NONAME ; static CGameAudioMot* NewL(TInt aRate, TBool aStereo, TInt aPcmFrames, TInt aBufferedFrames); diff --git a/platform/uiq2/audio/motorola/audio_motorola.h b/platform/uiq2/audio/motorola/audio_motorola.h new file mode 100644 index 00000000..26c41098 --- /dev/null +++ b/platform/uiq2/audio/motorola/audio_motorola.h @@ -0,0 +1,91 @@ +/******************************************************************* + * + * File: Audio_motorola.h + * + * Author: Peter van Sebille (peter@yipton.net) + * + * Modified/adapted for picodriveN by notaz, 2006 + * + * (c) Copyright 2006, notaz + * (c) Copyright 2001, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +#ifndef __AUDIO_MEDIASERVER_H +#define __AUDIO_MEDIASERVER_H + +#include + +#include "audio.h" +#include "polledas.h" + +const TInt KSoundBuffers = 8; +const TInt KMaxUnderflows = 20; // max underflows/API errors we are going allow in a row (to prevent lockups) + + +class TGameAudioEventListener : public MMAudioFBObserver, public MMAudioACObserver +{ +public: + // Implementation of MMAudioFBObserver + void OnEvent(TMAudioFBCallbackState aState, TInt aError); + void OnEvent(TMAudioFBCallbackState aState, TInt aError, TDes8* aBuffer); + // Implementation of MMAudioACObserver + void OnEvent(TMAudioACCallbackState aState, TInt aError); + + TBool iIsOpen; + TBool iIsCtrlOpen; +// TBool iHasCopied; + TInt iUnderflowed; + TBool iFatalError; +}; + + +class CGameAudioMot : public IGameAudio // IGameAudio MUST be specified first! +{ +public: // implements IGameAudio + TInt16 *NextFrameL(); + TInt16 *DupeFrameL(TInt &aUnderflowed); + TInt16 *ResumeL(); + void Pause(); + void ChangeVolume(TInt aUp); + +public: + ~CGameAudioMot(); + CGameAudioMot(TInt aRate, TBool aStereo, TInt aPcmFrames, TInt aBufferedFrames); + void ConstructL(); + EXPORT_C static CGameAudioMot* NewL(TInt aRate, TBool aStereo, TInt aPcmFrames, TInt aBufferedFrames); + +protected: + void WriteBlockL(); + void UnderflowedL(); + +protected: + void WaitForOpenToCompleteL(); + + TInt iRate; + TBool iStereo; + + CMAudioFB *iAudioOutputStream; + CMAudioAC *iAudioControl; + TMAudioFBBufSettings iSettings; + + TGameAudioEventListener iListener; + + CPolledActiveScheduler *iScheduler; + + HBufC8* iSoundBuffers[KSoundBuffers+1]; + TPtr8* iSoundBufferPtrs[KSoundBuffers+1]; + + TInt iBufferedFrames; + TInt16* iCurrentPosition; + TInt iCurrentBuffer; + TInt iFrameCount; + TInt iPcmFrames; + + TBool iDecoding; + + //TInt64 iTime; // removed because can't test +}; + +#endif /* __AUDIO_MEDIASERVER_H */ diff --git a/platform/uiq2/audio/motorola/audio_motorola.mmp b/platform/uiq2/audio/motorola/audio_motorola.mmp new file mode 100644 index 00000000..473c4dd3 --- /dev/null +++ b/platform/uiq2/audio/motorola/audio_motorola.mmp @@ -0,0 +1,20 @@ +TARGET audio_motorola.dll +TARGETTYPE dll +UID 0x100039CE 0x1000C197 + +USERINCLUDE . +USERINCLUDE ..\..\ + +SYSTEMINCLUDE \epoc32\include + +SOURCEPATH . +SOURCE audio_motorola.cpp +SOURCE polledas.cpp + +LIBRARY EUSER.LIB +LIBRARY maudiofb.lib +LIBRARY maudioac.lib + +deffile .\audio_motorola.def + +nostrictdef diff --git a/platform/uiq2/audio/motorola/polledas.cpp b/platform/uiq2/audio/motorola/polledas.cpp new file mode 100644 index 00000000..60991ec5 --- /dev/null +++ b/platform/uiq2/audio/motorola/polledas.cpp @@ -0,0 +1,209 @@ +/******************************************************************* + * + * File: PolledAS.cpp + * + * Author: Peter van Sebille (peter@yipton.net) + * + * (c) Copyright 2002, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +/* + * Oh Lord, forgive me for I have sinned. + * In their infinite wisdom, Symbian Engineers have decided that + * the Active Scheduler's queue of Active Objects is private + * and no getters are provided... sigh. + * This mere mortal will have to excercise the power of C pre-processor + * once more to circumvent the will of the gods. + */ + + +#include + +// from e32base.h +class CBase + { +public: + IMPORT_C virtual ~CBase(); + inline TAny* operator new(TUint aSize,TAny *aBase) {Mem::FillZ(aBase,aSize);return(aBase);} + IMPORT_C TAny* operator new(TUint aSize); + inline TAny* operator new(TUint aSize, TLeave) {return newL(aSize);} + IMPORT_C TAny* operator new(TUint aSize,TUint anExtraSize); +protected: + IMPORT_C CBase(); +private: + CBase(const CBase&); + CBase& operator=(const CBase&); + IMPORT_C static TAny* newL(TUint aSize); + }; + +class CActive : public CBase + { +public: +enum TPriority + { + EPriorityIdle=-100, + EPriorityLow=-20, + EPriorityStandard=0, + EPriorityUserInput=10, + EPriorityHigh=20, + }; +public: + IMPORT_C ~CActive(); + IMPORT_C void Cancel(); + IMPORT_C void Deque(); + IMPORT_C void SetPriority(TInt aPriority); + inline TBool IsActive() const {return(iActive);} + inline TBool IsAdded() const {return(iLink.iNext!=NULL);} + inline TInt Priority() const {return iLink.iPriority;} +protected: + IMPORT_C CActive(TInt aPriority); + IMPORT_C void SetActive(); +// Pure virtual + virtual void DoCancel() =0; + virtual void RunL() =0; + IMPORT_C virtual TInt RunError(TInt aError); +public: + TRequestStatus iStatus; +private: + TBool iActive; + TPriQueLink iLink; + friend class CActiveScheduler; +// friend class CServer; + friend class CPrivatePolledActiveScheduler; // added + }; + +// +class CActiveScheduler : public CBase + { +public: + IMPORT_C CActiveScheduler(); + IMPORT_C ~CActiveScheduler(); + IMPORT_C static void Install(CActiveScheduler* aScheduler); + IMPORT_C static CActiveScheduler* Current(); + IMPORT_C static void Add(CActive* anActive); + IMPORT_C static void Start(); + IMPORT_C static void Stop(); + IMPORT_C static TBool RunIfReady(TInt& aError, TInt aMinimumPriority); + IMPORT_C static CActiveScheduler* Replace(CActiveScheduler* aNewActiveScheduler); + IMPORT_C virtual void WaitForAnyRequest(); + IMPORT_C virtual void Error(TInt anError) const; +private: + void DoStart(); + IMPORT_C virtual void OnStarting(); + IMPORT_C virtual void OnStopping(); + IMPORT_C virtual void Reserved_1(); + IMPORT_C virtual void Reserved_2(); + friend class CPrivatePolledActiveScheduler; // added +protected: + inline TInt Level() const; +private: + TInt iLevel; + TPriQue iActiveQ; + }; + +class TCleanupItem; +class CleanupStack + { +public: + IMPORT_C static void PushL(TAny* aPtr); + IMPORT_C static void PushL(CBase* aPtr); + IMPORT_C static void PushL(TCleanupItem anItem); + IMPORT_C static void Pop(); + IMPORT_C static void Pop(TInt aCount); + IMPORT_C static void PopAndDestroy(); + IMPORT_C static void PopAndDestroy(TInt aCount); + IMPORT_C static void Check(TAny* aExpectedItem); + inline static void Pop(TAny* aExpectedItem); + inline static void Pop(TInt aCount, TAny* aLastExpectedItem); + inline static void PopAndDestroy(TAny* aExpectedItem); + inline static void PopAndDestroy(TInt aCount, TAny* aLastExpectedItem); + }; + + +/* + * This will declare CPrivatePolledActiveScheduler as a friend + * of all classes that define a friend. CPrivatePolledActiveScheduler needs to + * be a friend of CActive + */ +//#define friend friend class CPrivatePolledActiveScheduler; friend + + +/* + * This will change the: + * void DoStart(); + * method in CActiveScheduler to: + * void DoStart(); friend class CPrivatePolledActiveScheduler; + * We need this to access the private datamembers in CActiveScheduler. + */ +//#define DoStart() DoStart(); friend class CPrivatePolledActiveScheduler; +//#include +#include "PolledAS.h" + + +class CPrivatePolledActiveScheduler : public CActiveScheduler +{ +public: + void Schedule(); +}; + + + +void CPrivatePolledActiveScheduler::Schedule() +{ + TDblQueIter q(iActiveQ); + q.SetToFirst(); + FOREVER + { + CActive *pR=q++; + if (pR) + { + if (pR->IsActive() && pR->iStatus!=KRequestPending) + { + pR->iActive=EFalse; + TRAPD(r,pR->RunL()); + break; + } + } + else + break; + } +} + + +CPolledActiveScheduler::~CPolledActiveScheduler() +{ + delete iPrivatePolledActiveScheduler; +} + +//static CPolledActiveScheduler* sPolledActiveScheduler = NULL; +CPolledActiveScheduler* CPolledActiveScheduler::NewL() +{ + //sPolledActiveScheduler = + CPolledActiveScheduler* self = new(ELeave)CPolledActiveScheduler; + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return self; +} + +void CPolledActiveScheduler::ConstructL() +{ + iPrivatePolledActiveScheduler = new(ELeave) CPrivatePolledActiveScheduler; + iPrivatePolledActiveScheduler->Install(iPrivatePolledActiveScheduler); +} + + +void CPolledActiveScheduler::Schedule() +{ + iPrivatePolledActiveScheduler->Schedule(); +} + +/* +CPolledActiveScheduler* CPolledActiveScheduler::Instance() +{ +// return (CPolledActiveScheduler*) CActiveScheduler::Current(); + return sPolledActiveScheduler; +} +*/ diff --git a/platform/uiq2/audio/motorola/retr.cmd b/platform/uiq2/audio/motorola/retr.cmd new file mode 100644 index 00000000..d7b22bb2 --- /dev/null +++ b/platform/uiq2/audio/motorola/retr.cmd @@ -0,0 +1,2 @@ +copy %EPOCROOT%\epoc32\release\armi\urel\audio_motorola.dll ..\ +..\..\..\qconsole-1.52\qtty\release\qtty --qc-addr P800 --qc-channel 5 --user qconsole --pass server --cmds "put d:\system\apps\picodriven\audio_motorola.dll ..\audio_motorola.dll" exit diff --git a/platform/uiq2/audio/motorola/retr2.cmd b/platform/uiq2/audio/motorola/retr2.cmd new file mode 100644 index 00000000..41bc59c2 --- /dev/null +++ b/platform/uiq2/audio/motorola/retr2.cmd @@ -0,0 +1 @@ +copy %EPOCROOT%\epoc32\release\armi\urel\audio_motorola.dll ..\ diff --git a/platform/uiq2/blit.h b/platform/uiq2/blit.h new file mode 100644 index 00000000..5556e342 --- /dev/null +++ b/platform/uiq2/blit.h @@ -0,0 +1,11 @@ +extern "C" { + void vidConvCpyRGB444(void *to, void *from, int pixels); + void vidConvCpyRGB565(void *to, void *from, int pixels); + void vidConvCpyRGB32 (void *to, void *from, int pixels); + + // warning: the functions below will reboot the phone if used incorrectly! + void vidConvCpyM2_16_90 (void *to, void *from, int width); // width is in blocks of 8 pixels + void vidConvCpyM2_16_270 (void *to, void *from, int width); + void vidConvCpyM2_RGB32_90 (void *to, void *from, int width); + void vidConvCpyM2_RGB32_270(void *to, void *from, int width); +} diff --git a/platform/uiq2/blit.s b/platform/uiq2/blit.s new file mode 100644 index 00000000..899f13e8 --- /dev/null +++ b/platform/uiq2/blit.s @@ -0,0 +1,432 @@ +@ assembly "optimized" blitter and copy functions +@ all pointers must be word-aligned + +@ (c) Copyright 2006, notaz +@ All Rights Reserved + + +@ Convert 0000bbb0 ggg0rrr0 +@ to 0000rrr0 ggg0bbb0 + +@ r2,r3 - scratch, lr = 0x000F000F +.macro convRGB444 reg + and r2, \reg, lr @ r2=red + and r3, \reg, lr, lsl #8 @ r3=blue + and \reg, \reg, lr, lsl #4 @ green stays in place + orr \reg, \reg, r2, lsl #8 @ add red back + orr \reg, \reg, r3, lsr #8 @ add blue back +.endm + +.global vidConvCpyRGB444 @ void *to, void *from, int pixels + +vidConvCpyRGB444: + stmfd sp!, {r4-r11,lr} + + mov r12, r2, lsr #4 @ repeats + mov lr, #0xF0000 + orr lr, lr, #0xF @ lr == pattern 0x000F000F + + +.loopRGB444: + subs r12, r12, #1 + + @ I first thought storing multiple registers would be faster, + @ but this doesn't seem to be the case, probably because of + @ slow video memory we are dealing with + ldmia r1!, {r4-r11} + convRGB444 r4 + str r4, [r0], #4 + convRGB444 r5 + str r5, [r0], #4 + convRGB444 r6 + str r6, [r0], #4 + convRGB444 r7 + str r7, [r0], #4 + convRGB444 r8 + str r8, [r0], #4 + convRGB444 r9 + str r9, [r0], #4 + convRGB444 r10 + str r10, [r0], #4 + convRGB444 r11 + str r11, [r0], #4 + + bgt .loopRGB444 + + + ldmfd sp!, {r4-r11,lr} + bx lr + + +@ Convert 0000bbb0 ggg0rrr0 +@ to rrr00ggg 000bbb00 + +@ r2,r3 - scratch, lr = 0x07800780 +.macro convRGB565 reg + and r2, \reg, lr, lsr #7 @ r2=red + and r3, \reg, lr, lsl #1 @ r3=blue + and \reg, lr, \reg,lsl #3 @ green stays, but needs shifting + orr \reg, \reg, r2, lsl #12 @ add red back + orr \reg, \reg, r3, lsr #7 @ add blue back +.endm + +.global vidConvCpyRGB565 @ void *to, void *from, int pixels + +vidConvCpyRGB565: + stmfd sp!, {r4-r11,lr} + + mov r12, r2, lsr #4 @ repeats + mov lr, #0x07800000 + orr lr, lr, #0x780 @ lr == pattern 0x07800780 + +.loopRGB565: + subs r12, r12, #1 + + ldmia r1!, {r4-r11} + convRGB565 r4 + str r4, [r0], #4 + convRGB565 r5 + str r5, [r0], #4 + convRGB565 r6 + str r6, [r0], #4 + convRGB565 r7 + str r7, [r0], #4 + convRGB565 r8 + str r8, [r0], #4 + convRGB565 r9 + str r9, [r0], #4 + convRGB565 r10 + str r10, [r0], #4 + convRGB565 r11 + str r11, [r0], #4 + + bgt .loopRGB565 + + ldmfd sp!, {r4-r11,lr} + bx lr + + +@ Convert 0000bbb0 ggg0rrr0 0000bbb0 ggg0rrr0 +@ to 00000000 rrr00000 ggg00000 bbb00000 ... + +@ r2,r3 - scratch, lr = 0x0000F000 +@ rin - src reg, rout - dest reg (can be same for both; rout can be r3) +.macro convRGB32_l rout rin + and r2, \rin, lr, lsr #12 @ r2=red + and r3, \rin, lr, lsr #4 @ r3=blue + orr r2, r3, r2, lsl #24 + and \rout, lr, \rin, lsl #8 @ green stays, but needs shifting + orr \rout, \rout, r2, lsr #4 @ add red+blue back +.endm + +@ r2,r3 - scratch, lr = 0x0000F000 +@ rin - src reg, rout - dest reg (can be same for both; rout can be r3) +.macro convRGB32_h rout rin + and r2, \rin, lr, lsl #4 @ r2=red + mov r3, \rin, lsr #24 @ r3=blue + orr r2, r3, r2 + and \rout, lr, \rin, lsr #8 @ green + orr \rout, \rout, r2, lsl #4 +.endm + +@ slightly faster conversion, saves 1 opcode, writes output +@ lr = 0x00F000F0, out: r3=lower_pix, r2=higher_pix; trashes rin +.macro convRGB32_2 rin rethigh=0 + and r2, lr, \rin, lsr #4 @ blue + and r3, \rin, lr + orr r2, r2, r3, lsl #8 @ g0b0g0b0 + + mov r3, r2, lsl #16 @ g0b00000 + and \rin,lr, \rin, ror #12 @ 00r000r0 (reversed) + orr r3, r3, \rin, lsr #16 @ g0b000r0 + mov r3, r3, ror #16 @ r3=low + + str r3, [r0], #4 + + mov r2, r2, lsr #16 +.if \rethigh + orr \rin,r2, \rin, lsl #16 +.else + orr r2, r2, \rin, lsl #16 + str r2, [r0], #4 +.endif +.endm + + +.global vidConvCpyRGB32 @ void *to, void *from, int pixels + +vidConvCpyRGB32: + stmfd sp!, {r4-r7,lr} + + mov r12, r2, lsr #3 @ repeats + mov lr, #0x00F00000 + orr lr, lr, #0x00F0 + +.loopRGB32: + subs r12, r12, #1 + + ldmia r1!, {r4-r7} + convRGB32_2 r4 + convRGB32_2 r5 + convRGB32_2 r6 + convRGB32_2 r7 + + bgt .loopRGB32 + + ldmfd sp!, {r4-r7,lr} + bx lr + + +@ -------- M2 stuff --------- + +.bss +tmpstore1d: .long + +.text +tmpstore1: .long tmpstore1d + + +@ r3 - scratch, ru - reg with 2 pixels from upper col, rl - ... lower col +.macro rot_str16_90 ru rl + mov r3, \rl,lsl #16 + mov r3, r3, lsr #16 + orr r3, r3, \ru, lsl #16 + str r3, [r0], #208*2 + mov r3, \ru,lsr #16 + mov r3, r3, lsl #16 + orr r3, r3, \rl, lsr #16 + str r3, [r0], #208*2 +.endm + + +.global vidConvCpyM2_16_90 @ void *to, void *from, int width + +vidConvCpyM2_16_90: + stmfd sp!, {r4-r11,lr} + + ldr r4, =tmpstore1 + str sp, [r4] @ save sp, we will need sp reg.. + mov sp, r0 @ .. to store our dst + + @ crashing beyond this point will be fatal (phone reboots), as Symbian OS expects sp to always point to stack + + sub r2, r2, #1 + mov r12, #0x00670000 + orr r12, r12, r2, lsl #24 + orr r12, r12, r2 @ r12 == ((208-2)/2 << 16) | ((width-1)<<24) | (width-1) + + add r0, r0, #206*2 + add r1, r1, #8*2 @ skip left border + add lr, r1, #328*2 + +.loopM2_16_90: + subs r12, r12, #1<<24 + + ldmia r1!, {r4-r7} + ldmia lr!, {r8-r11} + rot_str16_90 r4 r8 + rot_str16_90 r5 r9 + rot_str16_90 r6 r10 + rot_str16_90 r7 r11 + + bpl .loopM2_16_90 + + add r12, r12, #1<<24 + subs r12, r12, #0x00010000 + bmi .loopM2_16_90_end + + add r0, sp, r12, lsr #14 @ calculate new dst pointer + orr r12, r12, r12, lsl #24 @ restore the width counter + + @ skip remaining pixels on these 2 lines + mov r4, #328/8-1 @ width of mode2 in line_pixels/8 + sub r4, r4, r12, lsr #24 + add r1, lr, r4, lsl #4 @ skip src pixels + add lr, r1, #328*2 + b .loopM2_16_90 + +.loopM2_16_90_end: + @ restore sp + ldr r4, =tmpstore1 + ldr sp, [r4] + + ldmfd sp!, {r4-r11,lr} + bx lr + + + +@ r3 - scratch, ru - reg with 2 pixels from upper col, rl - ... lower col (for right-to-left copies) +.macro rot_str16_270 ru rl + mov r3, \rl,lsr #16 + mov r3, r3, lsl #16 + orr r3, r3, \ru, lsr #16 + str r3, [r0], #208*2 + mov r3, \ru,lsl #16 + mov r3, r3, lsr #16 + orr r3, r3, \rl, lsl #16 + str r3, [r0], #208*2 +.endm + + +.global vidConvCpyM2_16_270 @ void *to, void *from, int width + +vidConvCpyM2_16_270: + stmfd sp!, {r4-r11,lr} + + ldr r4, =tmpstore1 + str sp, [r4] @ save sp, we will need sp reg to store our dst + + sub r2, r2, #1 + mov r12, #0x00670000 + orr r12, r12, r2, lsl #24 + orr r12, r12, r2 @ r12 == ((208-2)/2 << 16) | ((width-1)<<24) | (width-1) + + add r1, r1, #328*2 @ skip left border+1line + add lr, r1, #328*2 + add sp, r0, #206*2 @ adjust for algo + +.loopM2_16_270: + subs r12, r12, #1<<24 + + ldmdb r1!, {r4-r7} + ldmdb lr!, {r8-r11} + rot_str16_270 r7 r11 @ update the screen in incrementing direction, reduces tearing slightly + rot_str16_270 r6 r10 + rot_str16_270 r5 r9 + rot_str16_270 r4 r8 + + bpl .loopM2_16_270 + + add r12, r12, #1<<24 + subs r12, r12, #0x00010000 + bmi .loopM2_16_90_end @ same end as in 90 + + sub r0, sp, r12, lsr #14 @ calculate new dst pointer + orr r12, r12, r12, lsl #24 @ restore the width counter + + @ skip remaining pixels on these 2 lines + mov r4, #328/8-1 @ width of mode2 in line_pixels/8 + sub r4, r4, r12, lsr #24 + sub r1, lr, r4, lsl #4 @ skip src pixels + add r1, r1, #328*2*2 + add lr, r1, #328*2 + b .loopM2_16_270 + + + +.global vidConvCpyM2_RGB32_90 @ void *to, void *from, int width + +vidConvCpyM2_RGB32_90: + stmfd sp!, {r4-r10,lr} + + mov lr, #0x00F00000 + orr lr, lr, #0x00F0 + + mov r12, #208/4 @ row counter + mov r10, r2, lsl #2 @ we do 2 pixel wide copies + + add r8, r0, #208*4 @ parallel line + add r1, r1, #0x21000 + add r1, r1, #0x00280 @ r1+=328*207*2+8*2 + mov r9, r1 + +.loopM2RGB32_90: + subs r12, r12, #1 + + @ at first this loop was written differently: src pixels were fetched with ldm's and + @ dest was not sequential. It ran nearly 2 times slower. It seems it is very important + @ to do sequential memory access on those items, which we have more (to offload addressing bus?). + + ldr r4, [r1], #-328*2 + ldr r5, [r1], #-328*2 + ldr r6, [r1], #-328*2 + ldr r7, [r1], #-328*2 + + convRGB32_2 r4, 1 + convRGB32_2 r5, 1 + convRGB32_2 r6, 1 + convRGB32_2 r7, 1 + + str r4, [r8], #4 + str r5, [r8], #4 + str r6, [r8], #4 + str r7, [r8], #4 + + bne .loopM2RGB32_90 + + subs r10, r10, #1 + ldmeqfd sp!, {r4-r10,pc} @ return + + mov r12, #208/4 @ restore row counter + mov r0, r8 @ set new dst pointer + add r8, r0, #208*4 + add r9, r9, #2*2 @ fix src pointer + mov r1, r9 + b .loopM2RGB32_90 + + + +@ converter for vidConvCpyM2_RGB32_270 +@ lr = 0x00F000F0, out: r3=lower_pix, r2=higher_pix; trashes rin +.macro convRGB32_3 rin + and r2, lr, \rin, lsr #4 @ blue + and r3, \rin, lr + orr r2, r2, r3, lsl #8 @ g0b0g0b0 + + mov r3, r2, lsl #16 @ g0b00000 + and \rin,lr, \rin, ror #12 @ 00r000r0 (reversed) + orr r3, r3, \rin, lsr #16 @ g0b000r0 + + mov r2, r2, lsr #16 + orr r2, r2, \rin, lsl #16 + str r2, [r0], #4 + + mov \rin,r3, ror #16 @ r3=low +.endm + + +.global vidConvCpyM2_RGB32_270 @ void *to, void *from, int width + +vidConvCpyM2_RGB32_270: + stmfd sp!, {r4-r10,lr} + + mov lr, #0x00F00000 + orr lr, lr, #0x00F0 + + mov r12, #208/4 @ row counter + mov r10, r2, lsl #2 @ we do 2 pixel wide copies (right to left) + + add r8, r0, #208*4 @ parallel line + add r1, r1, #326*2 + mov r9, r1 + +.loopM2RGB32_270: + subs r12, r12, #1 + + ldr r4, [r1], #328*2 + ldr r5, [r1], #328*2 + ldr r6, [r1], #328*2 + ldr r7, [r1], #328*2 + + convRGB32_3 r4 + convRGB32_3 r5 + convRGB32_3 r6 + convRGB32_3 r7 + + str r4, [r8], #4 + str r5, [r8], #4 + str r6, [r8], #4 + str r7, [r8], #4 + + bne .loopM2RGB32_270 + + subs r10, r10, #1 + ldmeqfd sp!, {r4-r10,pc} @ return + + mov r12, #208/4 @ restore row counter + mov r0, r8 @ set new dst pointer + add r8, r0, #208*4 + sub r9, r9, #2*2 @ fix src pointer + mov r1, r9 + b .loopM2RGB32_270 + diff --git a/platform/uiq2/debug.cpp b/platform/uiq2/debug.cpp new file mode 100644 index 00000000..efa60950 --- /dev/null +++ b/platform/uiq2/debug.cpp @@ -0,0 +1,241 @@ + +#include // RDebug +#include "debug.h" + +#ifdef __WINS__ + +void ExceptionHandler(TExcType exc) {} + +#else + +static const wchar_t * const exception_names[] = { + L"General", + L"IntegerDivideByZero", + L"SingleStep", + L"BreakPoint", + L"IntegerOverflow", + L"BoundsCheck", + L"InvalidOpCode", + L"DoubleFault", + L"StackFault", + L"AccessViolation", + L"PrivInstruction", + L"Alignment", + L"PageFault", + L"FloatDenormal", + L"FloatDivideByZero", + L"FloatInexactResult", + L"FloatInvalidOperation", + L"FloatOverflow", + L"FloatStackCheck", + L"FloatUnderflow", + L"Abort", + L"Kill", + L"DataAbort", + L"CodeAbort", + L"MaxNumber", + L"InvalidVector", + L"UserInterrupt", + L"Unknown" +}; + + +static void getASpace(TUint *code_start, TUint *code_end, TUint *stack_start, TUint *stack_end) +{ + TUint pc, sp; + RChunk chunk; + TFullName chunkname; + TFindChunk findChunk(_L("*")); + + asm volatile ("str pc, %0" : "=m" (pc) ); + asm volatile ("str sp, %0" : "=m" (sp) ); + + while( findChunk.Next(chunkname) != KErrNotFound ) { + chunk.Open(findChunk); + if((TUint)chunk.Base()+chunk.Bottom() < pc && pc < (TUint)chunk.Base()+chunk.Top()) { + if(code_start) *code_start = (TUint)chunk.Base()+chunk.Bottom(); + if(code_end) *code_end = (TUint)chunk.Base()+chunk.Top(); + } else + if((TUint)chunk.Base()+chunk.Bottom() < sp && sp < (TUint)chunk.Base()+chunk.Top()) { + if(stack_start) *stack_start = (TUint)chunk.Base()+chunk.Bottom(); + if(stack_end) *stack_end = (TUint)chunk.Base()+chunk.Top(); + } + chunk.Close(); + } +} + +// tmp +#if defined(__DEBUG_PRINT) +extern "C" char *debugString(); +#endif + +// our very own exception handler +void ExceptionHandler(TExcType exc) +{ + TUint lr, sp, i; + TUint stack_end = 0; // ending address of our stack chunk + TUint code_start = 0, code_end = 0; // starting and ending addresses of our code chunk + TUint guessed_address = 0; + + asm volatile ("str lr, %0" : "=m" (lr) ); + asm volatile ("str sp, %0" : "=m" (sp) ); + + // first get some info about the chunks we live in + getASpace(&code_start, &code_end, 0, &stack_end); + + // now we begin some black magic tricks + // we go up our stack until we pass our caller address + for(; sp < stack_end; sp += 4) + if(*(TUint *)sp == lr) break; + + // there might be mirored caller address + for(i = sp + 4; i < sp + 0x300 && i < stack_end; i += 4) + if(*(TUint *)i == lr) { sp = i; break; } + + // aah, it is always 0x9c bytes away from the caller address in my firmware, + // don't know how to detect it in any other way + sp += 0x9c; + guessed_address = *(TUint *)sp; + + // output the info + TUint exec_show = exc; + if(exec_show > 27) exec_show = 27; + TPtrC ptrExc((TUint16 *) exception_names[exec_show]); + + RDebug::Print(_L("!!!Exception %i (%S) @ 0x%08x (guessed; relative=0x%08x)"), exc, &ptrExc, guessed_address, guessed_address - code_start); +#ifdef __DEBUG_PRINT_FILE + DEBUGPRINT( _L("!!!Exception %i (%S) @ 0x%08x (guessed; relative=0x%08x)"), exc, &ptrExc, guessed_address, guessed_address - code_start); +#endif + + TBuf<148> buff1; + TBuf<10> buff2; + buff1.Copy(_L(" guessed stack: ")); + + for(sp += 4, i = 0; i < 5 && sp < stack_end; sp += 4) { + if((*(TUint *)sp >> 28) == 5) { + if(i++) buff1.Append(_L(", ")); + buff2.Format(_L("0x%08x"), *(TUint *)sp); + buff1.Append(buff2); + } + else if(code_start < *(TUint *)sp && *(TUint *)sp < code_end) { + if(i++) buff1.Append(_L(", ")); + buff2.Format(_L("0x%08x"), *(TUint *)sp); + buff1.Append(buff2); + buff1.Append(_L(" (")); + buff2.Format(_L("0x%08x"), *(TUint *)sp - code_start); + buff1.Append(buff2); + buff1.Append(_L(")")); + } + } + RDebug::Print(_L("%S"), &buff1); +#ifdef __DEBUG_PRINT_FILE + DEBUGPRINT(_L("%S"), &buff1); +#endif + + // tmp +#if defined(__DEBUG_PRINT) + char *ps, *cstr = debugString(); + for(ps = cstr; *ps; ps++) { + if(*ps == '\n') { + *ps = 0; + dprintf(cstr); + cstr = ps+1; + } + } +#endif + +// RDebug::Print(_L("Stack dump:")); +// asm volatile ("str sp, %0" : "=m" (sp) ); +// for(TUint i = sp+0x400; i >= sp-16; i-=4) +// RDebug::Print(_L("%08x: %08x"), i, *(int *)i); + + // more descriptive replacement of "KERN-EXEC 3" panic + buff1.Format(_L("K-EX3: %S"), &ptrExc); + User::Panic(buff1, exc); +} + +#endif // ifdef __WINS__ + + +#if defined(__DEBUG_PRINT) || defined(__WINS__) + +#ifndef __DLL__ + // c string dumper for RDebug::Print() + static TBuf<1024> sTextBuffer; + TDesC* DO_CONV(const char* s) + { + TPtrC8 text8((TUint8*) (s)); + sTextBuffer.Copy(text8); + return &sTextBuffer; + } +#endif + +#ifdef __DEBUG_PRINT_C + #include // va_* + #include // vsprintf + + // debug print from c code + extern "C" void dprintf(char *format, ...) + { + va_list args; + char buffer[512]; + + va_start(args,format); + vsprintf(buffer,format,args); + va_end(args); + + DEBUGPRINT(_L("%S"), DO_CONV(buffer)); + } +#endif + +#ifdef __DEBUG_PRINT_FILE + #include + + // note: uses tls, leaks some mem + void debugPrintFileInit() + { + RFs *fs = new(ELeave) RFs; + fs->Connect(); + RFile *file = new(ELeave) RFile; + // try to open + TInt res = file->Open(*fs, _L("C:\\documents\\Media files\\other\\snes9x.log"), EFileWrite|EFileShareAny); + if(res) res = file->Open(*fs, _L("C:\\snes9x.log"), EFileWrite|EFileShareAny); + if(!res) { TInt size; file->Size(size); file->Seek(ESeekStart, size); } + // try to create + if(res) res = file->Create(*fs, _L("C:\\documents\\Media files\\other\\snes9x.log"), EFileWrite|EFileShareAny); + if(res) res = file->Create(*fs, _L("C:\\snes9x.log"), EFileWrite|EFileShareAny); + Dll::SetTls(res ? 0 : file); + } + + // debug print to file + void debugPrintFile(TRefByValue aFmt, ...) + { + // get RFile + RFile *file = (RFile *) Dll::Tls(); + if(!file) return; // shit! + + TTime now; now.UniversalTime(); + TBuf<512> tmpBuff; + TBuf8<512> tmpBuff8; + TInt size; + + file->Size(size); file->Seek(ESeekStart, size); // something else could have written to the file + + now.FormatL(tmpBuff, _L("%H:%T:%S.%C: ")); + tmpBuff8.Copy(tmpBuff); + file->Write(tmpBuff8); + + VA_LIST args; + VA_START(args, aFmt); + tmpBuff.FormatList(aFmt, args); + VA_END(args); + tmpBuff8.Copy(tmpBuff); + file->Write(tmpBuff8); + + file->Write(TPtrC8((TUint8 const *) "\r\n")); + file->Flush(); + } +#endif + +#endif + diff --git a/platform/uiq2/debug.h b/platform/uiq2/debug.h new file mode 100644 index 00000000..b91ce268 --- /dev/null +++ b/platform/uiq2/debug.h @@ -0,0 +1,27 @@ +#include + +#define __DEBUG_PRINT_C + +#if defined(__DEBUG_PRINT) || defined(__WINS__) + #include // RDebug + #ifdef __DEBUG_PRINT_FILE + void debugPrintFileInit(); + void debugPrintFile(TRefByValue aFmt, ...); + #define DEBUG_PRINT_FILE_INIT debugPrintFileInit + #define DEBUGPRINT debugPrintFile + #else + #define DEBUG_PRINT_FILE_INIT() + #define DEBUGPRINT RDebug::Print + #endif + TDesC* DO_CONV(const char* s); + #ifdef __DEBUG_PRINT_C + #ifdef __cplusplus + extern "C" + #endif + void dprintf(char *format, ...); + #endif +#else + #define DEBUGPRINT(x...) +#endif + +void ExceptionHandler(TExcType exc); diff --git a/platform/uiq2/launcher/App.cpp b/platform/uiq2/launcher/App.cpp new file mode 100644 index 00000000..78367640 --- /dev/null +++ b/platform/uiq2/launcher/App.cpp @@ -0,0 +1,644 @@ +/******************************************************************* + * + * File: App.cpp + * + * Author: Peter van Sebille (peter@yipton.net) + * + * Modified/adapted for picodriveN by notaz, 2006 + * + * (c) Copyright 2006, notaz + * (c) Copyright 2002, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +#include "app.h" +// #include "picodriven.mbg" // bitmap identifiers +#include "picodriven.rsg" +#include +#include +//#include +//#include +#include // CEikMenuBar +#include // TApaSystemEvent + +#include "Dialogs.h" + + +CApaDocument* CPicolApplication::CreateDocumentL() +{ + return new (ELeave) CPicolDocument(*this); +} + + +CPicolDocument::CPicolDocument(CEikApplication& aApp) + : CEikDocument(aApp) +{ +} + +CPicolDocument::~CPicolDocument() +{ +} + +CEikAppUi* CPicolDocument::CreateAppUiL() +{ + return new(ELeave) CPicolAppUi; +} + + +//////////////////////////////////////////////////////////////// +// +// class CPicolAppUi +// +//////////////////////////////////////////////////////////////// + +CPicolAppUi::CPicolAppUi() +: iCurrentLConfig(iCurrentConfig) +{ + // set default config + Mem::FillZ(&iCurrentConfig, sizeof(iCurrentConfig)); + iCurrentConfig.iFlags = 1; // use_sram + iCurrentConfig.iFrameskip = TPicoConfig::PFSkipAuto; + iCurrentConfig.iScreenRotation = TPicoConfig::PRot90; +} + +CPicolAppUi::~CPicolAppUi() +{ + delete iAppView; + DeregisterView(*iFOView); + delete iFOView; + DeregisterView(*iFCView); + delete iFCView; +} + +void CPicolAppUi::ConstructL() +{ + BaseConstructL(); + + // load config + iCurrentLConfig.Load(); + + iAppView=new(ELeave) CEPicolAppView; + iAppView->ConstructL(ClientRect()); + + iFOView=new(ELeave) CPicolFOView(*iAppView); + RegisterViewL(*iFOView); + iFCView=new(ELeave) CPicolFCView(*iAppView); + RegisterViewL(*iFCView); +} + + +void CPicolAppUi::HandleCommandL(TInt aCommand) +{ + TInt oldFrameskip = iCurrentConfig.iFrameskip; + TInt res; + + // give time for config dialog destruction + if(iAfterConfigDialog) { + iAfterConfigDialog = EFalse; + TTime now; now.UniversalTime(); + if(now.MicroSecondsFrom(iConfigDialogClosed).Int64().Low() < 2500*1000) + User::After(2500*1000-now.MicroSecondsFrom(iConfigDialogClosed).Int64().Low()); + } + + switch (aCommand) + { + case EEikCmdPicoLoadState: + if(iGameRunner) { + CEikonEnv::Static()->BusyMsgL(_L("Loading State")); + res = ss.SendReceive(PicoMsgLoadState, 0); + CEikonEnv::Static()->BusyMsgCancel(); + // emu doesn't start to run if load fails, so we can display this + if(res) CEikonEnv::Static()->InfoMsg(_L("Load Failed")); + } + break; + + case EEikCmdPicoSaveState: + if(iGameRunner) { + CEikonEnv::Static()->BusyMsgL(_L("Saving State")); + res = ss.SendReceive(PicoMsgSaveState, 0); + CEikonEnv::Static()->BusyMsgCancel(); + if(res) CEikonEnv::Static()->InfoMsg(_L("Save Failed")); + } + break; + + case EEikCmdPicoLoadROM: + DisplayOpenROMDialogL(); + break; + + case EEikCmdPicoResume: + ss.Send(PicoMsgResume, 0); + iEmuRunning = ETrue; + break; + + case EEikCmdPicoReset: + ss.Send(PicoMsgReset, 0); + iEmuRunning = ETrue; + break; + + case EEikCmdPicoKeys: + if(!iGameRunner) RunGameL(); + ss.Send(PicoMsgKeys, 0); + iEmuRunning = ETrue; + break; + + case EEikCmdPicoSettings: + DisplayConfigDialogL(); + break; + + case EEikCmdHelpAbout: // EEikCmdPicoAbout: + DisplayAboutDialogL(); + break; + + // standard identifier must be used here, TApaTask::EndTask() and probably others send it + case EEikCmdExit: // EEikCmdPicoExit: + if(iGameRunner) { + iQuitting = ETrue; + iExitForcer = CExitForcer::NewL(*this, 2000); + ss.Send(PicoMsgQuit, 0); + } else { + iCurrentLConfig.Save(); + DEBUGPRINT(_L("[app] Exit (menu)")); + Exit(); + } + break; + + // frameskips + case EEikCmdPicoFrameskipAuto: + iCurrentConfig.iFrameskip = TPicoConfig::PFSkipAuto; + break; + + case EEikCmdPicoFrameskip0: + iCurrentConfig.iFrameskip = TPicoConfig::PFSkip0; + break; + + case EEikCmdPicoFrameskip1: + iCurrentConfig.iFrameskip = 1; + break; + + case EEikCmdPicoFrameskip2: + iCurrentConfig.iFrameskip = 2; + break; + + case EEikCmdPicoFrameskip4: + iCurrentConfig.iFrameskip = 4; + break; + + case EEikCmdPicoFrameskip8: + iCurrentConfig.iFrameskip = 8; + break; + + case EEikCmdPicoDebugKillEmu: + if(iGameRunner) { + iExitForcer = CExitForcer::NewL(*this, 4000); + ss.Send(PicoMsgQuit, 0); + } + break; + + case EEikCmdPicoDebugInfo: + if(iGameRunner) + DisplayDebugDialogL(); + break; + } + + // send config update if needed + if(iCurrentConfig.iFrameskip != oldFrameskip) + SendConfig(); +} + + +void CPicolAppUi::HandleSystemEventL(const TWsEvent& aEvent) +{ + TApaSystemEvent event; + event = *(TApaSystemEvent*)aEvent.EventData(); + + if(event == EApaSystemEventBroughtToForeground) // application brought to foreground + { + DEBUGPRINT(_L("[app] EApaSystemEventBroughtToForeground, iEmuRunning=%i"), iEmuRunning); + // we might have missed flip open event (when moved to background), + // so make sure we have correct view active + if(iCoeEnv->ScreenDevice()->CurrentScreenMode() == EScreenModeFlipOpen) { + ActivateViewL(TVwsViewId(KUidPicolApp, KUidPicolFOView)); + return; + } + } + if(event == EApaSystemEventShutdown) + { + DEBUGPRINT(_L("[app] EApaSystemEventShutdown")); + } + + CEikAppUi::HandleSystemEventL(aEvent); +} + + +// called just before the menu is shown +void CPicolAppUi::DynInitMenuPaneL(TInt aResourceId, CEikMenuPane* aMenuPane) +{ + if(aResourceId == R_APP_EMU_MENU) { + TBool dimmed = !iGameRunner || !iROMLoaded; + aMenuPane->SetItemDimmed(EEikCmdPicoLoadState, dimmed); + aMenuPane->SetItemDimmed(EEikCmdPicoSaveState, dimmed); + aMenuPane->SetItemDimmed(EEikCmdPicoResume, dimmed); + aMenuPane->SetItemDimmed(EEikCmdPicoReset, dimmed); + } else if(aResourceId == R_APP_FRAMESKIP_MENU) { + TInt itemToCheck = EEikCmdPicoFrameskipAuto; + switch(iCurrentConfig.iFrameskip) { + case 0: itemToCheck = EEikCmdPicoFrameskip0; break; + case 1: itemToCheck = EEikCmdPicoFrameskip1; break; + case 2: itemToCheck = EEikCmdPicoFrameskip2; break; + case 4: itemToCheck = EEikCmdPicoFrameskip4; break; + case 8: itemToCheck = EEikCmdPicoFrameskip8; break; + } + aMenuPane->SetItemButtonState(itemToCheck, EEikMenuItemSymbolOn); + } +} + + +void CPicolAppUi::DisplayAboutDialogL() +{ + CEikDialog* dialog = new(ELeave) CAboutDialog; + TInt iButtonRes = dialog->ExecuteLD(R_DIALOG_ABOUT); + if(iButtonRes == EEikBidYes) { + CCreditsDialog *creditsDialog = new (ELeave) CCreditsDialog(); + creditsDialog->iMessageResourceID = R_TBUF_CREDITS; + creditsDialog->ExecuteLD(R_DIALOG_CREDITS); + } +} + + +void CPicolAppUi::DisplayOpenROMDialogL() +{ + + TFileName file(iCurrentLConfig.iLastROMFile); + CEikDialog* dialog = new(ELeave) CEikFileOpenDialog(&file); + //((CEikFileOpenDialog *)dialog)->SetRequiredExtension(&ext); + + if(dialog->ExecuteLD(R_EIK_DIALOG_FILE_OPEN) == EEikBidOk) { + CEikonEnv::Static()->BusyMsgL(_L("Loading ROM")); + + // start emu process if it is not running + if(!iGameRunner) RunGameL(); + iROMLoaded = EFalse; + + TBuf8 file8; + file8.Copy(file); + TAny *p[KMaxMessageArguments]; + p[0]= (TAny*)(&file8); + TInt res = ss.SendReceive(PicoMsgLoadROM, &p[0]); + + CEikonEnv::Static()->BusyMsgCancel(); + + if(res == 1) + CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed to open file.")); + else if(res == 2) + CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed to allocate memory.")); + else if(res == 3) + CEikonEnv::Static()->InfoWinL(_L("Error"), _L("The file you selected is not a game ROM.")); + else if(res == 4) + CEikonEnv::Static()->InfoWinL(_L("Error"), _L("No game ROMs found in zipfile.")); + else if(res == 5) + CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed while unzipping ROM.")); + else if(res < 0) + CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed to send request to emu process.")); + else { + iROMLoaded = ETrue; + iEmuRunning = ETrue; + } + + // sound errors which leave ROM loaded + if(res == 6) + CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed to allocate sound buffer, disabled sound.")); + else if(res == 7) + CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed to start soundsystem, disabled sound.")); + if(res == 6 || res == 7) iCurrentConfig.iFlags &= ~4; + + iCurrentLConfig.iLastROMFile.Copy(file); + } +} + + +void CPicolAppUi::DisplayConfigDialogL() +{ + CPicoConfigDialog* configDialog = new(ELeave)CPicoConfigDialog(iCurrentConfig, iCurrentLConfig); + configDialog->ExecuteLD(R_PICO_CONFIG); + + if(iGameRunner) + SendConfig(); + + iCurrentLConfig.Save(); + + // configDialog seems to be actually destroyed later after returning, + // and this usually happens just after resuming game and causes emu slowdowns :/ + iAfterConfigDialog = ETrue; + iConfigDialogClosed.UniversalTime(); +} + + +void CPicolAppUi::DisplayDebugDialogL() +{ + // first get our debug info + char dtxt[1024]; + + TAny *p[KMaxMessageArguments]; + TPtr8 descr((TUint8*) dtxt, sizeof(dtxt)); + p[0]= (TAny*)(&descr); + ss.SendReceive(PicoMsgRetrieveDebugStr, &p[0]); + + CEikDialog* dialog = new(ELeave) CDebugDialog(dtxt); + dialog->ExecuteLD(R_DIALOG_DEBUG); +} + + +void CPicolAppUi::SendConfig() +{ + // send config + if(iGameRunner) { + TAny *p[KMaxMessageArguments]; + TPtrC8 descr((TUint8*) &iCurrentConfig, sizeof(iCurrentConfig)); + p[0]= (TAny*)(&descr); + ss.Send(PicoMsgConfigChange, &p[0]); + } +} + + +// get config from emu proc +void CPicolAppUi::RetrieveConfig() +{ + // ask to configure keys and receive new config + TAny *p[KMaxMessageArguments]; + TPtr8 descr((TUint8*) &iCurrentConfig, sizeof(iCurrentConfig)); + p[0]= (TAny*)(&descr); + ss.SendReceive(PicoMsgRetrieveConfig, &p[0]); + + iCurrentLConfig.Save(); +} + + +void CPicolAppUi::NotifyEmuDeath() +{ + StopGame(); + if(iQuitting) { + DEBUGPRINT(_L("[app] Exit (NotifyEmuDeath)")); + iCurrentLConfig.Save(); + RProcess me; + me.Terminate(0); + } +} + + +void CPicolAppUi::NotifyForcedExit() +{ + DEBUGPRINT(_L("[app] Exit (NotifyForcedExit)")); + StopGame(); + RProcess me; + me.Terminate(0); +} + + +TBool CPicolAppUi::EmuRunning() const +{ + return iEmuRunning; +} + + +void CPicolAppUi::StopGame() +{ + // in case we have busyMsg and process crashes + CEikonEnv::Static()->BusyMsgCancel(); + + ss.Close(); + if(iGameRunner) delete iGameRunner; + iGameRunner = NULL; + if(iExitForcer) delete iExitForcer; + iExitForcer = NULL; + if(iThreadWatcher1) delete iThreadWatcher1; + iThreadWatcher1 = NULL; + iROMLoaded = EFalse; + iEmuRunning = EFalse; +} + + +void CPicolAppUi::RunGameL() +{ + TInt res = KErrNone; + + // do one connection attemt to emu and ask it to quit if we succeed + res = ss.Connect(); + if(res == KErrNone) { + ss.Send(PicoMsgQuit, 0); + ss.Close(); + } + + iGameRunner = CGameRunner::NewL(*this); + + // Connect to the server + // we don't want to do complex asynchronous stuff here, so we just + // wait and do several connection attempts + User::After(200000); + for(TInt attempt=0; attempt < 10; attempt++) { + res = ss.Connect(); + if(res == KErrNone) break; + User::After(200000); + } + + if(res != KErrNone) { + CEikonEnv::Static()->BusyMsgCancel(); + CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed to communicate with the emulation process.")); + StopGame(); + RProcess me; + me.Terminate(2); + } + + // now we are successfully connected, that means emu process' helper-communication thread is running. + // we have to keep an eye on it too, because if it crashes, symbian OS leaves it's process + // alive, but it becomes useless without it's communication thread so we have to detect it's death. + iThreadWatcher1 = CThreadWatcher::NewL(*this, KServerName); + + // send initial config + SendConfig(); +} + + +/* +void CPicolAppUi::HandleScreenDeviceChangedL() +{ + // does not receive when emu is in foreground + if(iCoeEnv->ScreenDevice()->CurrentScreenMode() == 0) { // flip open + // regain focus + //iCoeEnv->BringOwnerToFront(); + + } +// ss.Send(PicoMsgFlipChange, 0); +} +*/ + +void CPicolAppUi::HandleApplicationSpecificEventL(TInt aType, const TWsEvent& aEvent) +{ + DEBUGPRINT(_L("[app] event from server: %i"), aEvent.Type()); + + switch (aEvent.Type()) + { + case EEventKeyCfgDone: + RetrieveConfig(); + break; + + case EEventGamePaused: + iEmuRunning = EFalse; + break; + } +} + +//////////////////////////////////////////////////////////////// +// +// class CEPicolAppView +// +//////////////////////////////////////////////////////////////// + +void CEPicolAppView::ConstructL(const TRect& aRect) +{ + CreateWindowL(); + SetRect(aRect); + ActivateL(); + + /* + * Load background image + */ +/* + TBuf<1> name = _L("*"); + TRAPD(err, iBgImage = CEikonEnv::Static()->CreateBitmapL(name, EMbmEdoomDoom)); + if (iBgImage) + { + iImagePosition.iX = (aRect.Size().iWidth - iBgImage->SizeInPixels().iWidth) / 2; + iImagePosition.iY = (aRect.Size().iHeight - iBgImage->SizeInPixels().iHeight) / 2; + } +*/ +} + +CEPicolAppView::~CEPicolAppView() +{ + //if (iBgImage) delete iBgImage; +} + + +void CEPicolAppView::Draw(const TRect& aRect) const +{ + CWindowGc& gc = SystemGc(); + + //if (iBgImage) + //{ + // gc.DrawBitmap(iImagePosition, iBgImage); + // DrawUtils::ClearBetweenRects(gc, Rect(), TRect(iImagePosition, iBgImage->SizeInPixels())); + //} + //else + gc.Clear();//aRect); +} + + +//////////////////////////////////////////////////////////////// +// +// class CPicolViewBase +// +//////////////////////////////////////////////////////////////// + +void CPicolViewBase::ViewActivatedL(const TVwsViewId& /*aPrevViewId*/, TUid /*aCustomMessageId*/, const TDesC8& /*aCustomMessage*/) +{ + TPixelsAndRotation sizeAndRotation; + CEikonEnv::Static()->ScreenDevice()->GetDefaultScreenSizeAndRotation(sizeAndRotation); + CEikonEnv::Static()->ScreenDevice()->SetScreenSizeAndRotation(sizeAndRotation); + //iAppViewCtl.MakeVisible(ETrue); +} + +void CPicolViewBase::ViewDeactivated() +{ + //iAppViewCtl.MakeVisible(EFalse); +} + + +//////////////////////////////////////////////////////////////// +// +// class CPicolFOView +// +//////////////////////////////////////////////////////////////// + +TVwsViewId CPicolFOView::ViewId() const +{ + return TVwsViewId(KUidPicolApp, KUidPicolFOView); +} + +TVwsViewIdAndMessage CPicolFOView::ViewScreenDeviceChangedL() +{ + // only handle change to FC mode when emu process is running + if(static_cast(CEikonEnv::Static()->AppUi())->EmuRunning()) + return TVwsViewIdAndMessage(TVwsViewId(KUidPicolApp, KUidPicolFCView)); + else return MCoeView::ViewScreenDeviceChangedL(); +} + +TBool CPicolFOView::ViewScreenModeCompatible(TInt aScreenMode) +{ + return (aScreenMode == EScreenModeFlipOpen); +} + +void CPicolFOView::ViewActivatedL(const TVwsViewId& aPrevViewId, TUid aCustomMessageId, const TDesC8& aCustomMessage) +{ + DEBUGPRINT(_L("[app] FO")); + CPicolViewBase::ViewActivatedL(aPrevViewId, aCustomMessageId, aCustomMessage); + CEikonEnv::Static()->AppUiFactory()->MenuBar()->MakeVisible(ETrue); + + iAppViewCtl.SetRect(static_cast(CEikonEnv::Static()->AppUi())->ClientRect()); +} + + +//////////////////////////////////////////////////////////////// +// +// class CPicolFCView +// +//////////////////////////////////////////////////////////////// + +TVwsViewId CPicolFCView::ViewId() const +{ + return TVwsViewId(KUidPicolApp, KUidPicolFCView); +} + +TVwsViewIdAndMessage CPicolFCView::ViewScreenDeviceChangedL() +{ + return TVwsViewIdAndMessage(TVwsViewId(KUidPicolApp, KUidPicolFOView)); +} + +TBool CPicolFCView::ViewScreenModeCompatible(TInt aScreenMode) +{ + return (aScreenMode == EScreenModeFlipClosed); +} + +void CPicolFCView::ViewActivatedL(const TVwsViewId& aPrevViewId, TUid aCustomMessageId, const TDesC8& aCustomMessage) +{ + DEBUGPRINT(_L("[app] FC")); + CPicolViewBase::ViewActivatedL(aPrevViewId, aCustomMessageId, aCustomMessage); + CEikonEnv::Static()->AppUiFactory()->MenuBar()->MakeVisible(EFalse); + //iAppViewCtl.ChangeLayout(ETrue); + iAppViewCtl.SetRect(CEikonEnv::Static()->ScreenDevice()->SizeInPixels()); +} + + +//////////////////////////////////////////////////////////////// +// +// framework +// +//////////////////////////////////////////////////////////////// + +GLDEF_C TInt E32Dll(TDllReason) +{ + return KErrNone; +} + + +EXPORT_C CApaApplication* NewApplication() +{ + return new CPicolApplication; +} + + +TUid CPicolApplication::AppDllUid() const +{ + return KUidPicolApp; +} + diff --git a/platform/uiq2/launcher/App.h b/platform/uiq2/launcher/App.h new file mode 100644 index 00000000..1ac65265 --- /dev/null +++ b/platform/uiq2/launcher/App.h @@ -0,0 +1,178 @@ +/******************************************************************* + * + * File: App.h + * + * Author: Peter van Sebille (peter@yipton.net) + * + * Modified/adapted for picodriveN by notaz, 2006 + * + * (c) Copyright 2006, notaz + * (c) Copyright 2001, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +#ifndef __APP_H +#define __APP_H + +#include +#include +#include + +#include +#include +#include + +#include "Engine.h" +#include "../ClientServer.h" +#include "SimpleClient.h" +#include "picodriven.hrh" + +const TUid KUidPicolApp = { 0x1000C193 }; +const TUid KUidPicolFOView = { 0x1000C194 }; +const TUid KUidPicolFCView = { 0x1000C195 }; + +enum +{ + EScreenModeFlipOpen = 0, + EScreenModeFlipClosed +}; + + +//class CWsBitmap; + + +class CPicolDocument : public CEikDocument +{ +public: + ~CPicolDocument(); + CPicolDocument(CEikApplication& aApp); + void ConstructL(); + +private: // from CEikDocument + CEikAppUi* CreateAppUiL(); +}; + + +class CEPicolAppView : public CCoeControl // , public MCoeControlBrushContext +{ +public: + ~CEPicolAppView(); + void ConstructL(const TRect& aRect); + +private: + void Draw(const TRect& aRect) const; + + //CWsBitmap* iBgImage; + //TPoint iImagePosition; +}; + + +class CPicolViewBase : public CBase, public MCoeView +{ + public: + + CPicolViewBase(CEPicolAppView& aAppViewCtl) : iAppViewCtl(aAppViewCtl) {} + //~CPicolViewBase(); + + protected: + + // implements MCoeView: + virtual void ViewActivatedL(const TVwsViewId& /*aPrevViewId*/, TUid /*aCustomMessageId*/, const TDesC8& /*aCustomMessage*/); + virtual void ViewDeactivated(); + //virtual void ViewConstructL(); + + CEPicolAppView& iAppViewCtl; +}; + + +class CPicolFOView : public CPicolViewBase +{ + public: + + CPicolFOView(CEPicolAppView& aAppViewCtl) : CPicolViewBase(aAppViewCtl) {} + //~CPicolFOView(); + virtual TVwsViewId ViewId() const; + virtual TVwsViewIdAndMessage ViewScreenDeviceChangedL(); + virtual TBool ViewScreenModeCompatible(TInt aScreenMode); + virtual void ViewActivatedL(const TVwsViewId& /*aPrevViewId*/, TUid /*aCustomMessageId*/, const TDesC8& /*aCustomMessage*/); +}; + + +class CPicolFCView : public CPicolViewBase +{ + public: + + CPicolFCView(CEPicolAppView& aAppViewCtl) : CPicolViewBase(aAppViewCtl) {} + //~CPicolFCView(); + virtual TVwsViewId ViewId() const; + virtual TVwsViewIdAndMessage ViewScreenDeviceChangedL(); + virtual TBool ViewScreenModeCompatible(TInt aScreenMode); + virtual void ViewActivatedL(const TVwsViewId& /*aPrevViewId*/, TUid /*aCustomMessageId*/, const TDesC8& /*aCustomMessage*/); +}; + + + +class CPicolAppUi : public CEikAppUi, public MGameWatcher +{ +public: + CPicolAppUi(); + void ConstructL(); + ~CPicolAppUi(); + +public: // implements MGameWatcher + void NotifyEmuDeath(); + void NotifyForcedExit(); + + TBool EmuRunning() const; + +protected: // from CEikAppUi + void HandleCommandL(TInt aCommand); + void DynInitMenuPaneL(TInt aResourceId,CEikMenuPane* aMenuPane); + void HandleSystemEventL(const TWsEvent& aEvent); + +protected: // new stuf + void DisplayAboutDialogL(); + void DisplayOpenROMDialogL(); + void DisplayConfigDialogL(); + void DisplayDebugDialogL(); + + void StopGame(); + void RunGameL(); + void SendConfig(); + void RetrieveConfig(); + + CGameRunner* iGameRunner; + CExitForcer* iExitForcer; // makes sure emu process exits + CThreadWatcher* iThreadWatcher1; // emu process helper thread watcher + RServSession ss; + +private: + //void HandleScreenDeviceChangedL(); + //void HandleWsEventL(const TWsEvent& aEvent, CCoeControl* aDestination); + virtual void HandleApplicationSpecificEventL(TInt aType, const TWsEvent& aEvent); + +private: + TBool iQuitting; + TBool iROMLoaded; + TBool iEmuRunning; + TBool iAfterConfigDialog; + TTime iConfigDialogClosed; + TPicoConfig iCurrentConfig; + TPLauncherConfig iCurrentLConfig; + + CEPicolAppView* iAppView; + CPicolFOView* iFOView; + CPicolFCView* iFCView; +}; + + + +class CPicolApplication : public CEikApplication +{ +private: // from CApaApplication + CApaDocument* CreateDocumentL(); + TUid AppDllUid() const; +}; + +#endif diff --git a/platform/uiq2/launcher/CSimpleTextParser.cpp b/platform/uiq2/launcher/CSimpleTextParser.cpp new file mode 100644 index 00000000..865e35ee --- /dev/null +++ b/platform/uiq2/launcher/CSimpleTextParser.cpp @@ -0,0 +1,477 @@ +/******************************************************************* + * + * File: CSimpleTextParser.cpp + * + * Author: Peter van Sebille (peter@yipton.net) + * + * (c) Copyright 2002, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +#include "CSimpleTextParser.h" + +enum +{ + EBadTag, + EBadZeroLengthTag, + EBadIntegerParam, + EBadAlignmentParam, + EBadRgbColorParam +}; + +void Panic(TInt aPanic) +{ + User::Panic(_L("STP"), aPanic); +} + +CSimpleTextFormatParser* CSimpleTextFormatParser::NewLC() +{ + CSimpleTextFormatParser* self = new(ELeave)CSimpleTextFormatParser; + CleanupStack::PushL(self); + self->ConstructL(); + return self; +} + +CSimpleTextFormatParser::~CSimpleTextFormatParser() +{ + delete iParaFormat; +} + +void CSimpleTextFormatParser::ConstructL() +{ + iParaFormat = CParaFormat::NewL(); +} + + +void CSimpleTextFormatParser::SetBold(TBool aEnable) +{ + iCharFormat.iFontSpec.iFontStyle.SetStrokeWeight(aEnable ? EStrokeWeightBold : EStrokeWeightNormal); + iCharMask.ClearAll(); + iCharMask.SetAttrib(EAttFontStrokeWeight); + iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0); +} + +void CSimpleTextFormatParser::SetItalic(TBool aEnable) +{ + iCharFormat.iFontSpec.iFontStyle.SetPosture(aEnable ? EPostureItalic : EPostureUpright); + iCharMask.ClearAll(); + iCharMask.SetAttrib(EAttFontPosture); + iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0); +} + +void CSimpleTextFormatParser::SetUnderLine(TBool aEnable) +{ + iCharFormat.iFontPresentation.iUnderline = aEnable ? EUnderlineOn : EUnderlineOff; + iCharMask.ClearAll(); + iCharMask.SetAttrib(EAttFontUnderline); + iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0); +} + +void CSimpleTextFormatParser::SetHiddenText(TBool aEnable) +{ + iCharFormat.iFontPresentation.iHiddenText = aEnable; + iCharMask.ClearAll(); + iCharMask.SetAttrib(EAttFontHiddenText); + iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0); +} + +TRgb CSimpleTextFormatParser::ForegroundColor() +{ + iCharMask.ClearAll(); + iCharMask.SetAttrib(EAttColor); + iRichText->GetCharFormat(iCharFormat, iCharMask, TextPos(), 0); + return iCharFormat.iFontPresentation.iTextColor; +} + +void CSimpleTextFormatParser::SetForegroundColor(const TRgb& aColor) +{ + iCharFormat.iFontPresentation.iTextColor = aColor; + iCharMask.ClearAll(); + iCharMask.SetAttrib(EAttColor); + iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0); +} + +void CSimpleTextFormatParser::SetBackgroundColor(const TRgb& aColor) +{ + iParaFormat->iFillColor = aColor; + iParaMask.ClearAll(); + iParaMask.SetAttrib(EAttFillColor); + iRichText->ApplyParaFormatL(iParaFormat, iParaMask, ParaPos(), 0); +} + +void CSimpleTextFormatParser::NewParagraph() +{ + iCurrentPara++; + iRichText->AppendParagraphL(); + AppendTextL(_L("")); +} + + +void CSimpleTextFormatParser::SetAlignment(CParaFormat::TAlignment aAlignment) +{ + iParaFormat->iHorizontalAlignment = aAlignment; + iParaMask.ClearAll(); + iParaMask.SetAttrib(EAttAlignment); + iRichText->ApplyParaFormatL(iParaFormat, iParaMask, ParaPos(), 0); +} + + +void CSimpleTextFormatParser::SetFontHeight(TInt aHeight) +{ + iCharFormat.iFontSpec.iHeight = (aHeight * KTwipsPerInch)/KPointsPerInch; + iCharMask.ClearAll(); + iCharMask.SetAttrib(EAttFontHeight); + iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0); +} + +void CSimpleTextFormatParser::SetFontName(const TDesC& aName) +{ + iCharFormat.iFontSpec.iTypeface.iName = aName; + iCharFormat.iFontSpec.iTypeface.SetAttributes(0); + iCharFormat.iFontSpec.iTypeface.SetIsProportional(ETrue); + iCharMask.ClearAll(); + iCharMask.SetAttrib(EAttFontTypeface); + iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0); +} + + +/* + * Character formatting: + * Bold on + * Bold of + * Italic on + * Italic off + * Underline on + * Underline off + * Hidden text on **doesn't work** + * Hidden text off **doesn't work** + * Fontname: name (type: string) + * Fontsize: size (type: integer) + * Foreground color: color (type: color) + * Restore foreground color + * + * Paragraph formatting: + *

New paragraph - will reset both character & paragraph formatting to defaults + * Alignment: aling (type: alignement) + * Background color: color (type: color) **doesn't work** + * + * Special characters: + * The character: < + * + * Types: + * - string: + * - integer: Either decimal or hexidecimal value + * - color: Either integer specifing rgb value, or (r,g,b) in which r, g and b are of type integer + * - align: element of enumeration {center, left, right} + * + * Comments: + * The syntax/parser is fairly simplistic. The parser is not trying to match a tag like + * as XML/HTML do. Basically, when it encounters a tag (e.g., ) it will + * simply instruct the the editor to apply the formatting from the current position as + * specified by the tag (e.g., enable bold). For example, HelloWorld results + * in Hello displayed in a Bold font and World in a normal font. + * + * The only case where state is maintained is when using and . The current + * fg color is stored when parsing and restored when doing . Again, and + * don't have the XML/HTML behavior. For example: + * Peterwashere + * results in "Peter" displayed in red, "was" displayed in blue and "here" displayed in red. + * It literally goes like this: + * 1) --> apply editor text color red, previous color = whatever the editor's text color is now + * 2) --> apply editor text color blue, previous color = whatever the editor's text color + * is now --> red + * 3) --> apply editor text to previous color --> red + * 4) --> apply editor text to previous color --> red + * + * What you probably wanted was: + * Peterwashere + * Now "Peter" is displayed in red, "was" in blue and "here" in the default editor's color + */ + +static TUint32 ParseInteger(const TDesC& aString) +{ + TUint32 val = 0; + TBool parsed = EFalse; + if (aString.Length() > 2) + { + if ((aString[0] == '0') && ((aString[0] == 'x') || (aString[0] == 'X'))) + { + TLex lex(aString.Right(aString.Length()-2)); + if (lex.Val(val, EHex) != KErrNone) + { + __ASSERT_DEBUG(ETrue, Panic(EBadIntegerParam)); + } + parsed = ETrue; + } + } + if (!parsed) + { + TLex lex(aString); + if (lex.Val(val, EDecimal) != KErrNone) + { + __ASSERT_DEBUG(ETrue, Panic(EBadIntegerParam)); + } + } + return val; +} + +static TRgb ParseColor(const TDesC& aString) +{ + if (aString.Length() > 0) + { + if (aString[0] == 'R') + { + if (aString.Compare(_L("RgbBlack")) == 0) + return KRgbBlack; + else if (aString.Compare(_L("RgbDarkGray")) == 0) + return KRgbDarkGray; + else if (aString.Compare(_L("RgbDarkRed")) == 0) + return KRgbDarkRed; + else if (aString.Compare(_L("RgbDarkGreen")) == 0) + return KRgbDarkGreen; + else if (aString.Compare(_L("RgbDarkYellow")) == 0) + return KRgbDarkYellow; + else if (aString.Compare(_L("RgbDarkBlue")) == 0) + return KRgbDarkBlue; + else if (aString.Compare(_L("RgbDarkMagenta")) == 0) + return KRgbDarkMagenta; + else if (aString.Compare(_L("RgbDarkCyan")) == 0) + return KRgbDarkCyan; + else if (aString.Compare(_L("RgbRed")) == 0) + return KRgbRed; + else if (aString.Compare(_L("RgbGreen")) == 0) + return KRgbGreen; + else if (aString.Compare(_L("RgbYellow")) == 0) + return KRgbYellow; + else if (aString.Compare(_L("RgbBlue")) == 0) + return KRgbBlue; + else if (aString.Compare(_L("RgbMagenta")) == 0) + return KRgbMagenta; + else if (aString.Compare(_L("RgbCyan")) == 0) + return KRgbCyan; + else if (aString.Compare(_L("RgbGray")) == 0) + return KRgbGray; + else if (aString.Compare(_L("RgbWhite")) == 0) + return KRgbWhite; + else + { + __ASSERT_DEBUG(ETrue, Panic(EBadRgbColorParam)); + } + } + return ParseInteger(aString); + } + __ASSERT_DEBUG(ETrue, Panic(EBadRgbColorParam)); + + return KRgbBlack; +} + + + +static CParaFormat::TAlignment ParseAlignment(const TDesC& aString) +{ + if (aString.Compare(_L("center")) == 0) + { + return CParaFormat::ECenterAlign; + } + else if (aString.Compare(_L("left")) == 0) + { + return CParaFormat::ELeftAlign; + } + else if (aString.Compare(_L("right")) == 0) + { + return CParaFormat::ERightAlign; + } + __ASSERT_DEBUG(ETrue, Panic(EBadAlignmentParam)); + + return CParaFormat::ECenterAlign; +} + +void CSimpleTextFormatParser::ParseTagL(const TDesC& aTag) +{ + TInt tagLength = aTag.Length(); + if (tagLength == 0) + { + __ASSERT_DEBUG(ETrue, Panic(EBadZeroLengthTag)); + return; + } + + TPtrC param(_L("")); + TInt pos = aTag.Find(_L("=")); + if (pos>0) + { + param.Set(aTag.Right(aTag.Length()-pos-1)); + tagLength = pos; + } + TPtrC tag = aTag.Left(tagLength); + +// RDebug::Print(_L("tag=%S, param=%S"), &tag, ¶m); + + switch (tagLength) + { + case 1: + { + if (tag.Compare(_L("a")) == 0) + SetAlignment(ParseAlignment(param)); + else if (tag.Compare(_L("b")) == 0) + SetBold(); + else if (tag.Compare(_L("f")) == 0) + SetFontName(param); + else if (tag.Compare(_L("h")) == 0) + SetHiddenText(); + else if (tag.Compare(_L("i")) == 0) + SetItalic(); + else if (tag.Compare(_L("p")) == 0) + NewParagraph(); + else if (tag.Compare(_L("s")) == 0) + SetFontHeight(ParseInteger(param)); + else if (tag.Compare(_L("u")) == 0) + SetUnderLine(); + else + { + __ASSERT_DEBUG(ETrue, Panic(EBadTag)); + } + break; + } + + case 2: + { + if (tag.Compare(_L("/b")) == 0) + SetBold(EFalse); + if (tag.Compare(_L("bg")) == 0) + SetBackgroundColor(ParseColor(param)); + if (tag.Compare(_L("fg")) == 0) + { + iPrevFgColor = ForegroundColor(); + SetForegroundColor(ParseColor(param)); + } + else if (tag.Compare(_L("/h")) == 0) + SetHiddenText(EFalse); + else if (tag.Compare(_L("/i")) == 0) + SetItalic(EFalse); + else if (tag.Compare(_L("/u")) == 0) + SetUnderLine(EFalse); + else if (tag.Compare(_L("/<")) == 0) + AppendTextL(_L("<")); + break; + } + case 3: + { + if (tag.Compare(_L("/fg")) == 0) + SetForegroundColor(iPrevFgColor); + break; + } + default: + ; + } +} + +void CSimpleTextFormatParser::ParseL(const TDesC& aSimpleText, CRichText& aRichText) +{ + iRichText = &aRichText; + iCurrentPara = 0; + + TBool done = EFalse; + TPtrC simpleText(aSimpleText); + do + { + TInt pos = simpleText.Locate('<'); + if (pos > 0) + { + AppendTextL(simpleText.Left(pos)); + simpleText.Set(simpleText.Right(simpleText.Length() - pos)); + } + else if (pos == 0) + { + pos = simpleText.Locate('>'); + if (pos<=0) + User::Leave(KErrArgument); + ParseTagL(simpleText.Mid(1, pos-1)); + simpleText.Set(simpleText.Right(simpleText.Length() - pos - 1)); + } + else + { + AppendTextL(simpleText); + done = ETrue; + } + } while (!done); +} + + +TInt CSimpleTextFormatParser::TextPos() +{ + return iRichText->DocumentLength(); +#if 0 + TInt pos, length; + pos = iRichText->CharPosOfParagraph(length, iCurrentPara); + return pos+length-1; +#endif +} + +TInt CSimpleTextFormatParser::ParaPos() +{ + return TextPos(); +#if 0 + TInt pos, length; + pos = iRichText->CharPosOfParagraph(length, iCurrentPara); + return pos+length-1; +#endif +} + + +void CSimpleTextFormatParser::AppendTextL(const TDesC& aText) +{ +// RDebug::Print(_L("text=%S"), &aText); + iRichText->InsertL(TextPos(), aText); +} + + +#if 0 +void CTestDialog::ShowTextL(CRichText& aRichText) +{ + aRichText.Reset(); + + TCharFormat charFormat; + TCharFormatMask charMask; + aRichText.GetCharFormat(charFormat, charMask, 0, 0); + + TInt para = 0; + AppendTextL(_L("http://www.yipton.net"), aRichText); + + para++; + aRichText.AppendParagraphL(); + + CParaFormat* paraFormat = CParaFormat::NewLC(); + TParaFormatMask paraMask; + aRichText.GetParaFormatL(paraFormat, paraMask, ParaPos(aRichText, para), 0); + paraFormat->iHorizontalAlignment = CParaFormat::ECenterAlign; + paraMask.ClearAll(); + paraMask.SetAttrib(EAttAlignment); + aRichText.ApplyParaFormatL(paraFormat, paraMask, ParaPos(aRichText, para), 0); + + charFormat.iFontPresentation.iUnderline = EUnderlineOn; + charFormat.iFontSpec.iFontStyle.SetPosture(EPostureItalic); + charMask.ClearAll(); + charMask.SetAttrib(EAttFontPosture); + charMask.SetAttrib(EAttFontUnderline); + aRichText.ApplyCharFormatL(charFormat, charMask, TextPos(aRichText, para)); + AppendTextL(_L("mailto:Peter is here"), aRichText, para); + + para++; + aRichText.AppendParagraphL(); + + TFontSpec fontSpec(_L("edmunds"), 20 * KPointsPerInch); +// CFont* font = NULL; +// iCoeEnv->ScreenDevice()->GetNearestFontInTwips(font, fontSpec); + + charFormat.iFontSpec = fontSpec; + charMask.ClearAll(); + charMask.SetAttrib(EAttFontHeight); + charMask.SetAttrib(EAttFontTypeface); + aRichText.ApplyCharFormatL(charFormat, charMask, TextPos(aRichText, para)); + AppendTextL(_L("mailto:Peter is here"), aRichText, para); + + CleanupStack::PopAndDestroy(); +} + +#endif diff --git a/platform/uiq2/launcher/CSimpleTextParser.h b/platform/uiq2/launcher/CSimpleTextParser.h new file mode 100644 index 00000000..6f6b76cf --- /dev/null +++ b/platform/uiq2/launcher/CSimpleTextParser.h @@ -0,0 +1,62 @@ +/******************************************************************* + * + * File: CSimpleTextParser.h + * + * Author: Peter van Sebille (peter@yipton.net) + * + * Modified/adapted for picodriveN by notaz, 2006 + * + * (c) Copyright 2006, notaz + * (c) Copyright 2002, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +#ifndef __CSIMPLE_TEXT_PARSER_H +#define __CSIMPLE_TEXT_PARSER_H + +#include +#include // CRichText +#include // CEikRichTextEditor + +class CSimpleTextFormatParser : public CBase +{ +public: + static CSimpleTextFormatParser* NewLC(); + void ParseL(const TDesC& aPSTText, CRichText& aRichText); + +protected: + CSimpleTextFormatParser(){} + ~CSimpleTextFormatParser(); + void ConstructL(); + + void ParseTagL(const TDesC& aTag); + + TRgb ForegroundColor(); + void SetBold(TBool aEnable=ETrue); + void SetItalic(TBool aEnable=ETrue); + void SetUnderLine(TBool aEnable=ETrue); + void SetFontHeight(TInt aHeight); + void SetFontName(const TDesC& aName); + void SetHiddenText(TBool aEnable=ETrue); + void SetForegroundColor(const TRgb& aColor); + + void NewParagraph(); + void SetAlignment(CParaFormat::TAlignment aAlignment); + void SetBackgroundColor(const TRgb& aColor); + + void AppendTextL(const TDesC& aText); + TInt TextPos(); + TInt ParaPos(); + + + CRichText* iRichText; + TCharFormat iCharFormat; + TCharFormatMask iCharMask; + CParaFormat* iParaFormat; + TParaFormatMask iParaMask; + TInt iCurrentPara; + TRgb iPrevFgColor; +}; + +#endif /* __CSIMPLE_TEXT_PARSER_H */ diff --git a/platform/uiq2/launcher/Dialogs.cpp b/platform/uiq2/launcher/Dialogs.cpp new file mode 100644 index 00000000..847d7b01 --- /dev/null +++ b/platform/uiq2/launcher/Dialogs.cpp @@ -0,0 +1,473 @@ +/******************************************************************* + * + * File: Dialogs.cpp + * + * Author: Peter van Sebille (peter@yipton.net) + * + * Modified/adapted for picodriveN by notaz, 2006 + * + * (c) Copyright 2006, notaz + * (c) Copyright 2002, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +#include "Dialogs.h" +#include "Engine.h" +#include "picodriven.hrh" +#include "picodriven.rsg" + +#include "../version.h" +#include "CSimpleTextParser.h" +#include // CRichText +#include // CEikRichTextEditor +#include // CEikHorOptionButtonList +#include // CEikOptionButton +#include // EQuartzKeyTwoWayDown + + +/************************************************ + * + * config Dialog + * + ************************************************/ + +CPicoConfigDialog::CPicoConfigDialog(TPicoConfig &cfg, TPLauncherConfig &cfgl) : config(cfg), config_l(cfgl) +{ +} + +void CPicoConfigDialog::PostLayoutDynInitL() +{ + CEikHorOptionButtonList *buttons_rot = (CEikHorOptionButtonList*) Control( ECtlOptRotation ); + CEikHorOptionButtonList *buttons_disp = (CEikHorOptionButtonList*) Control( ECtlOptScreenMode ); + CEikCheckBox *chkbox_altrend= (CEikCheckBox*) Control( ECtlOptUseAltRend ); + CEikCheckBox *chkbox_acctmng= (CEikCheckBox*) Control( ECtlOptUseAccTiming ); + CEikCheckBox *chkbox_sram = (CEikCheckBox*) Control( ECtlOptUseSRAM ); + CEikCheckBox *chkbox_fps = (CEikCheckBox*) Control( ECtlOptShowFPS ); + CEikCheckBox *chkbox_sound = (CEikCheckBox*) Control( ECtlOptEnableSound ); + CEikCheckBox *chkbox_z80 = (CEikCheckBox*) Control( ECtlOptEmulateZ80 ); + CEikCheckBox *chkbox_ym2612 = (CEikCheckBox*) Control( ECtlOptEmulateYM2612 ); + CEikCheckBox *chkbox_sn76496= (CEikCheckBox*) Control( ECtlOptEmulateSN76496 ); + CEikChoiceListBase *combo_sndq = (CEikChoiceListBase*) Control( ECtlOptSndQuality ); + CEikCheckBox *chkbox_6bpad = (CEikCheckBox*) Control( ECtlOpt6ButtonPad ); + CEikCheckBox *chkbox_gzipst = (CEikCheckBox*) Control( ECtlOptGzipStates ); + CEikCheckBox *chkbox_motvol = (CEikCheckBox*) Control( ECtlOptMotDontUseVol ); + CEikCheckBox *chkbox_accsprt= (CEikCheckBox*) Control( ECtlOptUseAccSprites ); + CEikChoiceListBase *combo_region = (CEikChoiceListBase*) Control( ECtlOptRegion ); + CEikOptionButton *opt_fit2 = (CEikOptionButton*) buttons_disp->ComponentControl( TPicoConfig::PMFit2 ); + + buttons_rot ->SetButtonById(ECtlOptRotation0 + config.iScreenRotation); + buttons_disp->SetButtonById(ECtlOptScreenModeCenter + config.iScreenMode); + chkbox_sram ->SetState(config.iFlags & 1 ? CEikButtonBase::ESet : CEikButtonBase::EClear); + chkbox_fps ->SetState(config.iFlags & 2 ? CEikButtonBase::ESet : CEikButtonBase::EClear); + chkbox_sound ->SetState(config.iFlags & 4 ? CEikButtonBase::ESet : CEikButtonBase::EClear); + chkbox_motvol ->SetState(config.iFlags & 0x40 ? CEikButtonBase::ESet : CEikButtonBase::EClear); + chkbox_gzipst ->SetState(config.iFlags & 0x80 ? CEikButtonBase::ESet : CEikButtonBase::EClear); + chkbox_z80 ->SetState(config.iPicoOpt & 4 ? CEikButtonBase::ESet : CEikButtonBase::EClear); + chkbox_ym2612 ->SetState(config.iPicoOpt & 1 ? CEikButtonBase::ESet : CEikButtonBase::EClear); + chkbox_sn76496->SetState(config.iPicoOpt & 2 ? CEikButtonBase::ESet : CEikButtonBase::EClear); + chkbox_altrend->SetState(config.iPicoOpt & 0x10? CEikButtonBase::ESet : CEikButtonBase::EClear); + chkbox_6bpad ->SetState(config.iPicoOpt & 0x20? CEikButtonBase::ESet : CEikButtonBase::EClear); + chkbox_acctmng->SetState(config.iPicoOpt & 0x40? CEikButtonBase::ESet : CEikButtonBase::EClear); + chkbox_accsprt->SetState(config.iPicoOpt & 0x80? CEikButtonBase::ESet : CEikButtonBase::EClear); + + // hide "fit2" if we are not in 0 or 180 mode + if(config.iScreenRotation != TPicoConfig::PRot0 && config.iScreenRotation != TPicoConfig::PRot180) opt_fit2->MakeVisible(EFalse); + // dim some stuff for alternative renderer + if(config.iPicoOpt & 0x10) { + buttons_disp->SetDimmed(ETrue); + ((CEikOptionButton*)(buttons_rot->ComponentControl(TPicoConfig::PRot0)))->SetDimmed(ETrue); + ((CEikOptionButton*)(buttons_rot->ComponentControl(TPicoConfig::PRot180)))->SetDimmed(ETrue); + } + // dim accurate sprites + if(config.iPicoOpt & 0x10) { + chkbox_accsprt->SetState(CEikButtonBase::EClear); + chkbox_accsprt->SetDimmed(ETrue); + } + + TInt sel = (config.iPicoOpt&8) ? 4 : 0; + sel+= (config.iFlags>>3)&3; + combo_sndq->SetCurrentItem(sel); + switch(config.PicoRegion) { + case 1: sel = 4; break; + case 2: sel = 3; break; + case 4: sel = 2; break; + case 8: sel = 1; break; + default:sel = 0; // auto + } + combo_region->SetCurrentItem(sel); +} + +TBool CPicoConfigDialog::OkToExitL(TInt aButtonId) +{ + if(aButtonId != EEikBidOk) return ETrue; + + CEikHorOptionButtonList *buttons_rot = (CEikHorOptionButtonList*) Control( ECtlOptRotation ); + CEikHorOptionButtonList *buttons_disp = (CEikHorOptionButtonList*) Control( ECtlOptScreenMode ); + CEikCheckBox *chkbox_altrend= (CEikCheckBox*) Control( ECtlOptUseAltRend ); + CEikCheckBox *chkbox_acctmng= (CEikCheckBox*) Control( ECtlOptUseAccTiming ); + CEikCheckBox *chkbox_sram = (CEikCheckBox*) Control( ECtlOptUseSRAM ); + CEikCheckBox *chkbox_fps = (CEikCheckBox*) Control( ECtlOptShowFPS ); + CEikCheckBox *chkbox_sound = (CEikCheckBox*) Control( ECtlOptEnableSound ); + CEikCheckBox *chkbox_z80 = (CEikCheckBox*) Control( ECtlOptEmulateZ80 ); + CEikCheckBox *chkbox_ym2612 = (CEikCheckBox*) Control( ECtlOptEmulateYM2612 ); + CEikCheckBox *chkbox_sn76496= (CEikCheckBox*) Control( ECtlOptEmulateSN76496 ); + CEikChoiceListBase *combo_sndq = (CEikChoiceListBase*) Control( ECtlOptSndQuality ); + CEikCheckBox *chkbox_6bpad = (CEikCheckBox*) Control( ECtlOpt6ButtonPad ); + CEikCheckBox *chkbox_gzipst = (CEikCheckBox*) Control( ECtlOptGzipStates ); + CEikCheckBox *chkbox_motvol = (CEikCheckBox*) Control( ECtlOptMotDontUseVol ); + CEikCheckBox *chkbox_accsprt= (CEikCheckBox*) Control( ECtlOptUseAccSprites ); + CEikChoiceListBase *combo_region = (CEikChoiceListBase*) Control( ECtlOptRegion ); + + config.iScreenRotation = (TPicoConfig::TPicoScreenRotation) (buttons_rot->LabeledButtonId() - ECtlOptRotation0); + config.iScreenMode = (TPicoConfig::TPicoScreenMode) (buttons_disp->LabeledButtonId() - ECtlOptScreenModeCenter); + + if(chkbox_sram ->State() == CEikButtonBase::ESet) config.iFlags |= 1; else config.iFlags &= ~1; + if(chkbox_fps ->State() == CEikButtonBase::ESet) config.iFlags |= 2; else config.iFlags &= ~2; + if(chkbox_sound ->State() == CEikButtonBase::ESet) config.iFlags |= 4; else config.iFlags &= ~4; + if(chkbox_motvol ->State() == CEikButtonBase::ESet) config.iFlags |= 0x40; else config.iFlags &= ~0x40; + if(chkbox_gzipst ->State() == CEikButtonBase::ESet) config.iFlags |= 0x80; else config.iFlags &= ~0x80; + if(chkbox_z80 ->State() == CEikButtonBase::ESet) config.iPicoOpt |= 4; else config.iPicoOpt &= ~4; + if(chkbox_ym2612 ->State() == CEikButtonBase::ESet) config.iPicoOpt |= 1; else config.iPicoOpt &= ~1; + if(chkbox_sn76496->State() == CEikButtonBase::ESet) config.iPicoOpt |= 2; else config.iPicoOpt &= ~2; + if(chkbox_altrend->State() == CEikButtonBase::ESet) config.iPicoOpt |= 0x10;else config.iPicoOpt &= ~0x10; + if(chkbox_6bpad ->State() == CEikButtonBase::ESet) config.iPicoOpt |= 0x20;else config.iPicoOpt &= ~0x20; + if(chkbox_acctmng->State() == CEikButtonBase::ESet) config.iPicoOpt |= 0x40;else config.iPicoOpt &= ~0x40; + if(chkbox_accsprt->State() == CEikButtonBase::ESet) config.iPicoOpt |= 0x80;else config.iPicoOpt &= ~0x80; + + TInt sel = combo_sndq->CurrentItem(); + if(sel > 3) { config.iPicoOpt |= 8; sel-=4; } else config.iPicoOpt &= ~8; + config.iFlags &= ~0x18; + config.iFlags |= (sel<<3)&0x18; + + switch(combo_region->CurrentItem()) { + case 4: config.PicoRegion = 1; break; + case 3: config.PicoRegion = 2; break; + case 2: config.PicoRegion = 4; break; + case 1: config.PicoRegion = 8; break; + default:config.PicoRegion = 0; // auto + } + + return ETrue; +} + +// simple GUI stuff needs lots of code +void CPicoConfigDialog::HandleControlStateChangeL(TInt aControlId) +{ + if(aControlId == ECtlOptEnableSound) { + CEikCheckBox *chkbox_sound = (CEikCheckBox*) Control( ECtlOptEnableSound ); + CEikCheckBox *chkbox_z80 = (CEikCheckBox*) Control( ECtlOptEmulateZ80 ); + CEikCheckBox *chkbox_ym2612 = (CEikCheckBox*) Control( ECtlOptEmulateYM2612 ); + CEikCheckBox *chkbox_sn76496= (CEikCheckBox*) Control( ECtlOptEmulateSN76496 ); + + if(chkbox_sound->State() == CEikButtonBase::ESet) { + // check all sound chips too, but only if they all are not set + if((chkbox_z80->State() | chkbox_ym2612->State() | chkbox_sn76496->State()) == CEikButtonBase::EClear) { // (==0) + chkbox_z80 ->SetState(CEikButtonBase::ESet); + chkbox_ym2612 ->SetState(CEikButtonBase::ESet); + chkbox_sn76496->SetState(CEikButtonBase::ESet); + chkbox_z80 ->DrawDeferred(); + chkbox_ym2612 ->DrawDeferred(); + chkbox_sn76496->DrawDeferred(); + } + } else { + // clear everything, but only if everything is set + if((chkbox_z80->State() & chkbox_ym2612->State() & chkbox_sn76496->State()) == CEikButtonBase::ESet) { // (==1) + chkbox_z80 ->SetState(CEikButtonBase::EClear); + chkbox_ym2612 ->SetState(CEikButtonBase::EClear); + chkbox_sn76496->SetState(CEikButtonBase::EClear); + chkbox_z80 ->DrawDeferred(); + chkbox_ym2612 ->DrawDeferred(); + chkbox_sn76496->DrawDeferred(); + } + } + } else if(aControlId == ECtlOptUseAltRend) { + CEikCheckBox *chkbox_altrend= (CEikCheckBox*) Control( ECtlOptUseAltRend ); + CEikCheckBox *chkbox_accsprt= (CEikCheckBox*) Control( ECtlOptUseAccSprites ); + CEikHorOptionButtonList *buttons_rot = (CEikHorOptionButtonList*) Control( ECtlOptRotation ); + CEikHorOptionButtonList *buttons_disp = (CEikHorOptionButtonList*) Control( ECtlOptScreenMode ); + + TBool dimmed = chkbox_altrend->State() == CEikButtonBase::ESet; + // show/hide more stuff for alternative renderer + buttons_disp->SetDimmed(dimmed); + chkbox_accsprt->SetDimmed(dimmed); + ((CEikOptionButton*)(buttons_rot->ComponentControl(TPicoConfig::PRot0)))->SetDimmed(dimmed); + ((CEikOptionButton*)(buttons_rot->ComponentControl(TPicoConfig::PRot180)))->SetDimmed(dimmed); + if(dimmed && buttons_rot->LabeledButtonId() != ECtlOptRotation90 && buttons_rot->LabeledButtonId() != ECtlOptRotation270) { + buttons_rot->SetButtonById(ECtlOptRotation90); + aControlId = ECtlOptRotation; // cause rotation update + } + buttons_disp->SetButtonById(ECtlOptScreenModeCenter); + chkbox_accsprt->DrawDeferred(); + buttons_disp->DrawDeferred(); + buttons_rot->DrawDeferred(); + } + if(aControlId == ECtlOptRotation) { + CEikHorOptionButtonList *buttons_rot = (CEikHorOptionButtonList*) Control( ECtlOptRotation ); + CEikHorOptionButtonList *buttons_disp = (CEikHorOptionButtonList*) Control( ECtlOptScreenMode ); + CEikOptionButton *opt_fit2 = (CEikOptionButton*) buttons_disp->ComponentControl( TPicoConfig::PMFit2 ); + + if(buttons_rot->LabeledButtonId() == ECtlOptRotation0 || buttons_rot->LabeledButtonId() == ECtlOptRotation180) { + opt_fit2->MakeVisible(ETrue); + opt_fit2->DrawDeferred(); + } else { + if(opt_fit2->State() == CEikButtonBase::ESet) { + buttons_disp->SetButtonById(ECtlOptScreenModeFit); + buttons_disp->DrawDeferred(); + } + opt_fit2->MakeVisible(EFalse); + } + } +} + + +/************************************************************* +* +* Credits dialog +* +**************************************************************/ + +void CCreditsDialog::PreLayoutDynInitL() +{ + CDesCArrayFlat* desArray = CEikonEnv::Static()->ReadDesCArrayResourceL(iMessageResourceID); + CleanupStack::PushL(desArray); + + TInt iLength; + TInt count = desArray->Count(); + for (TInt i=0 ;i < count; i++) + { + iLength = static_cast(Control(ECtlCredits))->TextLength(); + static_cast(Control(ECtlCredits))->Text()->InsertL(iLength, desArray->operator[](i)); + iLength = static_cast(Control(ECtlCredits))->TextLength(); + static_cast(Control(ECtlCredits))->Text()->InsertL(iLength, CEditableText::ELineBreak); + } + CleanupStack::PopAndDestroy(desArray); +} + +void CCreditsDialog::PostLayoutDynInitL() +{ + static_cast(Control(ECtlCredits))->CreateScrollBarFrameL(); + static_cast(Control(ECtlCredits))->ScrollBarFrame()->SetScrollBarVisibilityL(CEikScrollBarFrame::EAuto, CEikScrollBarFrame::EAuto); +} + +TKeyResponse CCreditsDialog::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType) +{ + if (aType == EEventKey) + { + if (aKeyEvent.iCode == EQuartzKeyTwoWayDown) + { + static_cast(Control(ECtlCredits))->MoveDisplayL(TCursorPosition::EFLineDown); + static_cast(Control(ECtlCredits))->UpdateScrollBarsL(); + return EKeyWasConsumed; + } + else if (aKeyEvent.iCode == EQuartzKeyTwoWayUp) + { + static_cast(Control(ECtlCredits))->MoveDisplayL(TCursorPosition::EFLineUp); + static_cast(Control(ECtlCredits))->UpdateScrollBarsL(); + return EKeyWasConsumed; + } + } + return CEikDialog::OfferKeyEventL(aKeyEvent, aType); +} + + +/************************************************************* +* +* Debug dialog +* +**************************************************************/ + +CDebugDialog::CDebugDialog(char *t) +{ + Mem::Copy(iText, t, 1024); + iText[1023] = 0; +} + +void CDebugDialog::PreLayoutDynInitL() +{ + char *p = iText, *line = iText; + TBool end=0; + TBuf<128> tbuf; + CEikGlobalTextEditor *editor = static_cast(Control(ECtlDebugEdit)); + + while(!end) { + while(*p && *p != '\r' && *p != '\n') p++; + if(!*p) end=1; + *p = 0; + TPtrC8 ptr((TUint8*) line); + tbuf.Copy(ptr); + editor->Text()->InsertL(editor->TextLength(), tbuf); + editor->Text()->InsertL(editor->TextLength(), CEditableText::ELineBreak); + line = ++p; + } +} + +void CDebugDialog::PostLayoutDynInitL() +{ + static_cast(Control(ECtlDebugEdit))->CreateScrollBarFrameL(); + static_cast(Control(ECtlDebugEdit))->ScrollBarFrame()->SetScrollBarVisibilityL(CEikScrollBarFrame::EAuto, CEikScrollBarFrame::EAuto); +} + +TKeyResponse CDebugDialog::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType) +{ + if (aType == EEventKey) + { + if (aKeyEvent.iCode == EQuartzKeyTwoWayDown) + { + static_cast(Control(ECtlDebugEdit))->MoveDisplayL(TCursorPosition::EFLineDown); + static_cast(Control(ECtlDebugEdit))->UpdateScrollBarsL(); + return EKeyWasConsumed; + } + else if (aKeyEvent.iCode == EQuartzKeyTwoWayUp) + { + static_cast(Control(ECtlDebugEdit))->MoveDisplayL(TCursorPosition::EFLineUp); + static_cast(Control(ECtlDebugEdit))->UpdateScrollBarsL(); + return EKeyWasConsumed; + } + } + return CEikDialog::OfferKeyEventL(aKeyEvent, aType); +} + + +/************************************************ + * + * SimpleTextInfoDialog + * + ************************************************/ + + +CSimpleTextInfoDialog::CSimpleTextInfoDialog(TInt aTextIdOne, TInt aRichTextCtlIdOne, TInt aTextIdTwo, TInt aRichTextCtlIdTwo, TBool aSimpleTextResIdOneIsArray, TBool aSimpleTextResIdTwoIsArray) + : iSimpleTextResIdOne(aTextIdOne), + iSimpleTextResIdTwo(aTextIdTwo), + iRichTextCtlIdOne(aRichTextCtlIdOne), + iRichTextCtlIdTwo(aRichTextCtlIdTwo), + iSimpleTextResIdOneIsArray(aSimpleTextResIdOneIsArray), + iSimpleTextResIdTwoIsArray(aSimpleTextResIdTwoIsArray), + iSetDialogBackground(ETrue) +{ +} + +void CSimpleTextInfoDialog::PreLayoutDynInitL() +{ + CEikRichTextEditor* richTextEditor; + + if (iRichTextCtlIdOne != -1) + { + richTextEditor=STATIC_CAST(CEikRichTextEditor*, Control(iRichTextCtlIdOne)); + PreLayoutDynInitRichTextL(*richTextEditor, iRichTextCtlIdOne, iSimpleTextResIdOne); + } + + if (iRichTextCtlIdTwo != -1) + { + richTextEditor=STATIC_CAST(CEikRichTextEditor*, Control(iRichTextCtlIdTwo)); + richTextEditor->Border().SetType(ENone); + PreLayoutDynInitRichTextL(*richTextEditor, iRichTextCtlIdTwo, iSimpleTextResIdTwo); + } +} + + +void CSimpleTextInfoDialog::PreLayoutDynInitRichTextL(CEikRichTextEditor& aRichTextEditor, TInt aRichTextCtlId, TInt aSimpleTextResId) +{ + iEikonEnv->BusyMsgL(_L("Opening")); + aRichTextEditor.SetEdwinSizeObserver(this); + if (iSetDialogBackground) + aRichTextEditor.SetBackgroundColorL(iEikonEnv->Color(EColorDialogBackground)); + aRichTextEditor.SetSize(aRichTextEditor.Size()); // Set the size of the edwin + + // no scrollbars for us + aRichTextEditor.CreateScrollBarFrameL(); // Create the scrollbars + aRichTextEditor.ScrollBarFrame()->SetScrollBarVisibilityL(CEikScrollBarFrame::EOff, iWantVertScrollbar ? CEikScrollBarFrame::EAuto: CEikScrollBarFrame::EOff); + + ShowTextL(*aRichTextEditor.RichText(), aRichTextCtlId, aSimpleTextResId); + + aRichTextEditor.UpdateAllFieldsL(); // Updates all the fields in the document + + aRichTextEditor.UpdateScrollBarsL(); +} + + +void CSimpleTextInfoDialog::PostLayoutDynInitL() +{ + Layout(); + iEikonEnv->BusyMsgCancel(); +} + +TBool CSimpleTextInfoDialog::HandleEdwinSizeEventL(CEikEdwin* aEdwin, TEdwinSizeEvent aEventType, TSize aDesirableEdwinSize) +{ + if ((aEventType == EEventSizeChanging)) + aEdwin->SetSize(aDesirableEdwinSize); + return EFalse; +} + +void CSimpleTextInfoDialog::ShowTextL(CRichText& aRichText, TInt /*aRichTextCtlId*/, TInt aResId) +{ + if (aResId != -1) + { + if ( ((aResId == iSimpleTextResIdOne) && (iSimpleTextResIdOneIsArray)) || + ((aResId == iSimpleTextResIdTwo) && (iSimpleTextResIdTwoIsArray)) + ) + { + CDesCArrayFlat* desArray = CEikonEnv::Static()->ReadDesCArrayResourceL(aResId); + CleanupStack::PushL(desArray); + + CSimpleTextFormatParser* parser = CSimpleTextFormatParser::NewLC(); + + TInt count = desArray->Count(); + for (TInt i=0 ;iParseL(desArray->operator[](i), aRichText); + + CleanupStack::PopAndDestroy(parser); + CleanupStack::PopAndDestroy(desArray); + } + else + { + HBufC* text = CEikonEnv::Static()->AllocReadResourceLC(aResId); + ShowSimpleTextL(*text, aRichText); + CleanupStack::PopAndDestroy(text); + } + } +} + +void CSimpleTextInfoDialog::ShowSimpleTextL(const TDesC& aSimpleText, CRichText& aRichText) +{ + CSimpleTextFormatParser* parser = CSimpleTextFormatParser::NewLC(); + parser->ParseL(aSimpleText, aRichText); + + CleanupStack::PopAndDestroy(parser); +} + + + +/************************************************ + * + * About Dialog + * + ************************************************/ + +CAboutDialog::CAboutDialog() : CSimpleTextInfoDialog(-1, ECtlAboutVersion, R_SIMPLE_TEXT_ABOUT_LINKS, ECtlAboutLinks) +{ +} + +void CAboutDialog::ShowTextL(CRichText& aRichText, TInt aRichTextCtlId, TInt aResId) +{ + if (aRichTextCtlId == ECtlAboutLinks) + CSimpleTextInfoDialog::ShowTextL(aRichText, aRichTextCtlId, aResId); + else + { + TBuf<16> versionText; + TBuf<512> text; + + #if (KPicoBuildNumber != 0) + versionText.Format(_L("%d.%d%d"), KPicoMajorVersionNumber, KPicoMinorVersionNumber, KPicoBuildNumber); + #else + versionText.Format(_L("%d.%d"), KPicoMajorVersionNumber, KPicoMinorVersionNumber); + #endif + + HBufC* aboutFormat = CEikonEnv::Static()->AllocReadResourceLC(R_SIMPLE_TEXT_ABOUT); + text.Format(*aboutFormat, &versionText); + + ShowSimpleTextL(text, aRichText); + + CleanupStack::PopAndDestroy(aboutFormat); + } +} diff --git a/platform/uiq2/launcher/Dialogs.h b/platform/uiq2/launcher/Dialogs.h new file mode 100644 index 00000000..c8076e6f --- /dev/null +++ b/platform/uiq2/launcher/Dialogs.h @@ -0,0 +1,145 @@ +/******************************************************************* + * + * File: Dialogs.h + * + * Author: Peter van Sebille (peter@yipton.net) + * + * Modified/adapted for picodriveN by notaz, 2006 + * + * (c) Copyright 2006, notaz + * (c) Copyright 2002, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +#ifndef __DIALOGS_H +#define __DIALOGS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../ClientServer.h" + +class CRichText; +class CEikRichTextEditor; +class TPLauncherConfig; + +/************************************************ + * + * CSimpleTextInfo Dialog + * + ************************************************/ + +class CSimpleTextInfoDialog : public CEikDialog, public MEikEdwinSizeObserver +{ +public: + CSimpleTextInfoDialog(TInt aTextIdOne = -1, TInt aRichTextCtlIdOne = -1, + TInt aTextIdTwo = -1, TInt aRichTextCtlIdTwo = -1, + TBool aSimpleTextResIdOneIsArray = EFalse, TBool aSimpleTextResIdTwoIsArray = EFalse + ); + void SetDialogBackground(TBool aEnable){iSetDialogBackground=aEnable;} + void WantVertScrollbar(TBool aEnable){iWantVertScrollbar=aEnable;} +public: // implements MEikEdwinSizeObserver + virtual TBool HandleEdwinSizeEventL(CEikEdwin* aEdwin, TEdwinSizeEvent aEventType, TSize aDesirableEdwinSize); + +protected: // framework + void PreLayoutDynInitL(); + void PostLayoutDynInitL(); + +protected: // new stuff + virtual void ShowTextL(CRichText& aRichText, TInt aRichTextCtlId, TInt aResId); + virtual void PreLayoutDynInitRichTextL(CEikRichTextEditor& aRichTextEditor, TInt aRichTextCtlId, TInt aResId); + + void ShowSimpleTextL(const TDesC& aSimpleText, CRichText& aRichText); + + TInt iSimpleTextResIdOne; + TInt iSimpleTextResIdTwo; + TInt iRichTextCtlIdOne; + TInt iRichTextCtlIdTwo; + TBool iSimpleTextResIdOneIsArray; + TBool iSimpleTextResIdTwoIsArray; + TBool iSetDialogBackground; + TBool iWantVertScrollbar; +}; + + +/************************************************ + * + * config Dialog + * + ************************************************/ + +class CPicoConfigDialog : public CEikDialog +{ +public: + CPicoConfigDialog(TPicoConfig &cfg, TPLauncherConfig &cfgl); + +protected: // framework + void PostLayoutDynInitL(); + void HandleControlStateChangeL(TInt aControlId); + TBool OkToExitL(TInt aButtonId); + + TPicoConfig &config; + TPLauncherConfig &config_l; +}; + + +/************************************************ + * + * About Dialog + * + ************************************************/ + +class CAboutDialog : public CSimpleTextInfoDialog +{ +public: + CAboutDialog(); +protected: // from CSimpleTextInfoDialog + virtual void ShowTextL(CRichText& aRichText, TInt aRichTextCtlId, TInt aResId); +}; + +/************************************************************* +* +* Credits dialog +* +**************************************************************/ + +class CCreditsDialog : public CEikDialog +{ +public: + TInt iMessageResourceID; + +protected: + void PreLayoutDynInitL(); + void PostLayoutDynInitL(); + TKeyResponse OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType); +}; + +/************************************************************* +* +* Debug dialog +* +**************************************************************/ + +class CDebugDialog : public CEikDialog +{ +public: + CDebugDialog(char *t); + +protected: + char iText[1024]; + void PreLayoutDynInitL(); + void PostLayoutDynInitL(); + TKeyResponse OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType); +}; + + + +#endif // __DIALOGS_H diff --git a/platform/uiq2/launcher/Engine.cpp b/platform/uiq2/launcher/Engine.cpp new file mode 100644 index 00000000..489cd4fa --- /dev/null +++ b/platform/uiq2/launcher/Engine.cpp @@ -0,0 +1,256 @@ +/******************************************************************* + * + * File: Engine.cpp + * + * Author: Peter van Sebille (peter@yipton.net) + * + * Modified/adapted for picodriveN by notaz, 2006 + * + * (c) Copyright 2006, notaz + * (c) Copyright 2002, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +#include "Engine.h" +#include +#include +//#include + +#include "../version.h" + + +CGameRunner::~CGameRunner() +{ + Cancel(); + + RProcess process; + if(process.Open(iProcessId) == KErrNone) { + process.Terminate(1); + process.Close(); + } +} + +CGameRunner::CGameRunner(MGameWatcher& aGameWatcher) +: CActive(CActive::EPriorityStandard), iGameWatcher(aGameWatcher) +{ +} + + +CGameRunner* CGameRunner::NewL(MGameWatcher& aGameWatcher) +{ + CGameRunner* self = new(ELeave) CGameRunner(aGameWatcher); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); // self + return self; +} + +void CGameRunner::ConstructL() +{ + RProcess newProcess, thisProcess; + + // make path to picosmall + TBuf exePath; + TBuf tmpbuff; // hopefully large enough + thisProcess.CommandLine(tmpbuff); + TInt pos = tmpbuff.Find(_L(" ")); + if(pos == KErrNotFound) pos = tmpbuff.Length(); + for(pos--; pos > 2; pos--) + if(tmpbuff[pos] == '\\') break; + if(pos > 2) { + exePath.Copy(tmpbuff.Ptr(), pos+1); + exePath.Append(_L("PICOSMALL.EXE")); + } + + DEBUGPRINT(_L("[app] starting EXE: %S"), &exePath); + if(newProcess.Create(exePath, _L(""))) { + CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed to start emulation process.")); + thisProcess.Terminate(1); + } + + iProcessId = newProcess.Id(); + DEBUGPRINT(_L("[app] newProcess.Id(): %d"), iProcessId); + + CActiveScheduler::Add(this); + newProcess.SetOwner(thisProcess); // Warning: phone strangely reboots when attempting to get owner after thisProcess exits + newProcess.Logon(iStatus); + + SetActive(); + + newProcess.Resume(); // start execution + newProcess.Close(); +} + +void CGameRunner::RunL() +{ + iGameWatcher.NotifyEmuDeath(); +} + +void CGameRunner::DoCancel() +{ + RProcess process; + if(process.Open(iProcessId) == KErrNone) { + process.LogonCancel(iStatus); + process.Close(); + } +} + + +// CExitForcer +CExitForcer::~CExitForcer() +{ + Cancel(); +} + +CExitForcer::CExitForcer(MGameWatcher& aGameWatcher) : CActive(CActive::EPriorityStandard), iGameWatcher(aGameWatcher) +{ +} + + +CExitForcer* CExitForcer::NewL(MGameWatcher& aGameWatcher, TInt ms) +{ + CExitForcer* self = new(ELeave) CExitForcer(aGameWatcher); + CleanupStack::PushL(self); + self->ConstructL(ms); + CleanupStack::Pop(); // self + return self; +} + +void CExitForcer::ConstructL(TInt ms) +{ + CActiveScheduler::Add(this); + iTimer.CreateLocal(); + iTimer.After(iStatus, ms*1000); + SetActive(); +} + +void CExitForcer::RunL() +{ + iGameWatcher.NotifyForcedExit(); +} + +void CExitForcer::DoCancel() +{ + if(iTimer.Handle()) { + iTimer.Cancel(); + iTimer.Close(); + } +} + + +// CThreadWatcher +CThreadWatcher::~CThreadWatcher() +{ + Cancel(); +} + +CThreadWatcher::CThreadWatcher(MGameWatcher& aGameWatcher, const TDesC& aName) +: CActive(CActive::EPriorityStandard), iGameWatcher(aGameWatcher), iName(aName) +{ +} + + +CThreadWatcher* CThreadWatcher::NewL(MGameWatcher& aGameWatcher, const TDesC& aName) +{ + CThreadWatcher* self = new(ELeave) CThreadWatcher(aGameWatcher, aName); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); // self + return self; +} + +void CThreadWatcher::ConstructL() +{ + CActiveScheduler::Add(this); + RThread thread; + if(thread.Open(iName) == KErrNone) { + thread.Logon(iStatus); + thread.Close(); + SetActive(); + } +} + +void CThreadWatcher::RunL() +{ + iGameWatcher.NotifyEmuDeath(); +} + +void CThreadWatcher::DoCancel() +{ + RThread thread; + if(thread.Open(iName) == KErrNone) { + thread.LogonCancel(iStatus); + thread.Close(); + } +} + + +// config +TPLauncherConfig::TPLauncherConfig(TPicoConfig &cfg) +: iEmuConfig(cfg) +{ + iLastROMFile.Copy(_L("C:\\")); + + // ini + TBuf tmpbuff; // hopefully large enough + RProcess me; + me.CommandLine(tmpbuff); + TInt pos = tmpbuff.Find(_L(" ")); + if(pos == KErrNotFound) pos = tmpbuff.Length(); + if(pos > 3) { + iIniFileName.Copy(tmpbuff.Ptr(), pos-3); + iIniFileName.Append(_L("ini")); + } + //DEBUGPRINT(_L("[app] made ini: %S"), &iIniFileName); +} + + +void TPLauncherConfig::Load() +{ + RFile file; + + if(!file.Open(CEikonEnv::Static()->FsSession(), iIniFileName, 0)) + { + TInt version; + TPckg pkg_version(version); + TPckg pkg_Pad(iPad); + TBuf8 pad0; // reserved for future use (6 words) + TPtr8 picoCfg((TUint8*) &iEmuConfig, sizeof(iEmuConfig)); + + file.Read(pkg_version); + file.Read(pkg_Pad); + file.Read(pad0, 24); + file.Read(pad0, KMaxFileName); + file.Read(picoCfg); + + TBuf8 file8(pad0.Ptr()); // take as zero terminated string + iLastROMFile.Copy(file8); + //DEBUGPRINT(_L("[app] iLastROMFile (%i): %S"), iLastROMFile.Length(), &iLastROMFile); + + file.Close(); + } +} + +void TPLauncherConfig::Save() +{ + RFile file; + + if(!file.Replace(CEikonEnv::Static()->FsSession(), iIniFileName, EFileWrite)) { + TInt version = (KPicoMajorVersionNumber<<24)+(KPicoMinorVersionNumber<<16); + TPckgC pkg_version(version); + TPckgC pkg_Pad(iPad); + TBuf8 pad0; pad0.FillZ(KMaxFileName); + TBuf8 file8; file8.Copy(iLastROMFile); + TPtrC8 picoCfg((TUint8*) &iEmuConfig, sizeof(iEmuConfig)); + + file.Write(pkg_version); + file.Write(pkg_Pad); // 0x0004 + file.Write(pad0, 24); // 0x0008, reserved for future use (6 words) + file.Write(file8); // 0x0020 + file.Write(pad0, KMaxFileName-file8.Length()); + file.Write(picoCfg); // 0x0120 + + file.Close(); + } +} diff --git a/platform/uiq2/launcher/Engine.h b/platform/uiq2/launcher/Engine.h new file mode 100644 index 00000000..052edc88 --- /dev/null +++ b/platform/uiq2/launcher/Engine.h @@ -0,0 +1,112 @@ +/******************************************************************* + * + * File: Engine.h + * + * Author: Peter van Sebille (peter@yipton.net) + * + * Modified/adapted for picodriveN by notaz, 2006 + * + * (c) Copyright 2006, notaz + * (c) Copyright 2002, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +#ifndef __ENGINE_H +#define __ENGINE_H + +#include +#include + +#include "../ClientServer.h" + +class RFs; + +#ifdef __DEBUG_PRINT + #define DEBUGPRINT(x...) RDebug::Print(x) +#else + #define DEBUGPRINT(x...) +#endif + + +class MGameWatcher +{ +public: + virtual void NotifyEmuDeath() = 0; + virtual void NotifyForcedExit() = 0; +}; + + +class CGameRunner : public CActive +{ +public: + static CGameRunner* NewL(MGameWatcher& aGameWatcher); + ~CGameRunner(); + + void KillAfter(TInt ms); + +protected: + CGameRunner(MGameWatcher& aGameWatcher); + void ConstructL(); + + virtual void RunL(); + virtual void DoCancel(); + + MGameWatcher& iGameWatcher; + TProcessId iProcessId; +}; + + +class CExitForcer : public CActive +{ +public: + static CExitForcer* NewL(MGameWatcher& aGameWatcher, TInt ms); + ~CExitForcer(); + +protected: + CExitForcer(MGameWatcher& aGameWatcher); + void ConstructL(TInt ms); + + virtual void RunL(); + virtual void DoCancel(); + + MGameWatcher& iGameWatcher; + RTimer iTimer; +}; + + +class CThreadWatcher : public CActive +{ +public: + static CThreadWatcher* NewL(MGameWatcher& aGameWatcher, const TDesC& aName); + ~CThreadWatcher(); + +protected: + CThreadWatcher(MGameWatcher& aGameWatcher, const TDesC& aName); + void ConstructL(); + + virtual void RunL(); + virtual void DoCancel(); + + MGameWatcher& iGameWatcher; + const TDesC& iName; // thread name +}; + + +// configuration emu process doesn't care about +class TPLauncherConfig { +public: + TPLauncherConfig(TPicoConfig &cfg); + void Load(); + void Save(); + + TBool iPad; // was iPauseOnCall + TFileName iLastROMFile; + TPicoConfig &iEmuConfig; + +private: + TFileName iIniFileName; +}; + + +#endif diff --git a/platform/uiq2/launcher/PICODRIVEN.ARMI b/platform/uiq2/launcher/PICODRIVEN.ARMI new file mode 100644 index 00000000..11a10317 --- /dev/null +++ b/platform/uiq2/launcher/PICODRIVEN.ARMI @@ -0,0 +1,1070 @@ + +# CWD \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\ +# MMPFile \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICODRIVEN.MMP +# Target PICODRIVEN.APP +# TargetType APP +# BasicTargetType DLL +# MakefileType GNU + +ERASE = @erase 2>>nul + +# EPOC DEFINITIONS + +EPOCBLD = ..\..\..\..\..\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICODRIVEN\ARMI +EPOCTRG = ..\..\..\..\..\EPOC32\RELEASE\ARMI +EPOCLIB = ..\..\..\..\..\EPOC32\RELEASE\ARMI +EPOCLINK = ..\..\..\..\..\EPOC32\RELEASE\ARMI +EPOCSTATLINK = ..\..\..\..\..\EPOC32\RELEASE\ARMI +EPOCASSPLINK = ..\..\..\..\..\EPOC32\RELEASE\MARM +EPOCDATA = \DEV\UIQ21\EPOC32\DATA +EPOCINC = \DEV\UIQ21\EPOC32\INCLUDE +TRGDIR = Z\SYSTEM\APPS\PICODRIVEN +DATADIR = Z\SYSTEM\DATA + +EPOCBLDUREL = $(EPOCBLD)\UREL +EPOCTRGUREL = $(EPOCTRG)\UREL +EPOCLIBUREL = $(EPOCLIB)\UREL +EPOCLINKUREL = $(EPOCLINK)\UREL +EPOCSTATLINKUREL = $(EPOCSTATLINK)\UREL +EPOCASSPLINKUREL = $(EPOCASSPLINK)\UREL + +EPOCBLDUDEB = $(EPOCBLD)\UDEB +EPOCTRGUDEB = $(EPOCTRG)\UDEB +EPOCLIBUDEB = $(EPOCLIB)\UREL +EPOCLINKUDEB = $(EPOCLINK)\UREL +EPOCSTATLINKUDEB = $(EPOCSTATLINK)\UDEB +EPOCASSPLINKUDEB = $(EPOCASSPLINK)\UREL + +# EPOC PSEUDOTARGETS + +UREL : MAKEWORKUREL RESOURCEUREL + +UDEB : MAKEWORKUDEB RESOURCEUDEB + +ALL : UREL UDEB + +CLEAN CLEANALL : CLEANBUILD CLEANRELEASE CLEANLIBRARY + + + +WHAT WHATALL : WHATUREL WHATUDEB + +RESOURCE RESOURCEALL : RESOURCEUREL RESOURCEUDEB + +CLEANBUILD CLEANBUILDALL : CLEANBUILDUREL CLEANBUILDUDEB + +CLEANRELEASE CLEANRELEASEALL : CLEANRELEASEUREL CLEANRELEASEUDEB + +MAKEWORK MAKEWORKALL : MAKEWORKUREL MAKEWORKUDEB + +LISTING LISTINGALL : LISTINGUREL LISTINGUDEB + +MAKEWORK : MAKEWORKLIBRARY + +RESOURCEUREL RESOURCEUDEB : GENERIC_RESOURCE + + +# must set both PATH and Path to make it work correctly +Path:=X:\DEV\UIQ21\EPOC32\gcc\bin;$(Path) +PATH:=$(Path) + +INCDIR = -I "." -I "..\..\..\..\..\EPOC32\INCLUDE" + +GCCFLAGS=-march=armv4t -mthumb-interwork \ + -pipe -c -nostdinc -Wall -Wno-ctor-dtor-privacy -Wno-unknown-pragmas + +GCCDEFS = -D__SYMBIAN32__ -D__GCC32__ -D__EPOC32__ -D__MARM__ -D__MARM_ARMI__ -D__DLL__ $(USERDEFS) -D__DEBUG_PRINT + +GCCUREL = gcc -s -fomit-frame-pointer -O $(GCCFLAGS) -DNDEBUG -D_UNICODE $(GCCDEFS) +GCCUDEB = gcc -g -O $(GCCFLAGS) -D_DEBUG -D_UNICODE $(GCCDEFS) + + +UREL : \ + $(EPOCTRGUREL)\PICODRIVEN.APP + +UDEB : \ + $(EPOCTRGUDEB)\PICODRIVEN.APP + + +RESOURCEUREL : MAKEWORKUREL +RESOURCEUDEB : MAKEWORKUDEB + +LIBRARY : MAKEWORKLIBRARY + +FREEZE : + +CLEANLIBRARY : + + +GENERIC_RESOURCE : GENERIC_MAKEWORK + +# REAL TARGET - BUILD VARIANT UREL + +WHATUREL : WHATGENERIC + +CLEANUREL : CLEANBUILDUREL CLEANRELEASEUREL + +CLEANBUILDUREL : + @perl -S ermdir.pl "$(EPOCBLDUREL)" + +CLEANRELEASEUREL : CLEANGENERIC + + +UREL_RELEASEABLES1= \ + \DEV\UIQ21\EPOC32\RELEASE\ARMI\UREL\PICODRIVEN.APP \ + \DEV\UIQ21\EPOC32\RELEASE\ARMI\UREL\PICODRIVEN.APP.MAP + +WHATUREL: + @echo $(UREL_RELEASEABLES1) + +CLEANRELEASEUREL: + -$(ERASE) $(UREL_RELEASEABLES1) + +LISTINGUREL : MAKEWORKUREL \ + LISTINGURELAPP \ + LISTINGURELCSIMPLETEXTPARSER \ + LISTINGURELDIALOGS \ + LISTINGURELENGINE \ + LISTINGURELSIMPLECLIENT + +LIBSUREL= \ + $(EPOCSTATLINKUREL)\EDLLSTUB.LIB \ + $(EPOCSTATLINKUREL)\EGCC.LIB \ + $(EPOCLINKUREL)\EUSER.LIB \ + $(EPOCLINKUREL)\WS32.LIB \ + $(EPOCLINKUREL)\EFSRV.LIB \ + $(EPOCLINKUREL)\APPARC.LIB \ + $(EPOCLINKUREL)\CONE.LIB \ + $(EPOCLINKUREL)\EIKCOCTL.LIB \ + $(EPOCLINKUREL)\EIKCORE.LIB \ + $(EPOCLINKUREL)\EIKDLG.LIB \ + $(EPOCLINKUREL)\EIKCTL.LIB \ + $(EPOCLINKUREL)\EIKFILE.LIB \ + $(EPOCLINKUREL)\EGUL.LIB \ + $(EPOCLINKUREL)\ETEXT.LIB \ + $(EPOCLINKUREL)\GDI.LIB + +$(EPOCTRGUREL)\PICODRIVEN.APP : $(EPOCBLDUREL)\PICODRIVEN.in $(EPOCSTATLINKUREL)\EDLL.LIB $(LIBSUREL) + dlltool -m arm_interwork --output-def "$(EPOCBLDUREL)\PICODRIVEN.inf" "$(EPOCBLDUREL)\PICODRIVEN.in" + perl -S makedef.pl -Deffile "$(EPOCBLDUREL)\PICODRIVEN.inf" -1 NewApplication__Fv "$(EPOCBLD)\PICODRIVEN.def" + -$(ERASE) "$(EPOCBLDUREL)\PICODRIVEN.inf" + dlltool -m arm_interwork --def "$(EPOCBLD)\PICODRIVEN.def" \ + --output-exp "$(EPOCBLDUREL)\PICODRIVEN.exp" \ + --dllname "PICODRIVEN[1000c193].APP" + ld -s -e _E32Dll -u _E32Dll "$(EPOCBLDUREL)\PICODRIVEN.exp" --dll \ + --base-file "$(EPOCBLDUREL)\PICODRIVEN.bas" -o "$(EPOCBLDUREL)\PICODRIVEN.APP" \ + "$(EPOCSTATLINKUREL)\EDLL.LIB" --whole-archive "$(EPOCBLDUREL)\PICODRIVEN.in" \ + --no-whole-archive $(LIBSUREL) $(USERLDFLAGS) + -$(ERASE) "$(EPOCBLDUREL)\PICODRIVEN.exp" + -$(ERASE) "$(EPOCBLDUREL)\PICODRIVEN.APP" + dlltool -m arm_interwork \ + --def "$(EPOCBLD)\PICODRIVEN.def" \ + --dllname "PICODRIVEN[1000c193].APP" \ + --base-file "$(EPOCBLDUREL)\PICODRIVEN.bas" \ + --output-exp "$(EPOCBLDUREL)\PICODRIVEN.exp" + -$(ERASE) "$(EPOCBLDUREL)\PICODRIVEN.bas" + ld -s -e _E32Dll -u _E32Dll --dll \ + "$(EPOCBLDUREL)\PICODRIVEN.exp" \ + -Map "$(EPOCTRGUREL)\PICODRIVEN.APP.map" -o "$(EPOCBLDUREL)\PICODRIVEN.APP" \ + "$(EPOCSTATLINKUREL)\EDLL.LIB" --whole-archive "$(EPOCBLDUREL)\PICODRIVEN.in" \ + --no-whole-archive $(LIBSUREL) $(USERLDFLAGS) + -$(ERASE) "$(EPOCBLDUREL)\PICODRIVEN.exp" + petran "$(EPOCBLDUREL)\PICODRIVEN.APP" "$@" \ + -nocall -uid1 0x10000079 -uid2 0x100039ce -uid3 0x1000c193 + -$(ERASE) "$(EPOCBLDUREL)\PICODRIVEN.APP" + +OBJECTSUREL= \ + $(EPOCBLDUREL)\APP.o \ + $(EPOCBLDUREL)\CSIMPLETEXTPARSER.o \ + $(EPOCBLDUREL)\DIALOGS.o \ + $(EPOCBLDUREL)\ENGINE.o \ + $(EPOCBLDUREL)\SIMPLECLIENT.o + +$(EPOCBLDUREL)\PICODRIVEN.in : $(OBJECTSUREL) + if exist "$@" del "$@" + ar cr $@ $^ + + +# REAL TARGET - BUILD VARIANT UDEB + +WHATUDEB : WHATGENERIC + +CLEANUDEB : CLEANBUILDUDEB CLEANRELEASEUDEB + +CLEANBUILDUDEB : + @perl -S ermdir.pl "$(EPOCBLDUDEB)" + +CLEANRELEASEUDEB : CLEANGENERIC + + +UDEB_RELEASEABLES1= \ + \DEV\UIQ21\EPOC32\RELEASE\ARMI\UDEB\PICODRIVEN.APP \ + \DEV\UIQ21\EPOC32\RELEASE\ARMI\UDEB\PICODRIVEN.APP.MAP + +WHATUDEB: + @echo $(UDEB_RELEASEABLES1) + +CLEANRELEASEUDEB: + -$(ERASE) $(UDEB_RELEASEABLES1) + +LISTINGUDEB : MAKEWORKUDEB \ + LISTINGUDEBAPP \ + LISTINGUDEBCSIMPLETEXTPARSER \ + LISTINGUDEBDIALOGS \ + LISTINGUDEBENGINE \ + LISTINGUDEBSIMPLECLIENT + +LIBSUDEB= \ + $(EPOCSTATLINKUDEB)\EDLLSTUB.LIB \ + $(EPOCSTATLINKUDEB)\EGCC.LIB \ + $(EPOCLINKUDEB)\EUSER.LIB \ + $(EPOCLINKUDEB)\WS32.LIB \ + $(EPOCLINKUDEB)\EFSRV.LIB \ + $(EPOCLINKUDEB)\APPARC.LIB \ + $(EPOCLINKUDEB)\CONE.LIB \ + $(EPOCLINKUDEB)\EIKCOCTL.LIB \ + $(EPOCLINKUDEB)\EIKCORE.LIB \ + $(EPOCLINKUDEB)\EIKDLG.LIB \ + $(EPOCLINKUDEB)\EIKCTL.LIB \ + $(EPOCLINKUDEB)\EIKFILE.LIB \ + $(EPOCLINKUDEB)\EGUL.LIB \ + $(EPOCLINKUDEB)\ETEXT.LIB \ + $(EPOCLINKUDEB)\GDI.LIB + +$(EPOCTRGUDEB)\PICODRIVEN.APP : $(EPOCBLDUDEB)\PICODRIVEN.in $(EPOCSTATLINKUDEB)\EDLL.LIB $(LIBSUDEB) + dlltool -m arm_interwork --output-def "$(EPOCBLDUDEB)\PICODRIVEN.inf" "$(EPOCBLDUDEB)\PICODRIVEN.in" + perl -S makedef.pl -Deffile "$(EPOCBLDUDEB)\PICODRIVEN.inf" -1 NewApplication__Fv "$(EPOCBLD)\PICODRIVEN.def" + -$(ERASE) "$(EPOCBLDUDEB)\PICODRIVEN.inf" + dlltool -m arm_interwork --def "$(EPOCBLD)\PICODRIVEN.def" \ + --output-exp "$(EPOCBLDUDEB)\PICODRIVEN.exp" \ + --dllname "PICODRIVEN[1000c193].APP" + ld -s -e _E32Dll -u _E32Dll "$(EPOCBLDUDEB)\PICODRIVEN.exp" --dll \ + --base-file "$(EPOCBLDUDEB)\PICODRIVEN.bas" -o "$(EPOCBLDUDEB)\PICODRIVEN.APP" \ + "$(EPOCSTATLINKUDEB)\EDLL.LIB" --whole-archive "$(EPOCBLDUDEB)\PICODRIVEN.in" \ + --no-whole-archive $(LIBSUDEB) $(USERLDFLAGS) + -$(ERASE) "$(EPOCBLDUDEB)\PICODRIVEN.exp" + -$(ERASE) "$(EPOCBLDUDEB)\PICODRIVEN.APP" + dlltool -m arm_interwork \ + --def "$(EPOCBLD)\PICODRIVEN.def" \ + --dllname "PICODRIVEN[1000c193].APP" \ + --base-file "$(EPOCBLDUDEB)\PICODRIVEN.bas" \ + --output-exp "$(EPOCBLDUDEB)\PICODRIVEN.exp" + -$(ERASE) "$(EPOCBLDUDEB)\PICODRIVEN.bas" + ld -e _E32Dll -u _E32Dll --dll \ + "$(EPOCBLDUDEB)\PICODRIVEN.exp" \ + -Map "$(EPOCTRGUDEB)\PICODRIVEN.APP.map" -o "$(EPOCBLDUDEB)\PICODRIVEN.APP" \ + "$(EPOCSTATLINKUDEB)\EDLL.LIB" --whole-archive "$(EPOCBLDUDEB)\PICODRIVEN.in" \ + --no-whole-archive $(LIBSUDEB) $(USERLDFLAGS) + -$(ERASE) "$(EPOCBLDUDEB)\PICODRIVEN.exp" + objcopy -X "$(EPOCBLDUDEB)\PICODRIVEN.APP" "$(EPOCTRGUDEB)\PICODRIVEN.sym" + petran "$(EPOCBLDUDEB)\PICODRIVEN.APP" "$@" \ + -nocall -uid1 0x10000079 -uid2 0x100039ce -uid3 0x1000c193 + -$(ERASE) "$(EPOCBLDUDEB)\PICODRIVEN.APP" + +OBJECTSUDEB= \ + $(EPOCBLDUDEB)\APP.o \ + $(EPOCBLDUDEB)\CSIMPLETEXTPARSER.o \ + $(EPOCBLDUDEB)\DIALOGS.o \ + $(EPOCBLDUDEB)\ENGINE.o \ + $(EPOCBLDUDEB)\SIMPLECLIENT.o + +$(EPOCBLDUDEB)\PICODRIVEN.in : $(OBJECTSUDEB) + if exist "$@" del "$@" + ar cr $@ $^ + + +# SOURCES + +# Resource Z\SYSTEM\APPS\PICODRIVEN\PICODRIVEN.RSC + +DEPEND= \ + \DEV\UIQ21\EPOC32\INCLUDE\BADEF.RH \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKCDLG.RSG \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKCOCTL.RSG \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKCOLOR.HRH \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKCORE.RSG \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKCTL.RSG \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKDLG.RSG \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKFILE.RSG \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKMISC.RSG \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKON.HRH \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKON.RH \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKON.RSG \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKPRINT.RSG \ + \DEV\UIQ21\EPOC32\INCLUDE\GULFTFLG.HRH \ + \DEV\UIQ21\EPOC32\INCLUDE\UIKON.HRH \ + \DEV\UIQ21\EPOC32\INCLUDE\UIKON.RH \ + \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICODRIVEN.HRH + +GENERIC_RESOURCE : $(EPOCDATA)\Z\SYSTEM\APPS\PICODRIVEN\PICODRIVEN.RSC + +$(EPOCDATA)\Z\SYSTEM\APPS\PICODRIVEN\PICODRIVEN.RSC : \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICODRIVEN.RSS $(DEPEND) + perl -S epocrc.pl -I "." -I "." -I- -I "..\..\..\..\..\EPOC32\INCLUDE" -D__DEBUG_PRINT -DLANGUAGE_SC -u "\DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICODRIVEN.RSS" -o$@ -h"\DEV\UIQ21\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICODRIVEN\ARMI\PICODRIVEN.rsg" -t"\DEV\UIQ21\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICODRIVEN\ARMI" -l"Z\SYSTEM\APPS\PICODRIVEN:\DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER" + perl -S ecopyfile.pl "\DEV\UIQ21\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICODRIVEN\ARMI\PICODRIVEN.rsg" "\DEV\UIQ21\EPOC32\INCLUDE\PICODRIVEN.RSG" + +# Aif PICODRIVEN.AIF + +DEPEND= \ + \DEV\UIQ21\EPOC32\INCLUDE\AIFTOOL.RH + +GENERIC_RESOURCE : $(EPOCDATA)\Z\SYSTEM\APPS\PICODRIVEN\PICODRIVEN.AIF + +$(EPOCDATA)\Z\SYSTEM\APPS\PICODRIVEN\PICODRIVEN.AIF : \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICODRIVENAIF.RSS $(DEPEND) \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICON20X16.BMP \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICON20X16M.BMP \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICON32X32.BMP \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICON32X32M.BMP + perl -S epocaif.pl -o$@ "\DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICODRIVENAIF.RSS" \ + -t"\DEV\UIQ21\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICODRIVEN\ARMI" -l"$(TRGDIR):\DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER"\ + -b"\ + /c8\DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICON20X16.BMP\ + /c8\DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICON20X16M.BMP\ + /c8\DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICON32X32.BMP\ + /c8\DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICON32X32M.BMP" \ + -I "." -I- -I "..\..\..\..\..\EPOC32\INCLUDE" -I "..\..\..\..\..\EPOC32\INCLUDE" + +# Source APP.CPP + +$(EPOCBLDUREL)\APP.lis $(EPOCBLDUREL)\APP.o \ +$(EPOCBLDUDEB)\APP.lis $(EPOCBLDUDEB)\APP.o \ +: \ + \DEV\UIQ21\EPOC32\INCLUDE\APACMDLN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\APADEF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\APAFLREC.H \ + \DEV\UIQ21\EPOC32\INCLUDE\APAID.H \ + \DEV\UIQ21\EPOC32\INCLUDE\APGTASK.H \ + \DEV\UIQ21\EPOC32\INCLUDE\APPARC.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BADESCA.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BAERRHAN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BAMDESCA.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BARSC.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BASCHED.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BITBASE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BITDEV.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BITDEV.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\BITMAP.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BITSTD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BTDEFCOMMPORT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BTDEVICE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BTDEVICE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BTDEVICE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BTMANCLIENT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BTREGISTRY.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BTSDP.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BTSDP.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\BTTYPES.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BTTYPES.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\BTUIUTILOBSERVER.H \ + \DEV\UIQ21\EPOC32\INCLUDE\C32COMM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\C32COMM.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\CDBCOLS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\CDBLEN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\CDBPREFTABLE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COEAUI.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COEAUIB.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COECCNTX.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COECNTRL.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COECOBS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COEDEF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COEHELP.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COEINPUT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COEMAIN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COEUTILS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COEVIEW.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COMMDB.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COMMDB.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COMMDB.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\D32COMM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\D32COMM.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\D32DBMS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\D32DBMS.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\DIAL.H \ + \DEV\UIQ21\EPOC32\INCLUDE\DIAL.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\E32BASE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32BASE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\E32DEF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32DES16.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32DES8.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32HAL.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32KEYS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32PCCD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32STD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32STD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32STD.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\E32SVR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32UID.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32VER.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKALIGN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKAMNT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKAPP.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKAPPUI.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKAUFTY.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKBCTRL.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKBGFTY.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKBTGPC.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKBTGRP.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKBUTB.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKCDLG.RSG \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKCFDLG.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKCHKBX.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKCHLST.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKCLB.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKCMOBS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKCOCTL.RSG \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKCOLOR.HRH \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKCORE.RSG \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKCTGRP.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKCTL.RSG \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKDEF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKDGFTY.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKDIALG.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKDLG.RSG \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKDLGTB.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKDOC.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKDPOBS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKEDWOB.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKENV.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKENV.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKFCTRY.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKFILE.RSG \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKLABEL.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKLBED.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKLBI.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKLBM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKLBO.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKLBV.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKLBVO.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKLBX.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKLIBRY.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKMENUB.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKMENUP.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKMISC.RSG \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKMOBS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKON.HRH \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKON.RSG \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKPRINT.RSG \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKSBFRM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKSBOBS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKSCBUT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKSCRLB.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKTXLBM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKTXLBX.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKVCURS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\ETEL.H \ + \DEV\UIQ21\EPOC32\INCLUDE\ETEL.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\F32FILE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\F32FILE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\FAXDEFN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FBS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FLDBASE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FLDBLTIN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FLDINFO.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FLDSET.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FNTSTORE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FRMLAYDT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FRMPARAM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FRMTLAY.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FRMVIS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GDI.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GDI.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\GRAPHICSACCELERATOR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GULALIGN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GULBORDR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GULCOLOR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GULDEF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GULFTFLG.HRH \ + \DEV\UIQ21\EPOC32\INCLUDE\GULUTIL.H \ + \DEV\UIQ21\EPOC32\INCLUDE\LAFMAIN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\LAFPUBLC.H \ + \DEV\UIQ21\EPOC32\INCLUDE\OPENFONT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\PICODRIVEN.RSG \ + \DEV\UIQ21\EPOC32\INCLUDE\QBTSELECTDLG.H \ + \DEV\UIQ21\EPOC32\INCLUDE\QIKSHUTTER.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32BUF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32BUF.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\S32MEM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32MEM.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\S32PAGE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32PAGE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\S32SHARE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32SHARE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STD.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STOR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STOR.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STRM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STRM.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\SACLIENT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\SACLS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\SAVARSET.H \ + \DEV\UIQ21\EPOC32\INCLUDE\SAVENOTF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\T32WLD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TAGMA.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTETEXT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTETEXT.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTFMLYR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTFMLYR.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTFMSTM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTFRMAT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTFRMAT.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTLAYDC.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTSTYLE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTSTYLE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\UIKON.HRH \ + \DEV\UIQ21\EPOC32\INCLUDE\VWSDEF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\W32STD.H \ + \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\CLIENTSERVER.H \ + \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\APP.H \ + \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\DIALOGS.H \ + \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\ENGINE.H \ + \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICODRIVEN.HRH \ + \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\SIMPLECLIENT.H + +$(EPOCBLDUREL)\APP.o : \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\App.cpp + $(GCCUREL) -I "." $(INCDIR) -o $@ ".\App.cpp" + +LISTINGURELAPP : $(EPOCBLDUREL)\APP.lis + perl -S ecopyfile.pl $? \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\APP.lst.ARMI + +$(EPOCBLDUREL)\APP.lis : \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\App.cpp + $(GCCUREL) -Wa,-adln -I "." $(INCDIR) -o nul: ".\App.cpp" > $@ + +$(EPOCBLDUDEB)\APP.o : \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\App.cpp + $(GCCUDEB) -I "." $(INCDIR) -o $@ ".\App.cpp" + +LISTINGUDEBAPP : $(EPOCBLDUDEB)\APP.lis + perl -S ecopyfile.pl $? \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\APP.lst.ARMI + +$(EPOCBLDUDEB)\APP.lis : \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\App.cpp + $(GCCUDEB) -Wa,-adln -I "." $(INCDIR) -o nul: ".\App.cpp" > $@ + + + +# Source CSIMPLETEXTPARSER.CPP + +$(EPOCBLDUREL)\CSIMPLETEXTPARSER.lis $(EPOCBLDUREL)\CSIMPLETEXTPARSER.o \ +$(EPOCBLDUDEB)\CSIMPLETEXTPARSER.lis $(EPOCBLDUDEB)\CSIMPLETEXTPARSER.o \ +: \ + \DEV\UIQ21\EPOC32\INCLUDE\APADEF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\APAID.H \ + \DEV\UIQ21\EPOC32\INCLUDE\APPARC.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BADESCA.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BAMDESCA.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BARSC.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BASCHED.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BITBASE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BITDEV.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BITDEV.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\BITMAP.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BITSTD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COECNTRL.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COECOBS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COEDEF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COEHELP.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COEINPUT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COEMAIN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32BASE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32BASE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\E32DEF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32DES16.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32DES8.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32HAL.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32KEYS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32PCCD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32STD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32STD.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\E32SVR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKBCTRL.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKBUTB.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKCOLOR.HRH \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKEDWIN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKEDWOB.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKGTED.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKON.HRH \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKRTED.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKSBFRM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKSBOBS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKSCBUT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKSCRLB.H \ + \DEV\UIQ21\EPOC32\INCLUDE\F32FILE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\F32FILE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\FBS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FEPBASE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FLDBASE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FLDBLTIN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FLDINFO.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FLDSET.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FNTSTORE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FRMFRAME.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FRMLAYDT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FRMPARAM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FRMTLAY.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FRMTVIEW.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FRMVIS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GDI.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GDI.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\GRAPHICSACCELERATOR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GULALIGN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GULBORDR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GULDEF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GULFTFLG.HRH \ + \DEV\UIQ21\EPOC32\INCLUDE\GULUTIL.H \ + \DEV\UIQ21\EPOC32\INCLUDE\LAFPUBLC.H \ + \DEV\UIQ21\EPOC32\INCLUDE\MEDOBSRV.H \ + \DEV\UIQ21\EPOC32\INCLUDE\MPARSER.H \ + \DEV\UIQ21\EPOC32\INCLUDE\OPENFONT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32BUF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32BUF.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\S32PAGE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32PAGE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\S32SHARE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32SHARE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STD.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STOR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STOR.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STRM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STRM.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\TAGMA.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTETEXT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTETEXT.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTFMLYR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTFMLYR.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTFMSTM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTFRMAT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTFRMAT.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTGLOBL.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTGLOBL.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTLAYDC.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTMFMTX.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTMRTSR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTRICH.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTRICH.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTSTYLE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTSTYLE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\UIKON.HRH \ + \DEV\UIQ21\EPOC32\INCLUDE\W32STD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\W32STD.H \ + \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\CSIMPLETEXTPARSER.H + +$(EPOCBLDUREL)\CSIMPLETEXTPARSER.o : \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\Csimpletextparser.cpp + $(GCCUREL) -I "." $(INCDIR) -o $@ ".\Csimpletextparser.cpp" + +LISTINGURELCSIMPLETEXTPARSER : $(EPOCBLDUREL)\CSIMPLETEXTPARSER.lis + perl -S ecopyfile.pl $? \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\CSIMPLETEXTPARSER.lst.ARMI + +$(EPOCBLDUREL)\CSIMPLETEXTPARSER.lis : \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\Csimpletextparser.cpp + $(GCCUREL) -Wa,-adln -I "." $(INCDIR) -o nul: ".\Csimpletextparser.cpp" > $@ + +$(EPOCBLDUDEB)\CSIMPLETEXTPARSER.o : \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\Csimpletextparser.cpp + $(GCCUDEB) -I "." $(INCDIR) -o $@ ".\Csimpletextparser.cpp" + +LISTINGUDEBCSIMPLETEXTPARSER : $(EPOCBLDUDEB)\CSIMPLETEXTPARSER.lis + perl -S ecopyfile.pl $? \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\CSIMPLETEXTPARSER.lst.ARMI + +$(EPOCBLDUDEB)\CSIMPLETEXTPARSER.lis : \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\Csimpletextparser.cpp + $(GCCUDEB) -Wa,-adln -I "." $(INCDIR) -o nul: ".\Csimpletextparser.cpp" > $@ + + + +# Source DIALOGS.CPP + +$(EPOCBLDUREL)\DIALOGS.lis $(EPOCBLDUREL)\DIALOGS.o \ +$(EPOCBLDUDEB)\DIALOGS.lis $(EPOCBLDUDEB)\DIALOGS.o \ +: \ + \DEV\UIQ21\EPOC32\INCLUDE\APACMDLN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\APADEF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\APAFLREC.H \ + \DEV\UIQ21\EPOC32\INCLUDE\APAID.H \ + \DEV\UIQ21\EPOC32\INCLUDE\APPARC.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BADESCA.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BAERRHAN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BAMDESCA.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BARSC.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BASCHED.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BITBASE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BITDEV.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BITDEV.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\BITMAP.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BITSTD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\C32COMM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\C32COMM.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\COECCNTX.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COECNTRL.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COECOBS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COEDEF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COEHELP.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COEINPUT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COEMAIN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\D32COMM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\D32COMM.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\E32BASE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32BASE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\E32DEF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32DES16.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32DES8.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32HAL.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32KEYS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32PCCD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32STD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32STD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32STD.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\E32SVR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32VER.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKALIGN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKAMNT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKAUFTY.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKBCTRL.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKBGFTY.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKBTGPC.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKBTGRP.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKBUTB.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKCHKBX.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKCHLST.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKCMOBS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKCOLOR.HRH \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKCTGRP.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKDEF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKDGFTY.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKDIALG.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKDLGTB.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKDPOBS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKEDWIN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKEDWOB.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKENV.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKENV.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKFCTRY.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKGTED.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKHOPBT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKLABEL.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKLBED.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKLBM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKLBO.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKLBV.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKLBVO.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKLBX.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKLIBRY.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKON.HRH \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKOPBUT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKRTED.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKSBFRM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKSBOBS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKSCBUT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKSCRLB.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKTXLBM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKTXLBX.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKVCURS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\ETEL.H \ + \DEV\UIQ21\EPOC32\INCLUDE\ETEL.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\F32FILE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\F32FILE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\FAXDEFN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FBS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FEPBASE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FLDBASE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FLDBLTIN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FLDINFO.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FLDSET.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FNTSTORE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FRMFRAME.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FRMLAYDT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FRMPARAM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FRMTLAY.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FRMTVIEW.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FRMVIS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GDI.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GDI.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\GRAPHICSACCELERATOR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GULALIGN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GULBORDR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GULCOLOR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GULDEF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GULFTFLG.HRH \ + \DEV\UIQ21\EPOC32\INCLUDE\GULUTIL.H \ + \DEV\UIQ21\EPOC32\INCLUDE\LAFMAIN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\LAFPUBLC.H \ + \DEV\UIQ21\EPOC32\INCLUDE\MEDOBSRV.H \ + \DEV\UIQ21\EPOC32\INCLUDE\MPARSER.H \ + \DEV\UIQ21\EPOC32\INCLUDE\OPENFONT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\PICODRIVEN.RSG \ + \DEV\UIQ21\EPOC32\INCLUDE\QIKSHUTTER.H \ + \DEV\UIQ21\EPOC32\INCLUDE\QIKVERTOPTIONBUTTONLIST.H \ + \DEV\UIQ21\EPOC32\INCLUDE\QUARTZKEYS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32BUF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32BUF.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\S32PAGE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32PAGE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\S32SHARE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32SHARE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STD.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STOR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STOR.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STRM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STRM.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\TAGMA.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTETEXT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTETEXT.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTFMLYR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTFMLYR.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTFMSTM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTFRMAT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTFRMAT.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTGLOBL.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTGLOBL.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTLAYDC.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTMFMTX.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTMRTSR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTRICH.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTRICH.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTSTYLE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTSTYLE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\UIKON.HRH \ + \DEV\UIQ21\EPOC32\INCLUDE\W32STD.H \ + \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\CLIENTSERVER.H \ + \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\CSIMPLETEXTPARSER.H \ + \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\DIALOGS.H \ + \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\ENGINE.H \ + \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICODRIVEN.HRH \ + \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\VERSION.H + +$(EPOCBLDUREL)\DIALOGS.o : \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\Dialogs.cpp + $(GCCUREL) -I "." $(INCDIR) -o $@ ".\Dialogs.cpp" + +LISTINGURELDIALOGS : $(EPOCBLDUREL)\DIALOGS.lis + perl -S ecopyfile.pl $? \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\DIALOGS.lst.ARMI + +$(EPOCBLDUREL)\DIALOGS.lis : \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\Dialogs.cpp + $(GCCUREL) -Wa,-adln -I "." $(INCDIR) -o nul: ".\Dialogs.cpp" > $@ + +$(EPOCBLDUDEB)\DIALOGS.o : \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\Dialogs.cpp + $(GCCUDEB) -I "." $(INCDIR) -o $@ ".\Dialogs.cpp" + +LISTINGUDEBDIALOGS : $(EPOCBLDUDEB)\DIALOGS.lis + perl -S ecopyfile.pl $? \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\DIALOGS.lst.ARMI + +$(EPOCBLDUDEB)\DIALOGS.lis : \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\Dialogs.cpp + $(GCCUDEB) -Wa,-adln -I "." $(INCDIR) -o nul: ".\Dialogs.cpp" > $@ + + + +# Source ENGINE.CPP + +$(EPOCBLDUREL)\ENGINE.lis $(EPOCBLDUREL)\ENGINE.o \ +$(EPOCBLDUDEB)\ENGINE.lis $(EPOCBLDUDEB)\ENGINE.o \ +: \ + \DEV\UIQ21\EPOC32\INCLUDE\APACMDLN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\APADEF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\APAFLREC.H \ + \DEV\UIQ21\EPOC32\INCLUDE\APAID.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BADESCA.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BAERRHAN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BAMDESCA.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BARSC.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BASCHED.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BITBASE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BITDEV.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BITDEV.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\BITMAP.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BITSTD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\C32COMM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\C32COMM.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\COEDEF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\COEMAIN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\D32COMM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\D32COMM.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\E32BASE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32BASE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\E32DEF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32DES16.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32DES8.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32HAL.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32KEYS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32PCCD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32STD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32STD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32STD.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\E32SVR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32VER.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKAMNT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKAUFTY.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKCOLOR.HRH \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKDEF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKDGFTY.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKENV.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKFCTRY.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKLIBRY.H \ + \DEV\UIQ21\EPOC32\INCLUDE\EIKVCURS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\ETEL.H \ + \DEV\UIQ21\EPOC32\INCLUDE\ETEL.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\F32FILE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\F32FILE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\FAXDEFN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FBS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FLDBASE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FLDBLTIN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FLDINFO.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FLDSET.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FNTSTORE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FRMLAYDT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FRMPARAM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FRMTLAY.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FRMVIS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GDI.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GDI.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\GRAPHICSACCELERATOR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GULALIGN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GULBORDR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GULCOLOR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GULDEF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\LAFMAIN.H \ + \DEV\UIQ21\EPOC32\INCLUDE\OPENFONT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32BUF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32BUF.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\S32PAGE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32PAGE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\S32SHARE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32SHARE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STD.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STOR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STOR.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STRM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STRM.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\TAGMA.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTETEXT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTETEXT.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTFMLYR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTFMLYR.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTFMSTM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTFRMAT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTFRMAT.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTLAYDC.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTSTYLE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\TXTSTYLE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\UIKON.HRH \ + \DEV\UIQ21\EPOC32\INCLUDE\W32STD.H \ + \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\CLIENTSERVER.H \ + \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\ENGINE.H \ + \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\VERSION.H + +$(EPOCBLDUREL)\ENGINE.o : \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\Engine.cpp + $(GCCUREL) -I "." $(INCDIR) -o $@ ".\Engine.cpp" + +LISTINGURELENGINE : $(EPOCBLDUREL)\ENGINE.lis + perl -S ecopyfile.pl $? \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\ENGINE.lst.ARMI + +$(EPOCBLDUREL)\ENGINE.lis : \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\Engine.cpp + $(GCCUREL) -Wa,-adln -I "." $(INCDIR) -o nul: ".\Engine.cpp" > $@ + +$(EPOCBLDUDEB)\ENGINE.o : \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\Engine.cpp + $(GCCUDEB) -I "." $(INCDIR) -o $@ ".\Engine.cpp" + +LISTINGUDEBENGINE : $(EPOCBLDUDEB)\ENGINE.lis + perl -S ecopyfile.pl $? \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\ENGINE.lst.ARMI + +$(EPOCBLDUDEB)\ENGINE.lis : \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\Engine.cpp + $(GCCUDEB) -Wa,-adln -I "." $(INCDIR) -o nul: ".\Engine.cpp" > $@ + + + +# Source SIMPLECLIENT.CPP + +$(EPOCBLDUREL)\SIMPLECLIENT.lis $(EPOCBLDUREL)\SIMPLECLIENT.o \ +$(EPOCBLDUDEB)\SIMPLECLIENT.lis $(EPOCBLDUDEB)\SIMPLECLIENT.o \ +: \ + \DEV\UIQ21\EPOC32\INCLUDE\BITBASE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BITDEV.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BITDEV.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\BITMAP.H \ + \DEV\UIQ21\EPOC32\INCLUDE\BITSTD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32BASE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32BASE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\E32DEF.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32DES16.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32DES8.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32HAL.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32KEYS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32PCCD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32STD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\E32STD.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\E32SVR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\F32FILE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\F32FILE.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\FBS.H \ + \DEV\UIQ21\EPOC32\INCLUDE\FNTSTORE.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GDI.H \ + \DEV\UIQ21\EPOC32\INCLUDE\GDI.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\GRAPHICSACCELERATOR.H \ + \DEV\UIQ21\EPOC32\INCLUDE\OPENFONT.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STD.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STD.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STRM.H \ + \DEV\UIQ21\EPOC32\INCLUDE\S32STRM.INL \ + \DEV\UIQ21\EPOC32\INCLUDE\W32STD.H \ + \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\CLIENTSERVER.H \ + \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\SIMPLECLIENT.H \ + \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\VERSION.H + +$(EPOCBLDUREL)\SIMPLECLIENT.o : \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\Simpleclient.cpp + $(GCCUREL) -I "." $(INCDIR) -o $@ ".\Simpleclient.cpp" + +LISTINGURELSIMPLECLIENT : $(EPOCBLDUREL)\SIMPLECLIENT.lis + perl -S ecopyfile.pl $? \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\SIMPLECLIENT.lst.ARMI + +$(EPOCBLDUREL)\SIMPLECLIENT.lis : \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\Simpleclient.cpp + $(GCCUREL) -Wa,-adln -I "." $(INCDIR) -o nul: ".\Simpleclient.cpp" > $@ + +$(EPOCBLDUDEB)\SIMPLECLIENT.o : \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\Simpleclient.cpp + $(GCCUDEB) -I "." $(INCDIR) -o $@ ".\Simpleclient.cpp" + +LISTINGUDEBSIMPLECLIENT : $(EPOCBLDUDEB)\SIMPLECLIENT.lis + perl -S ecopyfile.pl $? \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\SIMPLECLIENT.lst.ARMI + +$(EPOCBLDUDEB)\SIMPLECLIENT.lis : \DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\Simpleclient.cpp + $(GCCUDEB) -Wa,-adln -I "." $(INCDIR) -o nul: ".\Simpleclient.cpp" > $@ + + + +ROMFILE: + @echo file=\DEV\UIQ21\EPOC32\RELEASE\ARMI\##BUILD##\PICODRIVEN.APP SYSTEM\APPS\PICODRIVEN\PICODRIVEN.APP + +GENERIC_RELEASEABLES1= \ + $(EPOCDATA)\Z\SYSTEM\APPS\PICODRIVEN\PICODRIVEN.AIF \ + $(EPOCDATA)\Z\SYSTEM\APPS\PICODRIVEN\PICODRIVEN.RSC \ + $(EPOCINC)\PICODRIVEN.RSG \ + \DEV\UIQ21\EPOC32\LOCALISATION\AIF\DEV\PICODRIVEN\AIF\PICODRIVEN.RPP \ + \DEV\UIQ21\EPOC32\LOCALISATION\AIF\DEV\PICODRIVEN\AIF\PICON20X16.BMP \ + \DEV\UIQ21\EPOC32\LOCALISATION\AIF\DEV\PICODRIVEN\AIF\PICON20X16M.BMP \ + \DEV\UIQ21\EPOC32\LOCALISATION\AIF\DEV\PICODRIVEN\AIF\PICON32X32.BMP \ + \DEV\UIQ21\EPOC32\LOCALISATION\AIF\DEV\PICODRIVEN\AIF\PICON32X32M.BMP \ + \DEV\UIQ21\EPOC32\LOCALISATION\DEV\PICODRIVEN\RSC\PICODRIVEN.RPP \ + \DEV\UIQ21\EPOC32\LOCALISATION\GROUP\PICODRIVEN.INFO + +WHATGENERIC: + @echo $(GENERIC_RELEASEABLES1) + +CLEANGENERIC: + -$(ERASE) $(GENERIC_RELEASEABLES1) + +# Rules to create all necessary directories + +GENERIC_MAKEWORK : \ + \DEV\UIQ21\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICODRIVEN\ARMI \ + \DEV\UIQ21\EPOC32\DATA\Z\SYSTEM\APPS\PICODRIVEN \ + \DEV\UIQ21\EPOC32\INCLUDE +MAKEWORKLIBRARY : \ + \DEV\UIQ21\EPOC32\RELEASE\ARMI\UREL +MAKEWORKUDEB : \ + \DEV\UIQ21\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICODRIVEN\ARMI\UDEB \ + \DEV\UIQ21\EPOC32\RELEASE\ARMI\UDEB +MAKEWORKUREL : \ + \DEV\UIQ21\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICODRIVEN\ARMI\UREL \ + \DEV\UIQ21\EPOC32\RELEASE\ARMI\UREL + +\DEV\UIQ21\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICODRIVEN\ARMI \ +\DEV\UIQ21\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICODRIVEN\ARMI\UDEB \ +\DEV\UIQ21\EPOC32\BUILD\DEV\UIQ21\_SRC\PICODRIVEN\PLATFORM\UIQ2\LAUNCHER\PICODRIVEN\ARMI\UREL \ +\DEV\UIQ21\EPOC32\DATA\Z\SYSTEM\APPS\PICODRIVEN \ +\DEV\UIQ21\EPOC32\INCLUDE \ +\DEV\UIQ21\EPOC32\RELEASE\ARMI\UDEB \ +\DEV\UIQ21\EPOC32\RELEASE\ARMI\UREL \ +: + perl -S emkdir.pl $@ + diff --git a/platform/uiq2/launcher/PicoN20x16.bmp b/platform/uiq2/launcher/PicoN20x16.bmp new file mode 100644 index 00000000..859f6d06 Binary files /dev/null and b/platform/uiq2/launcher/PicoN20x16.bmp differ diff --git a/platform/uiq2/launcher/PicoN20x16m.bmp b/platform/uiq2/launcher/PicoN20x16m.bmp new file mode 100644 index 00000000..578b643d Binary files /dev/null and b/platform/uiq2/launcher/PicoN20x16m.bmp differ diff --git a/platform/uiq2/launcher/PicoN32x32.bmp b/platform/uiq2/launcher/PicoN32x32.bmp new file mode 100644 index 00000000..292e1c2a Binary files /dev/null and b/platform/uiq2/launcher/PicoN32x32.bmp differ diff --git a/platform/uiq2/launcher/PicoN32x32m.bmp b/platform/uiq2/launcher/PicoN32x32m.bmp new file mode 100644 index 00000000..69f15e99 Binary files /dev/null and b/platform/uiq2/launcher/PicoN32x32m.bmp differ diff --git a/platform/uiq2/launcher/PicodriveN.hrh b/platform/uiq2/launcher/PicodriveN.hrh new file mode 100644 index 00000000..c2a4aee6 --- /dev/null +++ b/platform/uiq2/launcher/PicodriveN.hrh @@ -0,0 +1,70 @@ + +enum TAppMenuCommands +{ + // Emu menu + EEikCmdPicoLoadState = 10000, + EEikCmdPicoSaveState, + EEikCmdPicoLoadROM, + EEikCmdPicoResume, + EEikCmdPicoReset, + EEikCmdPicoKeys, + EEikCmdPicoSettings, + + // Frameskip menu + EEikCmdPicoFrameskipAuto, + EEikCmdPicoFrameskip0, + EEikCmdPicoFrameskip1, + EEikCmdPicoFrameskip2, + EEikCmdPicoFrameskip4, + EEikCmdPicoFrameskip8, + + // Debug menu + EEikCmdPicoDebugKillEmu, + EEikCmdPicoDebugInfo, + + // config Dialog + // pages + ECtlOptPageMain, + ECtlOptPageSound, + ECtlOptPageMisc, + // main page + ECtlOptRotationLabel, + ECtlOptRotation, + ECtlOptRotation0, + ECtlOptRotation90, + ECtlOptRotation180, + ECtlOptRotation270, + ECtlOptScreenModeLabel, + ECtlOptScreenMode, + ECtlOptScreenModeCenter, + ECtlOptScreenModeFit, + ECtlOptScreenModeFit2, + ECtlOptUseAltRend, + ECtlOptUseAccTiming, + ECtlOptUseAccSprites, + ECtlOptShowFPS, + // sound page + ECtlOptEnableSound, + ECtlOptChipSelLabel, + ECtlOptEmulateZ80, + ECtlOptEmulateYM2612, + ECtlOptEmulateSN76496, + ECtlOptSndQLabel, + ECtlOptSndQuality, + // misc page + ECtlOpt6ButtonPad, + ECtlOptGzipStates, + ECtlOptUseSRAM, + ECtlOptMotDontUseVol, + ECtlOptRegionLabel, + ECtlOptRegion, + // credits + ECtlCredits, + // debug + ECtlDebugEdit +}; + + +#define ECtlAboutVersion 1 +#define ECtlAboutLinks 2 + diff --git a/platform/uiq2/launcher/PicodriveN.mmp b/platform/uiq2/launcher/PicodriveN.mmp new file mode 100644 index 00000000..63628608 --- /dev/null +++ b/platform/uiq2/launcher/PicodriveN.mmp @@ -0,0 +1,34 @@ +TARGET PicodriveN.app +TARGETTYPE app +TARGETPATH \system\Apps\PicodriveN +UID 0x100039CE 0x1000C193 + + +USERINCLUDE . + +SYSTEMINCLUDE \epoc32\include + +SOURCEPATH . +SOURCE App.cpp +SOURCE Engine.cpp +SOURCE Dialogs.cpp +SOURCE CSimpleTextParser.cpp +SOURCE SimpleClient.cpp + +LIBRARY EUSER.LIB WS32.LIB EFSRV.LIB +LIBRARY APPARC.LIB CONE.LIB +LIBRARY EIKCOCTL.LIB EIKCORE.LIB EIKDLG.LIB EIKCTL.LIB +LIBRARY EIKFILE.LIB // CEikFileOpenDialog +LIBRARY EGUL.LIB // CColorList +LIBRARY ETEXT.LIB // TCharFormat +LIBRARY GDI.LIB // TTypeface + +//LIBRARY ETEL.LIB +//LIBRARY APGRFX.LIB FBSCLI.LIB bafl.lib BITGDI.LIB + +SOURCEPATH . +RESOURCE PicodriveN.rss + +//MACRO __DEBUG_PRINT + +AIF PicodriveN.aif . PicodriveNAif.rss c8 PicoN20x16.bmp PicoN20x16m.bmp PicoN32x32.bmp PicoN32x32m.bmp diff --git a/platform/uiq2/launcher/PicodriveN.rss b/platform/uiq2/launcher/PicodriveN.rss new file mode 100644 index 00000000..d4db38a7 --- /dev/null +++ b/platform/uiq2/launcher/PicodriveN.rss @@ -0,0 +1,474 @@ +NAME PDN + +#include +#include +#include "picodriven.hrh" + + +RESOURCE RSS_SIGNATURE { } + +RESOURCE TBUF { buf=""; } + +RESOURCE EIK_APP_INFO + { + menubar=r_app_menubar; + hotkeys=r_app_hotkeys; + } + +RESOURCE HOTKEYS r_app_hotkeys + { + control= + { + HOTKEY { command=EEikCmdExit; key='e'; } + }; + } + +RESOURCE MENU_BAR r_app_menubar + { + titles= + { + MENU_TITLE { menu_pane=r_app_emu_menu; txt="Emu"; }, + MENU_TITLE { menu_pane=r_app_frameskip_menu; txt="Frameskip"; } +#ifdef __DEBUG_PRINT + ,MENU_TITLE { menu_pane=r_app_debug_menu; txt="Debug"; } +#endif + }; + } + +RESOURCE MENU_PANE r_app_emu_menu + { + items= + { + MENU_ITEM { command=EEikCmdPicoLoadState; txt="Load state"; flags=EEikMenuItemDimmed; }, + MENU_ITEM { command=EEikCmdPicoSaveState; txt="Save state"; flags=EEikMenuItemDimmed; }, + MENU_ITEM { command=EEikCmdPicoLoadROM; txt="Load new ROM"; }, + MENU_ITEM { command=EEikCmdPicoResume; txt="Resume game"; flags=EEikMenuItemDimmed; }, + MENU_ITEM { command=EEikCmdPicoReset; txt="Reset game"; flags=EEikMenuItemDimmed; }, + MENU_ITEM { command=EEikCmdPicoKeys; txt="Configure keys"; }, + MENU_ITEM { command=EEikCmdPicoSettings; txt="Settings"; }, + MENU_ITEM { command=EEikCmdHelpAbout; txt="About"; flags=EEikMenuItemSeparatorAfter; }, + MENU_ITEM { command=EEikCmdExit; txt="Exit"; } + }; + } + +RESOURCE MENU_PANE r_app_frameskip_menu + { + items= + { + MENU_ITEM { command=EEikCmdPicoFrameskipAuto; txt="Auto"; flags=EEikMenuItemRadioStart | EEikMenuItemSeparatorAfter; }, + MENU_ITEM { command=EEikCmdPicoFrameskip0; txt="0"; flags=EEikMenuItemRadioMiddle; }, + MENU_ITEM { command=EEikCmdPicoFrameskip1; txt="1"; flags=EEikMenuItemRadioMiddle; }, + MENU_ITEM { command=EEikCmdPicoFrameskip2; txt="2"; flags=EEikMenuItemRadioMiddle; }, + MENU_ITEM { command=EEikCmdPicoFrameskip4; txt="4"; flags=EEikMenuItemRadioMiddle; }, + MENU_ITEM { command=EEikCmdPicoFrameskip8; txt="8"; flags=EEikMenuItemRadioEnd; } + }; + } + +RESOURCE MENU_PANE r_app_debug_menu + { + items= + { + MENU_ITEM { command=EEikCmdPicoDebugKillEmu; txt="Kill emu proc"; }, + MENU_ITEM { command=EEikCmdPicoDebugInfo; txt="info"; } + }; + } + + + +/************************************** + * + * about dialog + * + **************************************/ + +RESOURCE DIALOG r_dialog_about +{ + title = "About"; + buttons = r_buttons_continue_credits; + flags = EEikDialogFlagWait; + items = + { + DLG_LINE + { + itemflags = EQikDlgItemUseFullWidth | EQikDlgItemDenselyPacked; + type = EEikCtRichTextEditor; + id = ECtlAboutVersion; + control = RTXTED + { + flags = EEikEdwinResizable | EEikEdwinNoAutoSelection | EEikEdwinReadOnly | EEikEdwinWidthInPixels; + numlines = 4; + }; + }, + DLG_LINE + { + itemflags = EQikDlgItemUseFullWidth | EQikDlgItemDenselyPacked; + type = EEikCtRichTextEditor; + id = ECtlAboutLinks; + control = RTXTED + { + flags = EEikEdwinResizable | EEikEdwinNoAutoSelection | EEikEdwinReadOnly | EEikEdwinWidthInPixels | 0x00200000; + numlines = 4; + }; + } + }; +} + +RESOURCE DLG_BUTTONS r_buttons_continue_credits +{ + buttons = + { + DLG_BUTTON { id = EEikBidYes; button = CMBUT { txt = "Credits"; }; }, + DLG_BUTTON { id = EEikBidCancel; button = CMBUT { txt = "Continue"; }; flags=EEikLabeledButtonIsDefault; } + }; +} + + +RESOURCE TBUF r_simple_text_about_links +{ + buf= + "Email: notasas@gmail.com"\ + "

Web:

http://notaz.atspace.com"\ + "

Dave's Web:

http://www.finalburn.com"; +} + + +RESOURCE TBUF r_simple_text_about +{ + buf= + "PicodriveN"\ + "

for UIQ2"\ + "

Version %S, by notaz."\ + "

Port based on PicoDrive 0.030 for Pocket PC by Dave"; +} + + +RESOURCE DIALOG r_dialog_credits +{ + title = "Credits and thanks"; + buttons = R_EIK_BUTTONS_DONE; + flags = EEikDialogFlagWait; + items = + { + DLG_LINE + { + type = EEikCtGlobalTextEditor; + id = ECtlCredits; + control = GTXTED + { + width = 150; height = 200; numlines = 26; flags = EEikEdwinReadOnly | EEikEdwinNoAutoSelection | EEikEdwinDisplayOnly; + }; + } + }; +} + + +RESOURCE ARRAY r_tbuf_credits +{ + items= + { + LBUF{txt="This emulator uses code from these people / projects:";}, + LBUF{txt="";}, + LBUF{txt="Dave";}, + LBUF{txt="- Cyclone 68000 core, Pico emulation library";}, + LBUF{txt="Homepage: http://www.finalburn.com/";}, + LBUF{txt="E-mail: david(atsymbol)finalburn.com";}, + LBUF{txt="";}, + LBUF{txt="Reesy & FluBBa";}, + LBUF{txt="- DrZ80, the Z80 emulator written in ARM assembly.";}, + LBUF{txt="Homepage: http://reesy.gp32x.de/";}, + LBUF{txt="E-mail: drsms_reesy(atsymbol)yahoo.co.uk";}, + LBUF{txt="";}, + LBUF{txt="Tatsuyuki Satoh, Jarek Burczynski, MultiArcadeMachineEmulator (MAME) development";}, + LBUF{txt="- software implementation of Yamaha FM sound generator and";}, + LBUF{txt="Texas Instruments SN76489 / SN76496 programmable tone / noise generator";}, + LBUF{txt="Homepage: http://www.mame.net/";}, + LBUF{txt="";}, + LBUF{txt="Additional thanks:";}, + LBUF{txt="- Peter van Sebille for ECompXL and his various open-source Symbian projects to learn from.";}, + LBUF{txt="- Steve Fischer for his open-source Motorola projects.";}, + LBUF{txt="- Charles MacDonald (http://cgfm2.emuviews.com/) for old but still very useful info about genesis hardware.";}, + LBUF{txt="- Stéphane Dallongeville for creating Gens and making it open-source.";}, + LBUF{txt="- Steve Snake for all that he has done for Genesis emulation scene.";}, + LBUF{txt="- Bart Trzynadlowski for his SSFII and 68000 docs.";}, + LBUF{txt="- Haze for his research (http://haze.mameworld.info).";}, + LBUF{txt="- The development team behind \"Symbian GCC Improvement Project \" (http://www.inf.u-szeged.hu/symbian-gcc/) for their updated compile tools.";}, + LBUF{txt="- Mark and Jean-loup for zlib library.";}, + LBUF{txt="- Reesy for also finding some Cyclone bugs.";}, + LBUF{txt="- Inder for the icons.";} + }; +} + + +/************************************** + * + * debug dialog + * + **************************************/ + +RESOURCE DIALOG r_dialog_debug +{ + title = "debug"; + buttons = R_EIK_BUTTONS_DONE; + flags = EEikDialogFlagWait; + items = + { + DLG_LINE + { + type = EEikCtGlobalTextEditor; + id = ECtlDebugEdit; + control = GTXTED + { + width = 150; height = 200; numlines = 26; flags = EEikEdwinReadOnly | EEikEdwinNoAutoSelection | EEikEdwinDisplayOnly; + }; + } + }; +} + + +/************************************** + * + * config dialog + * + **************************************/ + +RESOURCE DIALOG r_pico_config +{ + title = "Settings"; + buttons = R_EIK_BUTTONS_CANCEL_OK; + flags = EEikDialogFlagWait; + pages = r_pico_config_pages; +} + +RESOURCE ARRAY r_pico_config_pages +{ + items = { + PAGE + { + id = ECtlOptPageMain; + text = "Main"; + lines = r_pico_config_page_main; + }, + PAGE + { + id = ECtlOptPageSound; + text = "Sound"; + lines = r_pico_config_page_sound; + }, + PAGE + { + id = ECtlOptPageMisc; + text = "Misc"; + lines = r_pico_config_page_misc; + } + }; +} + + +RESOURCE ARRAY r_pico_config_page_main +{ + items = { + DLG_LINE + { + id = ECtlOptRotationLabel; + type = EEikCtLabel; + prompt = "Screen Rotation"; + control = LABEL { horiz_align = EEikLabelAlignHLeft; }; + }, + DLG_LINE + { + id = ECtlOptRotation; + type = EEikCtHorOptionButList; + control = HOROPBUT + { + array_id = r_pico_config_rotation_buttons; + }; + }, + DLG_LINE + { + id = ECtlOptScreenModeLabel; + type = EEikCtLabel; + prompt = "Screen Mode"; + control = LABEL { horiz_align = EEikLabelAlignHLeft; }; + }, + DLG_LINE + { + id = ECtlOptScreenMode; + type = EEikCtHorOptionButList; + control = HOROPBUT + { + array_id = r_pico_config_screenmode_buttons; + }; + }, + DLG_LINE + { + id = ECtlOptUseAltRend; + type = EEikCtCheckBox; + prompt = "Fast renderer (inaccurate)"; + }, + DLG_LINE + { + id = ECtlOptUseAccTiming; + type = EEikCtCheckBox; + prompt = "Accurate timing (slower)"; + }, + DLG_LINE + { + id = ECtlOptUseAccSprites; + type = EEikCtCheckBox; + prompt = "Accurate sprites (slower)"; + }, + DLG_LINE + { + id = ECtlOptShowFPS; + type = EEikCtCheckBox; + prompt = "Show FPS"; + } + }; +} + + +RESOURCE ARRAY r_pico_config_page_sound +{ + items = { + DLG_LINE + { + id = ECtlOptEnableSound; + type = EEikCtCheckBox; + prompt = "Enable sound"; + }, + DLG_LINE + { + id = ECtlOptChipSelLabel; + type = EEikCtLabel; + prompt = "Emulate these sound chips:"; + control = LABEL { horiz_align = EEikLabelAlignHLeft; }; + }, + DLG_LINE + { + id = ECtlOptEmulateZ80; + type = EEikCtCheckBox; + prompt = "Z80"; + }, + DLG_LINE + { + id = ECtlOptEmulateYM2612; + type = EEikCtCheckBox; + prompt = "YM2612"; + }, + DLG_LINE + { + id = ECtlOptEmulateSN76496; + type = EEikCtCheckBox; + prompt = "SN76496 (PSG)"; + }, + DLG_LINE + { + id = ECtlOptSndQLabel; + type = EEikCtLabel; + prompt = "Quality (lowest is fastest)"; + control = LABEL { horiz_align = EEikLabelAlignHLeft; }; + }, + DLG_LINE + { + id = ECtlOptSndQuality; + type = EEikCtChoiceList; + prompt = ""; + control = CHOICELIST { array_id = r_pico_config_snd_quality; }; + itemflags = EEikDlgItemNonFocusing; + } + }; +} + + +RESOURCE ARRAY r_pico_config_page_misc +{ + items = { + DLG_LINE + { + id = ECtlOpt6ButtonPad; + type = EEikCtCheckBox; + prompt = "6 button pad"; + }, + DLG_LINE + { + id = ECtlOptGzipStates; + type = EEikCtCheckBox; + prompt = "gzip save states"; + }, + DLG_LINE + { + id = ECtlOptUseSRAM; + type = EEikCtCheckBox; + prompt = "Use SRAM saves (.srm)"; + }, + DLG_LINE + { + id = ECtlOptMotDontUseVol; + type = EEikCtCheckBox; + prompt = "Motorola: don't use volume keys for game controls"; + }, + DLG_LINE + { + id = ECtlOptRegionLabel; + type = EEikCtLabel; + prompt = "Region: "; + control = LABEL { horiz_align = EEikLabelAlignHLeft; }; + }, + DLG_LINE + { + id = ECtlOptRegion; + type = EEikCtChoiceList; + prompt = ""; + control = CHOICELIST { array_id = r_pico_config_region; }; + itemflags = EEikDlgItemNonFocusing; + } + }; +} + + +RESOURCE ARRAY r_pico_config_rotation_buttons +{ + items = { + OPBUT { id = ECtlOptRotation0; text = "0º"; }, + OPBUT { id = ECtlOptRotation90; text = "90º"; }, + OPBUT { id = ECtlOptRotation180; text = "180º"; }, + OPBUT { id = ECtlOptRotation270; text = "270º"; } + }; +} + + +RESOURCE ARRAY r_pico_config_screenmode_buttons +{ + items = { + OPBUT { id = ECtlOptScreenModeCenter; text = "Center"; }, + OPBUT { id = ECtlOptScreenModeFit; text = "Fit"; }, + OPBUT { id = ECtlOptScreenModeFit2; text = "Fit2"; } + }; +} + + +RESOURCE ARRAY r_pico_config_snd_quality +{ + items = { + LBUF { txt = "8000Hz mono"; }, + LBUF { txt = "11025Hz mono"; }, + LBUF { txt = "16000Hz mono"; }, + LBUF { txt = "22050Hz mono"; }, + LBUF { txt = "8000Hz stereo"; }, + LBUF { txt = "11025Hz stereo"; }, + LBUF { txt = "16000Hz stereo"; }, + LBUF { txt = "22050Hz stereo"; } + }; +} + + +RESOURCE ARRAY r_pico_config_region +{ + items = { + LBUF { txt = "Auto"; }, + LBUF { txt = "Europe"; }, + LBUF { txt = "USA"; }, + LBUF { txt = "Japan PAL"; }, + LBUF { txt = "Japan NTSC"; } + }; +} diff --git a/platform/uiq2/launcher/PicodriveNAif.rss b/platform/uiq2/launcher/PicodriveNAif.rss new file mode 100644 index 00000000..d39cf281 --- /dev/null +++ b/platform/uiq2/launcher/PicodriveNAif.rss @@ -0,0 +1,14 @@ +#include + +RESOURCE AIF_DATA +{ + app_uid=0x1000C193; + caption_list= + { + CAPTION { code=ELangEnglish; caption="PicodriveN"; } + }; + num_icons=2; + embeddability=KAppNotEmbeddable; + newfile=KAppDoesNotSupportNewFile; +} + diff --git a/platform/uiq2/launcher/SimpleClient.cpp b/platform/uiq2/launcher/SimpleClient.cpp new file mode 100644 index 00000000..e653721d --- /dev/null +++ b/platform/uiq2/launcher/SimpleClient.cpp @@ -0,0 +1,33 @@ + +// needed for client interface +#include "../version.h" +#include "../ClientServer.h" +#include "SimpleClient.h" + + +// Connect to the server - default number of message slots = 4 +TInt RServSession::Connect() +{ + TInt r=CreateSession(KServerName,Version(),kDefaultMessageSlots); + return(r); +} + + +// Return the client side version number. +TVersion RServSession::Version(void) const +{ + return(TVersion(KPicoMajorVersionNumber,KPicoMinorVersionNumber,0)); +} + + +TInt RServSession::SendReceive(TInt aFunction, TAny* aPtr) const +{ + return RSessionBase::SendReceive(aFunction, aPtr); +} + + +TInt RServSession::Send(TInt aFunction, TAny* aPtr) const +{ + return RSessionBase::Send(aFunction, aPtr); +} + diff --git a/platform/uiq2/launcher/SimpleClient.h b/platform/uiq2/launcher/SimpleClient.h new file mode 100644 index 00000000..11cd7a01 --- /dev/null +++ b/platform/uiq2/launcher/SimpleClient.h @@ -0,0 +1,23 @@ +#ifndef __SERVSESSION_H__ +#define __SERVSESSION_H__ + +#include + + +//********************************** +// RServSession +//********************************** + +class RServSession : public RSessionBase +{ +public: + RServSession() {} + TInt Connect(); + TVersion Version() const; + TInt SendReceive(TInt aFunction,TAny* aPtr) const; + TInt Send(TInt aFunction,TAny* aPtr) const; +}; + + +#endif + diff --git a/platform/uiq2/launcher/nicemake.c b/platform/uiq2/launcher/nicemake.c new file mode 100644 index 00000000..bb48c05c --- /dev/null +++ b/platform/uiq2/launcher/nicemake.c @@ -0,0 +1,101 @@ +#include +#include +#include + + +void targetname(char *dest, char *src) +{ + char *p, *p1; + + if(strlen(src) < 5 || src[0] == '\t') return; + + // goto string end + for(p=src; *p && *p != ' ' && *p != '\r'; p++); + // goto start + for(p1=p; p1 > src && *p1 != '\\'; p1--); p1++; + if(p-p1 > 0) { + strncpy(dest, p1, p-p1); + dest[p-p1] = 0; + } +} + + +int main(int argc, char *argv[]) +{ + FILE *f = 0, *fo = 0; + unsigned char buff[512], buff2[128], outname[512]; + buff2[0] = 0; + + if(argc != 2) { + printf("usage: %s \n\n", argv[0]); + return 1; + } + + f = fopen(argv[1], "r"); + if(!f) { + printf("%s: couldn't open %s\n", argv[0], argv[1]); + return 2; + } + + strcpy(outname, argv[1]); + strcat(outname, ".out"); + fo = fopen(outname, "w"); + if(!fo) { + fclose(f); + printf("%s: couldn't open %s for writing\n", argv[0], outname); + return 3; + } + + + while(!feof(f)) { + fgets(buff, 512, f); + if(!strncmp(buff, "\t$(GCCUREL)", 11) && !strchr(buff, '>')) { + fprintf(fo, "\t@echo %s: gcc\n\t@$(GCCUREL)", buff2); + fputs(buff+11, fo); + } else if(!strncmp(buff, "\tperl -S ecopyfile.pl", 21) && !strchr(buff, '>')) { + fprintf(fo, "\t@echo %s: perl -S ecopyfile.pl\n\t@perl", buff2); + fputs(buff+5, fo); + } else if(!strncmp(buff, "\tperl -S epocrc.pl", 18) && !strchr(buff, '>')) { + fprintf(fo, "\t@echo %s: perl -S epocrc.pl\n\t@perl", buff2); + fputs(buff+5, fo); + } else if(!strncmp(buff, "\tperl -S epocaif.pl", 19) && !strchr(buff, '>')) { + fprintf(fo, "\t@echo %s: perl -S epocaif.pl\n\t@perl", buff2); + fputs(buff+5, fo); + } else if(!strncmp(buff, "\tperl -S emkdir.pl", 18) && !strchr(buff, '>')) { + fprintf(fo, "\t@echo %s: perl -S emkdir.pl\n\t@perl", buff2); + fputs(buff+5, fo); + } else if(!strncmp(buff, "\tperl -S makedef.pl", 18) && !strchr(buff, '>')) { + fprintf(fo, "\t@echo %s: perl -S makedef.pl\n\t@perl", buff2); + fputs(buff+5, fo); + } else if(!strncmp(buff, "\tld ", 4) && !strchr(buff, '>')) { + fprintf(fo, "\t@echo %s: ld\n\t@ld ", buff2); + fputs(buff+4, fo); + } else if(!strncmp(buff, "\tar ", 4) && !strchr(buff, '>')) { + fprintf(fo, "\t@echo %s: ar\n\t@ar ", buff2); + fputs(buff+4, fo); + } else if(!strncmp(buff, "\tif exist ", 10) && !strchr(buff, '>')) { + fprintf(fo, "\t@echo %s: if exist (del?)\n\t@if exist ", buff2); + fputs(buff+10, fo); + } else if(!strncmp(buff, "\tdlltool ", 9) && !strchr(buff, '>')) { + fprintf(fo, "\t@echo %s: dlltool\n\t@dlltool ", buff2); + fputs(buff+9, fo); + } else if(!strncmp(buff, "\tpetran ", 8) && !strchr(buff, '>')) { + fprintf(fo, "\t@echo %s: petran\n\t@petran ", buff2); + fputs(buff+8, fo); + } else { + // try to get new targetname + targetname(buff2, buff); + fputs(buff, fo); + } + } + + + // done! + fclose(f); + fclose(fo); + + remove(argv[1]); + rename(outname, argv[1]); + + return 0; +} diff --git a/platform/uiq2/launcher/nicemake.exe b/platform/uiq2/launcher/nicemake.exe new file mode 100644 index 00000000..95c7317a Binary files /dev/null and b/platform/uiq2/launcher/nicemake.exe differ diff --git a/platform/uiq2/launcher/quploadpicol.cmd b/platform/uiq2/launcher/quploadpicol.cmd new file mode 100644 index 00000000..7cc4f14e --- /dev/null +++ b/platform/uiq2/launcher/quploadpicol.cmd @@ -0,0 +1 @@ +@..\..\..\..\qconsole-1.60\qtty-1.60\release\qtty --qc-addr P800 --qc-channel 5 --user qconsole --pass server --cmds "put d:\system\apps\picodriven\PICODRIVEN.APP ..\..\..\..\..\epoc32\release\armi\urel\PICODRIVEN.APP" "put d:\system\apps\picodriven\PICODRIVEN.rsc ..\..\..\..\..\epoc32\data\z\system\apps\PicodriveN\PICODRIVEN.rsc" exit diff --git a/platform/uiq2/main.cpp b/platform/uiq2/main.cpp new file mode 100644 index 00000000..d937bf7f --- /dev/null +++ b/platform/uiq2/main.cpp @@ -0,0 +1,1183 @@ +// mainloop with window server event handling +// event polling mechnism was taken from +// Peter van Sebille's projects + +// (c) Copyright 2006, notaz +// All Rights Reserved + +#include + +#include +#include +#include + +#include "debug.h" + +#include "pico/picoInt.h" +#include "vid.h" +#include "SimpleServer.h" +#include "ClientServer.h" +//#include "polledAS.h" +#include "audio.h" + +#include +#include "zlib/gzio_symb.h" + + +#define BENCHMARK +//#define TEST_FRAMEBUFF + +// keycodes we care about +enum TPxxxKeyCodes { + EKeyPxxxPower = EKeyDevice0, //0xF842 + EKeyPxxxBrowser = EKeyApplication0, + EKeyPxxxCamera = EKeyApplication1, + EKeyPxxxJogUp = EKeyDevice1, + EKeyPxxxJogDown = EKeyDevice2, + EKeyPxxxJogLeft = EKeyDevice3, + EKeyPxxxJogRight = EKeyDevice9, + EKeyPxxxJogInward= EKeyDevice8, + // FC keys + //EKeyPxxxFcOk = EKeyDevice8, // don't care about FC keycodes +}; +// EKeyScreenDimension1 ~ EStdKeyF24 is sent when flip is closed, +// EKeyScreenDimension0 ~ EStdKeyF23 when opened + +enum TMotAKeyCodes { + EKeyMotAUp = EKeyDevice4, //0xF846 + EKeyMotADown = EKeyDevice5, + EKeyMotALeft = EKeyDevice6, + EKeyMotARight = EKeyDevice7, + EKeyMotASelect = EKeyDevice8, + EKeyMotAButton1 = EKeyApplicationA, + EKeyMotAButton2 = EKeyApplicationB, + EKeyMotAHome = EKeyApplication0, + EKeyMotAShortcut = EKeyApplication1, + EKeyMotAVoice = EKeyDeviceA, + EKeyMotACamera = EKeyDeviceB, + EKeyMotAVolUp = EKeyIncVolume, + EKeyMotAVolDn = EKeyDecVolume, + EKeyMotASend = EKeyYes, + EKeyMotAEnd = EKeyNo, +}; + +// scancodes we care about +enum TPxxxScanCodes { + EScanPxxxPower = EStdKeyDevice0, // 0xa4 + EScanPxxxBrowser = EStdKeyApplication0, + EScanPxxxCamera = EStdKeyApplication1, + EScanPxxxJogUp = EStdKeyDevice1, + EScanPxxxJogDown = EStdKeyDevice2, + EScanPxxxJogLeft = EStdKeyDeviceE, // not consistent + EScanPxxxJogRight = EStdKeyDeviceD, + EScanPxxxJogInward= EStdKeyDevice8, + // FC keys + EScanPxxxFcOk = EStdKeyDeviceF, + EScanPxxxFcBack = EStdKeyDevice3, + EScanPxxxFcC = EStdKeyDeviceA, + EScanPxxxFcMenu = EStdKeyDevice9, + EScanPxxxFc0 = '0', + EScanPxxxFc1 = '1', + EScanPxxxFc2 = '2', + EScanPxxxFc3 = '3', + EScanPxxxFc4 = '4', + EScanPxxxFc5 = '5', + EScanPxxxFc6 = '6', + EScanPxxxFc7 = '7', + EScanPxxxFc8 = '8', + EScanPxxxFc9 = '9', + EScanPxxxFcHash = EStdKeyHash, + EScanPxxxFcAsterisk= EStdKeyNkpAsterisk, +}; + +enum TMotAScanCodes { + EScanMotAUp = EStdKeyDevice4, + EScanMotADown = EStdKeyDevice5, + EScanMotALeft = EStdKeyDevice6, + EScanMotARight = EStdKeyDevice7, + EScanMotASelect = EStdKeyDevice8, + EScanMotAButton1 = EStdKeyApplicationA, + EScanMotAButton2 = EStdKeyApplicationB, + EScanMotAHome = EStdKeyApplication0, + EScanMotAShortcut = EStdKeyApplication1, + EScanMotAVoice = EStdKeyDeviceA, + EScanMotACamera = EStdKeyDeviceB, + EScanMotAVolUp = EStdKeyIncVolume, + EScanMotAVolDn = EStdKeyDecVolume, + EScanMotASend = EStdKeyYes, + EScanMotAEnd = EStdKeyNo, + // some extra codes, don't know if these are actually used + EScanMotAExtra = EStdKeyApplicationC, + EScanMotAEsc = EStdKeyApplicationD, + EScanMotAStart = EStdKeyApplicationE, + EScanMotASelect2 = EStdKeyApplicationF, +}; + + +// list of key names and codes +TPicoKeyConfigEntry keyConfigPXXX[] = { + { EKeyPxxxPower, EScanPxxxPower, 0, -1, -1, "POWER" }, // 0 + { EKeyPxxxBrowser, EScanPxxxBrowser, 0, -1, -1, "BROWSER" }, + { EKeyPxxxCamera, EScanPxxxCamera, 0, -1, -1, "CAMERA" }, + { EKeyPxxxJogUp, EScanPxxxJogUp, 2, -1, -1, "JOG@UP" }, + { EKeyPxxxJogDown, EScanPxxxJogDown, 2, -1, -1, "JOG@DOWN" }, + { EKeyPxxxJogLeft, EScanPxxxJogLeft, 0, -1, -1, "JOG@LEFT" }, // 5 + { EKeyPxxxJogRight, EScanPxxxJogRight, 0, -1, -1, "JOG@RIGHT" }, + { 0, EScanPxxxJogInward, 0, -1, -1, "JOG@INWARD" }, + { 0, EScanPxxxFcOk, 0, -1, -1, "FC@OK" }, + { 0, EScanPxxxFcBack, 0, -1, -1, "FC@BACK" }, + { 0, EScanPxxxFcC, 0, -1, -1, "FC@C" }, // 10 + { 0, EScanPxxxFcMenu, 0, -1, -1, "FC@MENU" }, + { 0, EScanPxxxFc0, 0, -1, -1, "FC@0" }, + { 0, EScanPxxxFc1, 0, -1, -1, "FC@1" }, + { 0, EScanPxxxFc2, 0, -1, -1, "FC@2" }, + { 0, EScanPxxxFc3, 0, -1, -1, "FC@3" }, + { 0, EScanPxxxFc4, 0, -1, -1, "FC@4" }, + { 0, EScanPxxxFc5, 0, -1, -1, "FC@5" }, + { 0, EScanPxxxFc6, 0, -1, -1, "FC@6" }, + { 0, EScanPxxxFc7, 0, -1, -1, "FC@7" }, + { 0, EScanPxxxFc8, 0, -1, -1, "FC@8" }, + { 0, EScanPxxxFc9, 0, -1, -1, "FC@9" }, + { 0, EScanPxxxFcHash, 0, -1, -1, "FC@HASH" }, + { 0, EScanPxxxFcAsterisk,0, -1, -1, "FC@AST" }, + { 0, 0, 0, 0, 0, 0 } +}; + +// Motorola A92x & A1000 support +TPicoKeyConfigEntry keyConfigMotA[] = { + { EKeyMotAUp, EScanMotAUp, 0, -1, -1, "UP" }, // 0 + { EKeyMotADown, EScanMotADown, 0, -1, -1, "DOWN" }, + { EKeyMotALeft, EScanMotALeft, 0, -1, -1, "LEFT" }, + { EKeyMotARight, EScanMotARight, 0, -1, -1, "RIGHT" }, + { EKeyMotASelect, EScanMotASelect, 0, -1, -1, "SELECT" }, + { EKeyMotAButton1, EScanMotAButton1, 0, -1, -1, "BUTTON1" }, // 5 + { EKeyMotAButton2, EScanMotAButton2, 0, -1, -1, "BUTTON2" }, + { EKeyMotAHome, EScanMotAHome, 0, -1, -1, "HOME" }, + { EKeyMotAShortcut, EScanMotAShortcut, 0, -1, -1, "SHORTCUT" }, + { EKeyMotAVoice, EScanMotAVoice, 0, -1, -1, "VOICE" }, + { EKeyMotACamera, EScanMotACamera, 0, -1, -1, "CAMERA" }, // 10 + { EKeyMotAVolUp, EScanMotAVolUp, 0, -1, -1, "VOL@UP" }, + { EKeyMotAVolDn, EScanMotAVolDn, 0, -1, -1, "VOL@DOWN" }, + { EKeyMotASend, EScanMotASend, 0, -1, -1, "SEND" }, + { EKeyMotAEnd, EScanMotAEnd, 0, -1, -1, "END" }, + { 0, EScanMotAExtra, 0, -1, -1, "EXTRA" }, + { 0, EScanMotAEsc, 0, -1, -1, "ESC" }, + { 0, EScanMotAStart, 0, -1, -1, "START" }, + { 0, EScanMotASelect2, 0, -1, -1, "SELECT" }, + { 0, 0, 0, 0, 0, 0 } +}; + + +// list of areas +TPicoAreaConfigEntry areaConfig[] = { + { TRect( 0, 0, 0, 0) }, + // small corner bottons + { TRect( 0, 0, 15, 15) }, + { TRect(192, 0, 207, 15) }, + { TRect( 0, 304, 15, 319) }, + { TRect(192, 304, 207, 319) }, + // normal buttons + { TRect( 0, 0, 68, 63) }, + { TRect( 69, 0, 138, 63) }, + { TRect(139, 0, 207, 63) }, + { TRect( 0, 64, 68, 127) }, + { TRect( 69, 64, 138, 127) }, + { TRect(139, 64, 207, 127) }, + { TRect( 0, 128, 68, 191) }, + { TRect( 69, 128, 138, 191) }, + { TRect(139, 128, 207, 191) }, + { TRect( 0, 192, 68, 255) }, + { TRect( 69, 192, 138, 255) }, + { TRect(139, 192, 207, 255) }, + { TRect( 0, 256, 68, 319) }, + { TRect( 69, 256, 138, 319) }, + { TRect(139, 256, 207, 319) }, + { TRect( 0, 0, 0, 0) } +}; + +// PicoPad[] format: SACB RLDU +const char *actionNames[] = { + "UP", "DOWN", "LEFT", "RIGHT", "B", "C", "A", "START", + 0, 0, 0, 0, 0, 0, 0, 0, // Z, Y, X, MODE (enabled only when needed), ?, ?, ?, ? + 0, 0, 0, 0, 0, 0, "NEXT@SAVE@SLOT", "PREV@SAVE@SLOT", // ?, ?, ?, ?, mot_vol_up, mot_vol_down, next_slot, prev_slot + 0, 0, "PAUSE@EMU", "SAVE@STATE", "LOAD@STATE", "FRAMESKIP@8", "AUTO@FRAMESKIP", "DONE" // ?, switch_renderer +}; + + +// globals are allowed, so why not to (ab)use them? +TInt machineUid = 0; +int gamestate = PGS_Paused, gamestate_prev = PGS_Paused; +TPicoConfig currentConfig; +TPicoKeyConfigEntry *keyConfig = 0; // currently used keys +static char noticeMsg[64]; // notice msg to draw +static timeval noticeMsgTime = { 0, 0 }; // when started showing +static RLibrary gameAudioLib; // audio object library +static _gameAudioNew gameAudioNew; // audio object maker +static IGameAudio *gameAudio = 0; // the audio object itself +static TProcessId launcherProcessId; +static int reset_timing, state_slot = 0; +extern const char *RomFileName; +extern int pico_was_reset; +#ifdef TEST_FRAMEBUFF +static TUint8 *iFrameBuffer = 0; +#endif + +// some forward declarations +static void MainInit(); +static void MainExit(); +static void CheckForLauncher(); +static void DumpMemInfo(); + +// just for a nicer grouping of WS related stuff +class CGameWindow +{ +public: + static void ConstructResourcesL(); + static void FreeResources(); + static void DoKeys(timeval &time); + static void DoKeysConfig(TUint &which); + static void RunEvents(TUint32 which); + static void SendClientWsEvent(TInt type); + + static RWsSession iWsSession; + static RWindowGroup iWsWindowGroup; + static RWindow iWsWindow; + static CWsScreenDevice* iWsScreen; + static CWindowGc* iWindowGc; + static TRequestStatus iWsEventStatus; + static TThreadId iLauncherThreadId; + static RDirectScreenAccess* iDSA; + static TRequestStatus iDSAstatus; +}; + + +void SkipFrame(int do_sound) +{ + PicoSkipFrame=1; + PicoFrame(); + PicoSkipFrame=0; + + if(do_sound && PsndOut) { + PsndOut = gameAudio->NextFrameL(); + if(!PsndOut) { // sound output problems? + strcpy(noticeMsg, "SOUND@OUTPUT@ERROR;@SOUND@DISABLED"); + gettimeofday(¬iceMsgTime, 0); + } + } + +/* + int total=0; + + // V-Blanking period: + if (Pico.video.reg[1]&0x20) SekInterrupt(6); // Set IRQ + Pico.video.status|=0x88; // V-Int happened / go into vblank + total+=SekRun(18560); + + // Active Scan: + if (Pico.video.reg[1]&0x40) Pico.video.status&=~8; // Come out of vblank if display is enabled + SekInterrupt(0); // Clear IRQ + total+=SekRun(127969-total); +*/ +} + + +void TargetEpocGameL() +{ + char buff[24]; // fps count c string + struct timeval tval; // timing + int thissec = 0, frames_done = 0, frames_shown = 0; + int target_fps, target_frametime, too_fast, too_fast_time; + int i, underflow; + TRawEvent blevent; + + MainInit(); + buff[0] = 0; + + // just to keep the backlight on.. + blevent.Set(TRawEvent::EActive); + + // loop? + for(;;) { + if(gamestate == PGS_Running) { + // prepare window and stuff + CGameWindow::ConstructResourcesL(); + + // if the system has something to do, it should better do it now + User::After(50000); + //CPolledActiveScheduler::Instance()->Schedule(); + + // pal/ntsc might have changed, reset related stuff + if(Pico.m.pal) { + target_fps = 50; + if(!noticeMsgTime.tv_sec) strcpy(noticeMsg, "PAL@SYSTEM@/@50@FPS"); + } else { + target_fps = 60; + if(!noticeMsgTime.tv_sec) strcpy(noticeMsg, "NTSC@SYSTEM@/@60@FPS"); + } + target_frametime = 1000000/target_fps; + if(!noticeMsgTime.tv_sec && pico_was_reset) + gettimeofday(¬iceMsgTime, 0); + + pico_was_reset = too_fast = 0; + reset_timing = 1; + + while(gamestate == PGS_Running) { + gettimeofday(&tval, 0); + if(reset_timing) { + reset_timing = 0; + thissec = tval.tv_sec; + frames_done = tval.tv_usec/target_frametime; + } + + // show notice message? + char *notice = 0; + if(noticeMsgTime.tv_sec) { + if((tval.tv_sec*1000000+tval.tv_usec) - (noticeMsgTime.tv_sec*1000000+noticeMsgTime.tv_usec) > 2000000) // > 2.0 sec + noticeMsgTime.tv_sec = noticeMsgTime.tv_usec = 0; + else notice = noticeMsg; + } + + // second changed? + if(thissec != tval.tv_sec) { +#ifdef BENCHMARK + static int bench = 0, bench_fps = 0, bench_fps_s = 0, bfp = 0, bf[4]; + if(++bench == 10) { + bench = 0; + bench_fps_s = bench_fps; + bf[bfp++ & 3] = bench_fps; + bench_fps = 0; + } + bench_fps += frames_shown; + sprintf(buff, "%02i/%02i/%02i", frames_shown, bench_fps_s, (bf[0]+bf[1]+bf[2]+bf[3])>>2); +#else + if(currentConfig.iFlags & 2) + sprintf(buff, "%02i/%02i", frames_shown, frames_done); +#endif + thissec = tval.tv_sec; + if((thissec & 7) == 7) UserSvr::AddEvent(blevent); + // in is quite common for this implementation to leave 1 fame unfinished + // when second changes. This creates sound clicks, so it's probably better to + // skip that frame and render sound + if(PsndOut && frames_done < target_fps && frames_done > target_fps-5) { + SkipFrame(1); frames_done++; + } + // try to prevent sound buffer underflows by making sure we did _exactly_ + // target_fps sound updates and copying last samples over and over again + if(PsndOut && frames_done < target_fps) + for(; frames_done < target_fps; frames_done++) { + PsndOut = gameAudio->DupeFrameL(underflow); + if(!PsndOut) { // sound output problems? + strcpy(noticeMsg, "SOUND@OUTPUT@ERROR;@SOUND@DISABLED"); + gettimeofday(¬iceMsgTime, 0); + break; + } + if(underflow) break; + } + frames_done = frames_shown = 0; + } + + if(currentConfig.iFrameskip >= 0) { // frameskip enabled + for(i = 0; i < currentConfig.iFrameskip; i++) { + SkipFrame(frames_done < target_fps); frames_done++; + CGameWindow::DoKeys(tval); + } + } else if(tval.tv_usec > (frames_done+1)*target_frametime) { // auto frameskip + // no time left for this frame - skip + SkipFrame(1); frames_done++; + CGameWindow::DoKeys(tval); + too_fast = 0; + continue; + } else if(tval.tv_usec < (too_fast_time=frames_done*target_frametime)) { // we are too fast + if(++too_fast > 2) { User::After(too_fast_time-tval.tv_usec); too_fast = 0; }// sleep, but only if we are _really_ fast + } + + // draw + vidDrawFrame(notice, buff, frames_shown); + if(PsndOut && frames_done < target_fps) { + PsndOut = gameAudio->NextFrameL(); + if(!PsndOut) { // sound output problems? + strcpy(noticeMsg, "SOUND@OUTPUT@ERROR;@SOUND@DISABLED"); + gettimeofday(¬iceMsgTime, 0); + } + } + frames_done++; frames_shown++; + CGameWindow::DoKeys(tval); + } + + // save SRAM + if((currentConfig.iFlags & 1) && SRam.changed) { + saveLoadGame(0, 1); + SRam.changed = 0; + } + CGameWindow::SendClientWsEvent(EEventGamePaused); + CGameWindow::FreeResources(); + } else if(gamestate == PGS_Paused) { + for(i = 0; gamestate == PGS_Paused; i++) { + User::After(250000); + if(!(i & 0x7F)) CheckForLauncher(); // every 32 secs + } + } else if(gamestate == PGS_KeyConfig) { + // prepare window and stuff + CGameWindow::ConstructResourcesL(); + + TUint whichAction = 0; + while(gamestate == PGS_KeyConfig) { + vidKeyConfigFrame(whichAction, CGameWindow::iWsScreen->CurrentScreenMode()); + CGameWindow::DoKeysConfig(whichAction); + User::After(200000); + } + + CGameWindow::SendClientWsEvent(EEventKeyCfgDone); + CGameWindow::SendClientWsEvent(EEventGamePaused); + CGameWindow::FreeResources(); + } else if(gamestate == PGS_DebugHeap) { + #ifdef __DEBUG_PRINT + TInt cells = User::CountAllocCells(); + TInt mem; + User::AllocSize(mem); + DEBUGPRINT(_L("worker: cels=%d, size=%d KB"), cells, mem/1024); + gamestate = gamestate_prev; + #endif + } else if(gamestate == PGS_Quit) { + break; + } + } + + MainExit(); +} + + +// gameAudio default "maker", which simply leaves +IGameAudio *gameAudioNew_failer(TInt aRate, TBool aStereo, TInt aPcmFrames, TInt aBufferedFrames) +{ + User::Leave(1); + return 0; // shouldn't happen +} + + +// main initialization +static void MainInit() +{ + RProcess thisProcess, launcherProcess; + TInt err = KErrGeneral; + + DEBUGPRINT(_L("\r\n\r\nstarting..")); + + //CPolledActiveScheduler::NewL(); // create Polled AS for the sound engine + + // get launcher id + if(thisProcess.Owner(launcherProcess) == KErrNone) { + launcherProcessId = launcherProcess.Id(); + launcherProcess.Close(); // messing with launcherProcess too much strangely reboots my phone + } else { + DEBUGPRINT(_L("%i: couldn't find owner, terminating.."), thisProcess.Id()); + thisProcess.Terminate(1); + } + + // also get launcher thread id (for sending events, nasty way) + TFindThread findThread; + TFullName dummy1; + RThread tmpThread; + RProcess tmpProcess; + + while(findThread.Next(dummy1) == KErrNone) + { + tmpThread.Open(findThread); + tmpThread.Process(tmpProcess); + if(tmpProcess.Id() == launcherProcessId) { + CGameWindow::iLauncherThreadId = tmpThread.Id(); + break; + } + tmpThread.Close(); + tmpProcess.Close(); + } + + // start event listening thread, which waits for GUI commands + if(StartThread() < 0) { + // communication thread failed to start, we serve no purpose now, so suicide + DEBUGPRINT(_L("%i: StartThread() failed, terminating.."), thisProcess.Id()); + thisProcess.Terminate(1); + } + + HAL::Get(HALData::EMachineUid, machineUid); // find out the machine UID + + // get current dir + TFileName pfName = thisProcess.FileName(); + TParse parse; + parse.Set(pfName, 0, 0); + TPtrC currDir = parse.DriveAndPath(); + DEBUGPRINT(_L("current dir: %S"), &currDir); + + static TPtrC audio_dlls[] = { _L("audio_motorola.dll"), _L("audio_mediaserver.dll") }; + + // find our audio object maker + for(TInt i=0; i < 2; i++) { + DEBUGPRINT(_L("trying audio DLL: %S"), &audio_dlls[i]); + err = gameAudioLib.Load(audio_dlls[i], currDir); + if(err == KErrNone) { // great, we loaded a dll! + gameAudioNew = (_gameAudioNew) gameAudioLib.Lookup(1); + if(!gameAudioNew) { + gameAudioLib.Close(); + err = KErrGeneral; + DEBUGPRINT(_L(" loaded, but Lookup(1) failed.")); + } else + break; // done + } else + DEBUGPRINT(_L(" load failed! (%i)"), err);; + } + + if(err != KErrNone) + gameAudioNew = gameAudioNew_failer; + else DEBUGPRINT(_L(" audio dll loaded!"));; + + DumpMemInfo(); + + // try to start pico + DEBUGPRINT(_L("PicoInit();")); + PicoInit(); + +#ifdef TEST_FRAMEBUFF + iFrameBuffer = (TUint8 *) malloc(208*320*4); +#endif +} + + +// does not return +static void MainExit() +{ + RProcess thisProcess; + + DEBUGPRINT(_L("%i: cleaning up.."), thisProcess.Id()); + + // save SRAM + if((currentConfig.iFlags & 1) && SRam.changed) { + saveLoadGame(0, 1); + SRam.changed = 0; + } + + PicoExit(); + + if(gameAudio) delete gameAudio; + + if(gameAudioLib.Handle()) gameAudioLib.Close(); + + // Polled AS + //delete CPolledActiveScheduler::Instance(); + + DEBUGPRINT(_L("%i: terminating.."), thisProcess.Id()); + thisProcess.Terminate(0); +} + + +static void CheckForLauncher() +{ + RProcess launcherProcess; + + // check for launcher, we are useless without it + if(launcherProcess.Open(launcherProcessId) != KErrNone || launcherProcess.ExitCategory().Length() != 0) { + #ifdef __DEBUG_PRINT + RProcess thisProcess; + DEBUGPRINT(_L("%i: launcher process is gone, terminating.."), thisProcess.Id()); + if(launcherProcess.Handle()) { + TExitCategoryName ecn = launcherProcess.ExitCategory(); + DEBUGPRINT(_L("%i: launcher exit category: %S"), thisProcess.Id(), &ecn); + launcherProcess.Close(); + } + #endif + MainExit(); + } + launcherProcess.Close(); +} + + +void DumpMemInfo() +{ + TInt ramSize, ramSizeFree, romSize; + + HAL::Get(HALData::EMemoryRAM, ramSize); + HAL::Get(HALData::EMemoryRAMFree, ramSizeFree); + HAL::Get(HALData::EMemoryROM, romSize); + + DEBUGPRINT(_L("ram=%dKB, ram_free=%dKB, rom=%dKB"), ramSize/1024, ramSizeFree/1024, romSize/1024); +} + + + +TInt E32Main() +{ + // first thing's first + RThread().SetExceptionHandler(&ExceptionHandler, -1); + + //TInt pc, sp; + //asm volatile ("str pc, %0" : "=m" (pc) ); + //asm volatile ("str sp, %0" : "=m" (sp) ); + //RDebug::Print(_L("executing @ 0x%08x, sp=0x%08x"), pc, sp); + +/* + RDebug::Print(_L("Base Bottom Top Size RW Name")); + TBuf<4> l_r(_L("R")), l_w(_L("W")), l_d(_L("-")); + RChunk chunk; + TFullName chunkname; + TFindChunk findChunk(_L("*")); + while( findChunk.Next(chunkname) != KErrNotFound ) { + chunk.Open(findChunk); + RDebug::Print(_L("%08x %08x %08x %08x %S%S %S"), chunk.Base(), chunk.Base()+chunk.Bottom(), chunk.Base()+chunk.Top(), chunk.Size(), chunk.IsReadable() ? &l_r : &l_d, chunk.IsWritable() ? &l_w : &l_d, &chunkname); + chunk.Close(); + } +*/ + + CTrapCleanup* cleanup=CTrapCleanup::New(); + + TRAPD(error, TargetEpocGameL()); + + __ASSERT_ALWAYS(!error, User::Panic(_L("Picosmall"), error)); + delete cleanup; + + return 0; +} + + +void CGameWindow::ConstructResourcesL() +{ + + // connect to window server + // tried to create it globally and not re-connect everytime, + // but my window started to lose focus strangely + User::LeaveIfError(iWsSession.Connect()); + + // * Tell the Window Server not to mess about with our process priority + // * Also, because of the way legacy games are written, they never sleep + // * and thus never voluntarily yield the CPU. We set our process priority + // * to EPriorityForeground and hope that a Telephony application on + // * this device runs at EPriorityForeground as well. If not, tough! ;-) + + CGameWindow::iWsSession.ComputeMode(RWsSession::EPriorityControlDisabled); + RProcess me; + me.SetPriority(EPriorityForeground); + + iWsScreen=new(ELeave) CWsScreenDevice(iWsSession); + User::LeaveIfError(iWsScreen->Construct()); +// User::LeaveIfError(iWsScreen->CreateContext(iWindowGc)); + + iWsWindowGroup=RWindowGroup(iWsSession); + User::LeaveIfError(iWsWindowGroup.Construct((TUint32)&iWsWindowGroup)); + //iWsWindowGroup.SetOrdinalPosition(0); + //iWsWindowGroup.SetName(KServerWGName); + iWsWindowGroup.EnableScreenChangeEvents(); // flip events (EEventScreenDeviceChanged) + iWsWindowGroup.EnableFocusChangeEvents(); // EEventFocusGroupChanged + iWsWindowGroup.SetOrdinalPosition(0, 1); // TInt aPos, TInt aOrdinalPriority + + iWsWindow=RWindow(iWsSession); + User::LeaveIfError(iWsWindow.Construct(iWsWindowGroup, (TUint32)&iWsWindow)); + iWsWindow.SetSize(iWsScreen->SizeInPixels()); + iWsWindow.PointerFilter(EPointerFilterDrag, 0); + iWsWindow.SetPointerGrab(ETrue); + iWsWindow.SetVisible(ETrue); + iWsWindow.Activate(); + + // request access through RDirectScreenAccess api, but don't care about the result + RRegion *dsa_region = 0; + iDSA = new(ELeave) RDirectScreenAccess(iWsSession); + if(iDSA->Construct() == KErrNone) + iDSA->Request(dsa_region, iDSAstatus, iWsWindow); + DEBUGPRINT(_L("DSA: %i"), dsa_region ? dsa_region->Count() : -1); + + // now get the screenbuffer + TScreenInfoV01 screenInfo; + TPckg sI(screenInfo); + UserSvr::ScreenInfo(sI); + + if(!screenInfo.iScreenAddressValid) + User::Leave(KErrNotSupported); + +#ifndef TEST_FRAMEBUFF + TUint8 *iFrameBuffer = (TUint8*) screenInfo.iScreenAddress; +#endif + TInt p800 = 0; + + switch(machineUid) + { + case 0x101f6b26: // A9xx & A10xx + case 0x101f6b27: // Chinese A10xx + case 0x101fd279: // P3x + iFrameBuffer += 32; + keyConfig = keyConfigMotA; + break; + case 0x101f408b: // P800 + p800 = 1; + //case 0x101fb2ae: // P900 + //case 0x10200ac6: // P910 + default: + keyConfig = keyConfigPXXX; + break; + } + DEBUGPRINT(_L("framebuffer=0x%08x (%dx%d)"), iFrameBuffer, + screenInfo.iScreenSize.iWidth, screenInfo.iScreenSize.iHeight); + + // vidInit + User::LeaveIfError(vidInit(iWsScreen->DisplayMode(), iFrameBuffer, p800)); + + // register for keyevents + for(TPicoKeyConfigEntry *e = keyConfig; e->name; e++) { + // release all keys + e->flags &= ~1; + if(e->flags & 0x80) { + // key disabled + e->handle1 = e->handle2 = -1; + continue; + } + e->handle1 = iWsWindowGroup.CaptureKeyUpAndDowns(e->scanCode, 0, 0, 2); + // although we only use UpAndDown events, register simple events too, + // just to prevent fireing their default actions. + if(e->keyCode) e->handle2 = iWsWindowGroup.CaptureKey(e->keyCode, 0, 0, 2); // priority of 1 is not enough on my phone + } + + // try to start the audio engine + static int PsndRate_old = 0, PicoOpt_old = 0, pal_old = 0; + + if(gamestate == PGS_Running && (currentConfig.iFlags & 4)) { + TInt err = 0; + if(PsndRate != PsndRate_old || (PicoOpt&11) != (PicoOpt_old&11) || Pico.m.pal != pal_old) { + // if rate changed, reset all enabled chips, else reset only those chips, which were recently enabled + //sound_reset(PsndRate != PsndRate_old ? PicoOpt : (PicoOpt&(PicoOpt^PicoOpt_old))); + sound_rerate(); + } + if(!gameAudio || PsndRate != PsndRate_old || ((PicoOpt&8) ^ (PicoOpt_old&8)) || Pico.m.pal != pal_old) { // rate or stereo or pal/ntsc changed + if(gameAudio) delete gameAudio; gameAudio = 0; + DEBUGPRINT(_L("starting audio: %i len: %i stereo: %i, pal: %i"), PsndRate, PsndLen, PicoOpt&8, Pico.m.pal); + TRAP(err, gameAudio = gameAudioNew(PsndRate, (PicoOpt&8) ? 1 : 0, PsndLen, Pico.m.pal ? 10 : 12)); + } + if( gameAudio) + TRAP(err, PsndOut = gameAudio->ResumeL()); + if(err) { + if(gameAudio) delete gameAudio; + gameAudio = 0; + PsndOut = 0; + strcpy(noticeMsg, "SOUND@STARTUP@FAILED"); + gettimeofday(¬iceMsgTime, 0); + } + PsndRate_old = PsndRate; + PicoOpt_old = PicoOpt; + pal_old = Pico.m.pal; + } else { + if(gameAudio) delete gameAudio; + gameAudio = 0; + PsndOut = 0; + } + + // start key WS event polling + iWsSession.EventReady(&iWsEventStatus); + DEBUGPRINT(_L("CGameWindow::ConstructResourcesL() finished.")); +} + + +void CGameWindow::FreeResources() +{ + if(gameAudio) gameAudio->Pause(); + + // free RDirectScreenAccess stuff + iDSA->Cancel(); + iDSA->Close(); + delete iDSA; + iDSA = NULL; + + iWsSession.EventReadyCancel(); + + for(TPicoKeyConfigEntry *e = keyConfig; e->name; e++) { + if(e->handle2 >= 0) iWsWindowGroup.CancelCaptureKey(e->handle2); + if(e->handle1 >= 0) iWsWindowGroup.CancelCaptureKeyUpAndDowns(e->handle1); + } + + if(iWsWindow.WsHandle()) + iWsWindow.Close(); + + if(iWsWindowGroup.WsHandle()) + iWsWindowGroup.Close(); + + // these must be deleted before calling iWsSession.Close() +// delete iWindowGc; +// iWindowGc = NULL; + + delete iWsScreen; + iWsScreen = NULL; + + // emu might change renderer by itself, so we may need to sync config + if(PicoOpt != currentConfig.iPicoOpt) { + currentConfig.iFlags |= 0x80; + CGameWindow::SendClientWsEvent(EEventKeyCfgDone); + } + + if(iWsSession.WsHandle()) + iWsSession.Close(); + + vidFree(); + +#ifdef TEST_FRAMEBUFF + FILE *tmp = fopen("d:\\temp\\screen.raw", "wb"); + fwrite(iFrameBuffer, 1, 208*320*4, tmp); + fclose(tmp); +#endif +} + + +void CGameWindow::DoKeys(timeval &time) +{ + TWsEvent iWsEvent; + TInt iWsEventType; + unsigned long allActions = 0; + static unsigned long areaActions = 0, forceUpdate = 0; + int i, nEvents; + + // detect if user is holding power button + static timeval powerPushed = { 0, 0 }; + if(powerPushed.tv_sec) { + if((time.tv_sec*1000000+time.tv_usec) - (powerPushed.tv_sec*1000000+powerPushed.tv_usec) > 1000000) { // > 1 sec + gamestate = PGS_Paused; + powerPushed.tv_sec = powerPushed.tv_usec = 0; + } + } + + for(nEvents = 0; iWsEventStatus != KRequestPending; nEvents++) + { + iWsSession.GetEvent(iWsEvent); + iWsEventType = iWsEvent.Type(); + + // pointer events? + if(iWsEventType == EEventPointer) { + if(iWsEvent.Pointer()->iType == TPointerEvent::EButton1Up) { + areaActions = 0; // remove all directionals + } else { // if(iWsEvent.Pointer()->iType == TPointerEvent::EButton1Down) { + TPoint p = iWsEvent.Pointer()->iPosition; + const TPicoAreaConfigEntry *e = areaConfig + 1; + for(i = 0; !e->rect.IsEmpty(); e++, i++) + if(e->rect.Contains(p)) { + areaActions = currentConfig.iAreaBinds[i]; + break; + } + } + } + else if(iWsEventType == EEventKeyDown || iWsEventType == EEventKeyUp) { + TInt iScanCode = iWsEvent.Key()->iScanCode; + + for(TPicoKeyConfigEntry *e = keyConfig; e->name; e++) + if(iScanCode == e->scanCode) { + if(iWsEventType == EEventKeyDown) e->flags |= 1; + else if((e->flags & 2) == 0) e->flags &= ~1; + break; + } + + // power? + if(iScanCode == EScanPxxxPower || iScanCode == EScanMotAEnd) { + if(iWsEventType == EEventKeyDown) + powerPushed = time; + else powerPushed.tv_sec = powerPushed.tv_usec = 0; + } + } + else if(iWsEventType == EEventScreenDeviceChanged) { + // we have the priority, so the launcher will not be able to process this, but it has to + User::After(500000); + reset_timing = 1; + } + else if(iWsEventType == EEventFocusGroupChanged) { + TInt launcherGrpId = iWsSession.FindWindowGroupIdentifier(0, iLauncherThreadId); + TInt focusGrpId = iWsSession.GetFocusWindowGroup(); + DEBUGPRINT(_L("EEventFocusGroupChanged: %i, our: %i, launcher: %i"), + focusGrpId, iWsWindowGroup.Identifier(), launcherGrpId); + // if it is not us and not launcher that got focus, pause emu + if(focusGrpId != iWsWindowGroup.Identifier() && focusGrpId != launcherGrpId) + gamestate = PGS_Paused; + } + + iWsEventStatus = KRequestPending; + iWsSession.EventReady(&iWsEventStatus); + } + + if(nEvents || forceUpdate) { + allActions = areaActions; + forceUpdate = 0; + + // add all pushed button actions + i = 0; + for(TPicoKeyConfigEntry *e = keyConfig; e->name; e++, i++) { + if(e->flags & 1) allActions |= currentConfig.iKeyBinds[i]; + if((e->flags& 3) == 3) forceUpdate = 1; + if(e->flags & 2) e->flags &= ~1; + } + + PicoPad[0] = (unsigned short) allActions; + if(allActions & 0xFFFF0000) { + RunEvents(allActions >> 16); + areaActions = 0; + } + } +} + + +void CGameWindow::DoKeysConfig(TUint &which) +{ + TWsEvent iWsEvent; + int i; + + // to detect if user is holding power button + static int powerIters = 0; + + while(iWsEventStatus != KRequestPending) + { + TUint currentActCode = 1 << which; + + iWsSession.GetEvent(iWsEvent); + + // pointer events? + if(iWsEvent.Type() == EEventPointer) { + TPoint p = iWsEvent.Pointer()->iPosition; + TRect prev(190, 112, 208, 126); + TRect next(190, 194, 208, 208); + + if(iWsEvent.Pointer()->iType == TPointerEvent::EButton1Down) { + if(prev.Contains(p)) do { which = (which-1) & 0x1F; } while(!actionNames[which]); + else if(next.Contains(p)) do { which = (which+1) & 0x1F; } while(!actionNames[which]); + else if(which == 31) gamestate = PGS_Paused; // done + else { + const TPicoAreaConfigEntry *e = areaConfig + 1; + for(i = 0; e->rect != TRect(0,0,0,0); e++, i++) + if(e->rect.Contains(p)) { + currentConfig.iAreaBinds[i] ^= currentActCode; + break; + } + } + } + } + else if(iWsEvent.Type() == EEventKeyDown || iWsEvent.Type() == EEventKeyUp) + { + //if(iWsEvent.Type() == EEventKey) + // DEBUGPRINT(_L("iWsEvent.Key()->iCode=0x%08x"), iWsEvent.Key()->iCode); + + //if(iWsEvent.Type() == EEventKeyDown) + // DEBUGPRINT(_L("EEventKeyDown iScanCode=0x%08x"), iWsEvent.Key()->iScanCode); + + //if(iWsEvent.Type() == EEventKeyUp) + // DEBUGPRINT(_L("EEventKeyUp iScanCode=0x%08x"), iWsEvent.Key()->iScanCode); + + // key events? + if(iWsEvent.Type() == EEventKeyDown) { + if(iWsScreen->CurrentScreenMode() == 1 && iWsEvent.Key()->iScanCode == EScanPxxxJogUp) { + do { which = (which-1) & 0x1F; } while(!actionNames[which]); + } else if(iWsScreen->CurrentScreenMode() == 1 && iWsEvent.Key()->iScanCode == EScanPxxxJogDown) { + do { which = (which+1) & 0x1F; } while(!actionNames[which]); + } else if(which == 31) { + gamestate = PGS_Paused; + if(iWsScreen->CurrentScreenMode()) // flip closed + vidDrawFCconfigDone(); + } else { + i = 0; + for(TPicoKeyConfigEntry *e = keyConfig; e->name; e++, i++) + if(iWsEvent.Key()->iScanCode == e->scanCode) + if(!(e->flags&0x40)) currentConfig.iKeyBinds[i] ^= currentActCode; + } + } + + // power? + if(iWsEvent.Key()->iScanCode == EScanPxxxPower || iWsEvent.Key()->iScanCode == EScanMotAEnd) + { + if(iWsEvent.Type() == EEventKeyDown) powerIters = 1; + else if(iWsEvent.Type() == EEventKeyUp) powerIters = 0; + } + } + else if(iWsEvent.Type() == EEventScreenDeviceChanged) { + // trying to fix the P910 problem when something steals focus (and returns it after a while?) + User::After(300000); + } + else if(iWsEvent.Type() == EEventFocusGroupChanged) { + TInt launcherGrpId = iWsSession.FindWindowGroupIdentifier(0, iLauncherThreadId); + TInt focusGrpId = iWsSession.GetFocusWindowGroup(); + DEBUGPRINT(_L("EEventFocusGroupChanged: %i, our: %i, launcher: %i"), + focusGrpId, iWsWindowGroup.Identifier(), launcherGrpId); + // if it is not us and not launcher that got focus, exit config mode + if(focusGrpId != iWsWindowGroup.Identifier() && focusGrpId != launcherGrpId) { + // don't give up that easily. May be the focus will be given back. + for (int i = 0; i < 4; i++) { + User::After(200000); + focusGrpId = iWsSession.GetFocusWindowGroup(); + if(focusGrpId == iWsWindowGroup.Identifier() || focusGrpId == launcherGrpId) break; + } + if(focusGrpId != iWsWindowGroup.Identifier() && focusGrpId != launcherGrpId) + // we probably should give up now + gamestate = PGS_Paused; + } + } + + iWsEventStatus = KRequestPending; + iWsSession.EventReady(&iWsEventStatus); + } + + if(powerIters) { // iterations when power was down + powerIters++; + if(powerIters > 5) { + gamestate = PGS_Paused; + powerIters = 0; + } + } +} + + +void CGameWindow::RunEvents(TUint32 which) +{ + if(which & 0x4000) currentConfig.iFrameskip = -1; + if(which & 0x2000) currentConfig.iFrameskip = 8; + if(which & 0x1800) { // save or load (but not both) + if(PsndOut) gameAudio->Pause(); // this may take a while, so we pause sound output + + vidDrawNotice((which & 0x1000) ? "LOADING@GAME" : "SAVING@GAME"); + saveLoadGame(which & 0x1000); + + if(PsndOut) PsndOut = gameAudio->ResumeL(); + reset_timing = 1; + } + if(which & 0x0400) gamestate = PGS_Paused; + if(which & 0x0200) { // switch renderer + if(currentConfig.iScreenMode == TPicoConfig::PMCenter && !noticeMsgTime.tv_sec && + (currentConfig.iScreenRotation == TPicoConfig::PRot90 || currentConfig.iScreenRotation == TPicoConfig::PRot270)) { + + PicoOpt^=0x10; + vidInit(iWsScreen->DisplayMode(), 0, 0, 1); + + strcpy(noticeMsg, (PicoOpt&0x10) ? "ALT@RENDERER" : "DEFAULT@RENDERER"); + gettimeofday(¬iceMsgTime, 0); + } + } + if(which & 0x00c0) { + if(which&0x0080) { + state_slot -= 1; + if(state_slot < 0) state_slot = 9; + } else { + state_slot += 1; + if(state_slot > 9) state_slot = 0; + } + sprintf(noticeMsg, "SAVE@SLOT@%i@SELECTED", state_slot); + gettimeofday(¬iceMsgTime, 0); + } + if(which & 0x0020) if(gameAudio) gameAudio->ChangeVolume(0); // for Motorolas (broken?) + if(which & 0x0010) if(gameAudio) gameAudio->ChangeVolume(1); +} + + +// send event to launcher windowgroup (WS session MUST be alive) +void CGameWindow::SendClientWsEvent(TInt type) +{ + if(!iWsSession.Handle()) { + DEBUGPRINT(_L("SendClientWsEvent(%i) called on dead iWsSession."), type); + return; + } + + TWsEvent event; + event.SetType(type); + event.SetTimeNow(); + + TInt launcherGrpId = iWsSession.FindWindowGroupIdentifier(0, iLauncherThreadId); + if(launcherGrpId != KErrNotFound) + iWsSession.SendEventToWindowGroup(launcherGrpId, event); + else DEBUGPRINT(_L("failed to send event %i to launcher."), event.Type()); +} + + +size_t gzRead2(void *p, size_t _size, size_t _n, void *file) +{ + return gzread(file, p, _n); +} + + +size_t gzWrite2(void *p, size_t _size, size_t _n, void *file) +{ + return gzwrite(file, p, _n); +} + + +// this function is shared between both threads +int saveLoadGame(int load, int sram) +{ + int res = 0; + + if(!RomFileName) return -1; + + // make save filename + char saveFname[KMaxFileName]; + strcpy(saveFname, RomFileName); + saveFname[KMaxFileName-8] = 0; + if(saveFname[strlen(saveFname)-4] == '.') saveFname[strlen(saveFname)-4] = 0; + if(sram) strcat(saveFname, ".srm"); + else { + if(state_slot > 0 && state_slot < 10) sprintf(saveFname, "%s.%i", saveFname, state_slot); + strcat(saveFname, ".mds"); + } + + DEBUGPRINT(_L("saveLoad (%i, %i): %S"), load, sram, DO_CONV(saveFname)); + + if(sram) { + FILE *sramFile; + int sram_size = SRam.end-SRam.start+1; + if(SRam.reg_back & 4) sram_size=0x2000; + if(!SRam.data) return 0; // SRam forcefully disabled for this game + if(load) { + sramFile = fopen(saveFname, "rb"); + if(!sramFile) return -1; + fread(SRam.data, 1, sram_size, sramFile); + fclose(sramFile); + } else { + // sram save needs some special processing + // see if we have anything to save + for(; sram_size > 0; sram_size--) + if(SRam.data[sram_size-1]) break; + + if(sram_size) { + sramFile = fopen(saveFname, "wb"); + res = fwrite(SRam.data, 1, sram_size, sramFile); + res = (res != sram_size) ? -1 : 0; + fclose((FILE *) sramFile); + } + } + return res; + } else { + void *PmovFile = NULL; + // try gzip first + if(currentConfig.iFlags & 0x80) { + strcat(saveFname, ".gz"); + if( (PmovFile = gzopen(saveFname, load ? "rb" : "wb")) ) { + areaRead = gzRead2; + areaWrite = gzWrite2; + if(!load) gzsetparams(PmovFile, 9, Z_DEFAULT_STRATEGY); + } else + saveFname[strlen(saveFname)-3] = 0; + } + if(!PmovFile) { // gzip failed or was disabled + if( (PmovFile = fopen(saveFname, load ? "rb" : "wb")) ) { + areaRead = fread; + areaWrite = fwrite; + } + } + if(PmovFile) { + PmovState(load ? 6 : 5, PmovFile); + strcpy(noticeMsg, load ? "GAME@LOADED" : "GAME@SAVED"); + if(areaRead == gzRead2) + gzclose(PmovFile); + else fclose ((FILE *) PmovFile); + PmovFile = 0; + } else { + strcpy(noticeMsg, load ? "LOAD@FAILED" : "SAVE@FAILED"); + res = -1; + } + + gettimeofday(¬iceMsgTime, 0); + return res; + } +} + +// static class members +RWsSession CGameWindow::iWsSession; +RWindowGroup CGameWindow::iWsWindowGroup; +RWindow CGameWindow::iWsWindow; +CWsScreenDevice* CGameWindow::iWsScreen = NULL; +CWindowGc* CGameWindow::iWindowGc = NULL; +TRequestStatus CGameWindow::iWsEventStatus = KRequestPending; +TThreadId CGameWindow::iLauncherThreadId = 0; +RDirectScreenAccess* CGameWindow::iDSA; +TRequestStatus CGameWindow::iDSAstatus = KRequestPending; diff --git a/platform/uiq2/port_config.h b/platform/uiq2/port_config.h new file mode 100644 index 00000000..e5ed140c --- /dev/null +++ b/platform/uiq2/port_config.h @@ -0,0 +1,23 @@ +// port specific settings + +#ifndef PORT_CONFIG_H +#define PORT_CONFIG_H + +#define CPU_CALL + +// draw2.c +#define START_ROW 1 // which row of tiles to start rendering at? +#define END_ROW 27 // ..end + +// pico.c +#define CAN_HANDLE_240_LINES 0 + +// common debug +#if defined(__DEBUG_PRINT) +void dprintf(char *format, ...); +#else +#define dprintf(x...) +#endif + + +#endif //PORT_CONFIG_H diff --git a/platform/uiq2/port_config.s b/platform/uiq2/port_config.s new file mode 100644 index 00000000..cb6592ae --- /dev/null +++ b/platform/uiq2/port_config.s @@ -0,0 +1,2 @@ +.equiv START_ROW, 1 +.equiv END_ROW, 27 diff --git a/platform/uiq2/qconn.cmd b/platform/uiq2/qconn.cmd new file mode 100644 index 00000000..96220c2b --- /dev/null +++ b/platform/uiq2/qconn.cmd @@ -0,0 +1 @@ +@..\..\..\qconsole-1.60\qtty-1.60\release\qtty --qc-addr P800 --qc-channel 5 --user qconsole --pass server \ No newline at end of file diff --git a/platform/uiq2/quploadpico.cmd b/platform/uiq2/quploadpico.cmd new file mode 100644 index 00000000..7ef2241d --- /dev/null +++ b/platform/uiq2/quploadpico.cmd @@ -0,0 +1 @@ +@..\..\..\qconsole-1.60\qtty-1.60\release\qtty --qc-addr P800 --qc-channel 5 --user qconsole --pass server --cmds "put d:\system\apps\picodriven\PICOSMALL.EXE PICOSMALL.EXE" exit diff --git a/platform/uiq2/quploadpicol.cmd b/platform/uiq2/quploadpicol.cmd new file mode 100644 index 00000000..1482b2f5 --- /dev/null +++ b/platform/uiq2/quploadpicol.cmd @@ -0,0 +1 @@ +@..\..\..\qconsole-1.60\qtty-1.60\release\qtty --qc-addr P800 --qc-channel 5 --user qconsole --pass server --cmds "put d:\system\apps\picodriven\PICODRIVEN.APP launcher\PICODRIVEN.APP" "put d:\system\apps\picodriven\PICODRIVEN.rsc launcher\PICODRIVEN.rsc" exit diff --git a/platform/uiq2/version.h b/platform/uiq2/version.h new file mode 100644 index 00000000..ab1bd1ee --- /dev/null +++ b/platform/uiq2/version.h @@ -0,0 +1,10 @@ +// version number + +#ifndef __VERSION_H +#define __VERSION_H + +#define KPicoMajorVersionNumber 0 +#define KPicoMinorVersionNumber 93 +#define KPicoBuildNumber 0 + +#endif /* __VERSION_H */ diff --git a/platform/uiq2/vid.cpp b/platform/uiq2/vid.cpp new file mode 100644 index 00000000..7b3b7aed --- /dev/null +++ b/platform/uiq2/vid.cpp @@ -0,0 +1,1017 @@ +// EmuScan routines for Pico, also simple text and shape drawing routines. + +// (c) Copyright 2006, notaz +// All Rights Reserved + +#include "vid.h" +#include "ClientServer.h" +#include "SimpleServer.h" +#include "pico\picoInt.h" +#include "blit.h" +#include "debug.h" + +// global stuff +extern TPicoConfig currentConfig; +extern TPicoKeyConfigEntry *keyConfig; +extern TPicoAreaConfigEntry areaConfig[]; +extern const char * actionNames[]; + +// main framebuffer +static void *screenbuff = 0; // pointer to real device video memory +//static +unsigned short *framebuff = 0; // temporary buffer in sega native BGR format +const int framebuffsize = (8+320)*(8+208+8)*2; // actual framebuffer size (in bytes+to support new rendering mode) +static int framebuff_offs = 0; // where to start copying (in pixels) +static int framebuff_len = 0; // how much of the framebuffer actually needs to be copied (in pixels) +static int fc_lines, fc_inc; // lines, inc for "0 fit2" mode + +// drawer function pointers +void (*drawTextFps)(const char *text) = 0; +void (*drawTextNotice)(const char *text) = 0; + +// blitter +void (*vidBlit)(int full) = 0; +void (*vidBlitKeyCfg)(int full) = 0; + +// stuff for rendermode2 +static unsigned short cram_high[0x40]; +static unsigned short dt_dmask=0x0333; +unsigned short color_redM2 = 0x022F; + +// colors +const unsigned short color_red = 0x022F; +const unsigned short color_red_dim = 0x0004; +const unsigned short color_green = 0x01F1; +const unsigned short color_blue = 0x0F11; +const unsigned short color_grey = 0x0222; + +// other +int txtheight_fit = 138; + +// bitmasks +static const unsigned long mask_numbers[] = { + 0x12244800, // 47 2F / + 0x69999600, // 48 30 0 + 0x26222200, // 49 31 1 + 0x69168F00, // 50 32 2 + 0x69219600, // 51 33 3 + 0x266AF200, // 52 34 4 + 0xF8E11E00, // 53 35 5 + 0x68E99600, // 54 36 6 + 0x71222200, // 55 37 7 + 0x69699600, // 56 38 8 + 0x69719600, // 57 39 9 + 0x04004000, // 58 3A : + 0x04004400, // 59 3B ; + 0x01242100, // 60 3C < + 0x00707000, // 61 3D = + 0x04212400, // 62 3E > + 0x69240400, // 63 3F ? + 0x00000000, // 64 40 @ [used instead of space for now] + 0x22579900, // 65 41 A + 0xE9E99E00, // 66 42 B + 0x69889600, // 67 43 C + 0xE9999E00, // 68 44 D + 0xF8E88F00, // 69 45 E + 0xF8E88800, // 70 46 F + 0x698B9700, // 71 47 G + 0x99F99900, // 72 48 H + 0x44444400, // 73 49 I + 0x11119600, // 74 4A J + 0x9ACCA900, // 75 4B K + 0x88888F00, // 76 4C L + 0x9F999900, // 77 4D M + 0x9DDBB900, // 78 4E N + 0x69999600, // 79 4F O + 0xE99E8800, // 80 50 P + 0x6999A500, // 81 51 Q + 0xE99E9900, // 82 52 R + 0x69429600, // 83 53 S + 0x72222200, // 84 54 T + 0x99999600, // 85 55 U + 0x55552200, // 86 56 V + 0x9999F900, // 87 57 W + 0x55225500, // 88 58 X + 0x55222200, // 89 59 Y + 0xF1248F00, // 90 5A Z +}; + + +//////////////////////////////// +// Cram functions + +inline int EmuCramNull(int cram) +{ + User::Panic(_L("Cram called!!"), 0); + return cram; +} + + +//////////////////////////////// +// PicoScan functions in "center" mode + +int EmuScanCenter0(unsigned int num, unsigned short *sdata) +{ + //unsigned short *vidmem=framebuff; + + //unsigned short *sp, *sto; + //sp=sdata+56; sto=sdata+264; vidmem += num*208; + + //do { *vidmem++ = *sp++; } while(sp < sto); + memcpy(framebuff + num*208, sdata+56, 208*2); // memcpy gives ~1 fps (~2 with optimized memcpy) + + return 0; +} + + +int EmuScanCenter90(unsigned int num, unsigned short *sdata) +{ + // ignore top and bottom lines + if(num < 8) return 7-num; // skip first 8 lines + if(num > 215) return 223+8-num; // this should not happen, just in case + + num -= 8; + if(!num) { + if(Pico.video.reg[12]&1) { // copy less in 32-col mode + framebuff_offs= 0; + framebuff_len = 208*320; + } else { + framebuff_offs= 208*32; + framebuff_len = 208*256; + } + } + + unsigned short *vidmem=framebuff; + vidmem += 207-num; // adjust x + + // do less copy in 32-column mode + unsigned short *sp, *sto; + int pixels; + if(!(Pico.video.reg[12]&1)) + { sp=sdata+32; sto=sdata+288; pixels = 288; vidmem += 32*208; } + else { sp=sdata; sto=sdata+320; pixels = 320; } + + do { *vidmem = *sp++; vidmem+=208; } while(sp < sto); + + if(num == 207) return 16; // skip bottom of this frame and top of next + + return 0; +} + + +int EmuScanCenter180(unsigned int num, unsigned short *sdata) +{ + unsigned short *vidmem=framebuff; + + unsigned short *sp, *sto; + sp=sdata+56; sto=sdata+264; vidmem += (224-num)*208; + + do { *(--vidmem) = *sp++; } while(sp < sto); // reversed + + return 0; +} + + +int EmuScanCenter270(unsigned int num, unsigned short *sdata) +{ + // ignore top and bottom lines + if(num < 8) return 7-num; // skip first 8 lines + if(num > 215) return 223-num+8; + + num -= 8; + if(num > 207) return 0; + if(!num) { + if(Pico.video.reg[12]&1) { + framebuff_offs= 0; + framebuff_len = 208*320; + } else { + framebuff_offs= 208*32; + framebuff_len = 208*256; + } + } + + unsigned short *vidmem=framebuff+320*208; + vidmem -= 208-num; // adjust x + + // do less copy in 32-column mode + unsigned short *sp, *sto; + if(!(Pico.video.reg[12]&1)) + { sp=sdata+32; sto=sdata+288; vidmem -= 32*208; } + else { sp=sdata; sto=sdata+320; } + + do { *vidmem = *sp++; vidmem-=208; } while(sp < sto); + + if(num == 207) return 16; // skip bottom of this frame and top of next + + return 0; +} + + + +//////////////////////////////// +// PicoScan functions in "fit" mode + +static int EmuScanFit0(unsigned int num, unsigned short *sdata) +{ + // 0.65, 145 lines in normal mode; 0.8125, 182 lines in 32-column mode + + // draw this line? (ARM4s don't support division, so do some tricks here) + static int u = 0, num2 = 0; + if(!num) { + u = num2 = 0; + if(currentConfig.iScreenMode == TPicoConfig::PMFit) { + if(Pico.video.reg[12]&1) { // 32 col mode? This can change on any frame + fc_inc = 6500; + txtheight_fit = 138; + framebuff_len = 208*145; + memset(framebuff+208*145, 0, 208*37*2); + } else { + fc_inc = 8125; + txtheight_fit = 175; + framebuff_len = 208*182; + } + } + } + u += fc_inc; + if(u < 10000) return 0; + u -= 10000; + + unsigned short *vidmem=framebuff; + + int slen; + unsigned short *sp; + if(!(Pico.video.reg[12]&1)) + { sp=sdata+32; slen=256; } + else { sp=sdata; slen=320; } + + vidmem += num2*208; +/* + int i=0; + while(sp < sto) { + i += inc; + if(i >= 10000) { + *vidmem++ = *sp; + i -= 10000; + } + sp++; + } +*/ + PicuShrink(vidmem, 208, sp, slen); + + num2++; + + // calculate how many lines pico engine should skip, + // making sure this func will be called on scanline 0 + int skip = 0; + while(u+fc_inc < 10000 && num+skip != 223) { u+=fc_inc; skip++; } + + return skip; +} + +int EmuScanFit90(unsigned int num, unsigned short *sdata) +{ + // 0.9285 + + // draw this line? + static int u = 0, num2 = 0; + if(!num) { + u = num2 = 0; + if(Pico.video.reg[12]&1) { + framebuff_offs= 0; + framebuff_len = 208*320; + } else { + framebuff_offs= 208*32; + framebuff_len = 208*256; + } + } + u += 9285; + if(u < 10000) return 0; + u -= 10000; + + unsigned short *vidmem=framebuff; + vidmem += 207-num2; // adjust x + + // do less copy in 32-column mode + unsigned short *sp, *sto; + if(!(Pico.video.reg[12]&1)) + { sp=sdata+32; sto=sdata+288; vidmem += 32*208; } + else { sp=sdata; sto=sdata+320; } + + do { *vidmem = *sp++; vidmem+=208; } while(sp < sto); + + num2++; + + // skip next line? + if(u+9285 < 10000 && num != 223) { u+=9285; return 1; } + + return 0; +} + +int EmuScanFit180(unsigned int num, unsigned short *sdata) +{ + // 0.65, 145 lines in normal mode; 0.8125, 182 lines in 32-column mode + + // draw this line? (ARM4s don't support division) + static int u = 0, num2 = 0; + if(!num) { + u = num2 = 0; + if(currentConfig.iScreenMode == TPicoConfig::PMFit) { + if(Pico.video.reg[12]&1) { // 32 col mode? This can change on any frame + fc_lines = 145; + fc_inc = 6500; + txtheight_fit = 138; + framebuff_len = 208*145; + memset(framebuff+208*145, 0, 208*37*2); + } else { + fc_lines = 182; + fc_inc = 8125; + txtheight_fit = 175; + framebuff_len = 208*182; + } + } + } + u += fc_inc; + if(u < 10000) return 0; + u -= 10000; + + unsigned short *vidmem=framebuff; + + int slen; + unsigned short *sp; + if(!(Pico.video.reg[12]&1)) + { sp=sdata+32; slen=256; } + else { sp=sdata; slen=320; } + + vidmem += (fc_lines-num2)*208; + + PicuShrinkReverse(vidmem, 208, sp, slen); + + num2++; + + // skip some lines? + int skip = 0; + while(u+fc_inc < 10000 && num+skip != 223) { u+=fc_inc; skip++; } + + return skip; +} + +int EmuScanFit270(unsigned int num, unsigned short *sdata) +{ + // 0.9285 + + // draw this line? + static int u = 0, num2 = 0; + if(!num) { + u = num2 = 0; + if(Pico.video.reg[12]&1) { + framebuff_offs= 0; + framebuff_len = 208*320; + } else { + framebuff_offs= 208*32; + framebuff_len = 208*256; + } + } + u += 9285; + if(u < 10000) return 0; + u -= 10000; + + unsigned short *vidmem=framebuff+320*208; + vidmem -= 208-num2; // adjust x + + // do less copy in 32-column mode + unsigned short *sp, *sto; + if(!(Pico.video.reg[12]&1)) + { sp=sdata+32; sto=sdata+288; vidmem -= 32*208; } + else { sp=sdata; sto=sdata+320; } + + do { *vidmem = *sp++; vidmem-=208; } while(sp < sto); + + num2++; + + // skip next line? + if(u+9285 < 10000 && num != 223) { u+=9285; return 1; } + + return 0; +} + + +//////////////////////////////// +// text drawers +// warning: text must be at least 1px away from screen borders + +void drawTextM2(int x, int y, const char *text, long color) +{ + unsigned short *vidmem=framebuff; + int charmask, i, cx = x, cy; + unsigned short *l, *le; + + // darken the background (left border) + for(l=vidmem+(cx-1)+(y-1)*328, le=vidmem+(cx-1)+(y+7)*328; l < le; l+=328) + *l = (*l >> 2) & dt_dmask; + + for(const char *p=text; *p; p++) { + cy = y; + charmask = *(mask_numbers + (*p - 0x2F)); + + for(l = vidmem+cx+(y-1)*328, le = vidmem+cx+(y+7)*328; l < le; l+=328-4) { + *l = (*l >> 2) & dt_dmask; l++; *l = (*l >> 2) & dt_dmask; l++; + *l = (*l >> 2) & dt_dmask; l++; *l = (*l >> 2) & dt_dmask; l++; + *l = (*l >> 2) & dt_dmask; + } + + for(i=0; i < 24; i++) { + // draw dot. Is this fast? + if(charmask&0x80000000) *( vidmem + (cx+(i&3)) + (cy+(i>>2))*328 ) = color; + charmask <<= 1; + } + cx += 5; + } +} + +void drawText0(int x, int y, const char *text, long color) +{ + unsigned short *vidmem=framebuff; + int charmask, i, cx = x, cy; + unsigned short *l, *le, dmask=0x0333; + + // darken the background (left border) + for(l=vidmem+(cx-1)+(y-1)*208, le=vidmem+(cx-1)+(y+7)*208; l < le; l+=208) + *l = (*l >> 2) & dmask; + + for(const char *p=text; *p; p++) { + cy = y; + charmask = *(mask_numbers + (*p - 0x2F)); + + for(l = vidmem+cx+(y-1)*208, le = vidmem+cx+(y+7)*208; l < le; l+=208-4) { + *l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++; + *l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++; + *l = (*l >> 2) & dmask; + } + + for(i=0; i < 24; i++) { + // draw dot. Is this fast? + if(charmask&0x80000000) *( vidmem + (cx+(i&3)) + (cy+(i>>2))*208 ) = color; + charmask <<= 1; + } + cx += 5; + } +} + +void drawText90(int x, int y, const char *text, long color) +{ + unsigned short *vidmem=framebuff; + unsigned short *l, *le, dmask=0x0333; + int charmask, i, cx, cy = y; + + for(l=vidmem+(x+1)+(cy-1)*208, le=vidmem+(x-7)+(cy-1)*208; l > le; l--) + *l = (*l >> 2) & dmask; + + for(const char *p=text; *p; p++) { + cx = x; + charmask = *(mask_numbers + (*p - 0x2F)); + + for(l = vidmem+(x+1)+(cy)*208, le = vidmem+(x+1)+(cy+5)*208; l < le; l+=208+7) { + *l = (*l >> 2) & dmask; l--; *l = (*l >> 2) & dmask; l--; + *l = (*l >> 2) & dmask; l--; *l = (*l >> 2) & dmask; l--; + *l = (*l >> 2) & dmask; l--; *l = (*l >> 2) & dmask; l--; + *l = (*l >> 2) & dmask; l--; *l = (*l >> 2) & dmask; + } + + for(i=0; i < 24; i++) { + if(charmask&0x80000000) *( vidmem + (cy+(i&3))*208 + (cx-(i>>2)) ) = color; + charmask <<= 1; + } + cy += 5; + } +} + +void drawText180(int x, int y, const char *text, long color) +{ + unsigned short *vidmem=framebuff; + int charmask, i, cx = x, cy; + unsigned short *l, *le, dmask=0x0333; + + for(l=vidmem+(cx+1)+(y+1)*208, le=vidmem+(cx+1)+(y-7)*208; l > le; l-=208) + *l = (*l >> 2) & dmask; + + for(const char *p=text; *p; p++) { + cy = y; + charmask = *(mask_numbers + (*p - 0x2F)); + + for(l = vidmem+cx+(y+1)*208, le = vidmem+cx+(y-8)*208; l > le; l-=208-4) { + *l = (*l >> 2) & dmask; l--; *l = (*l >> 2) & dmask; l--; + *l = (*l >> 2) & dmask; l--; *l = (*l >> 2) & dmask; l--; + *l = (*l >> 2) & dmask; + } + + for(i=0; i < 24; i++) { + if(charmask&0x80000000) *( vidmem + (cx-(i&3)) + (cy-(i>>2))*208 ) = color; + charmask <<= 1; + } + cx -= 5; + } +} + +void drawText270(int x, int y, const char *text, long color) +{ + unsigned short *vidmem=framebuff; + int charmask, i, cx, cy = y; + unsigned short *l, *le, dmask=0x0333; + + for(l=vidmem+(x-1)+(cy+1)*208, le=vidmem+(x+7)+(cy+1)*208; l < le; l++) + *l = (*l >> 2) & dmask; + + for(const char *p=text; *p; p++) { + cx = x; + charmask = *(mask_numbers + (*p - 0x2F)); + + for(l = vidmem+(x-1)+(cy)*208, le = vidmem+(x-1)+(cy-5)*208; l > le; l-=208+7) { + *l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++; + *l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++; + *l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++; + *l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; + } + + for(i=0; i < 24; i++) { + if(charmask&0x80000000) *( vidmem + (cy-(i&3))*208 + (cx+(i>>2)) ) = color; + charmask <<= 1; + } + cy -= 5; + } +} + +void drawTextFpsM2(const char *text) +{ + if(!text) return; + drawTextM2((Pico.video.reg[12]&1) ? 256 : 224, 200, text, color_redM2); +} + +void drawTextFps0(const char *text) +{ + if(!text) return; + drawText0(176, 216, text, color_red); +} + +void drawTextFpsFit0(const char *text) +{ + if(!text) return; + drawText0(176, txtheight_fit, text, color_red); +} + +void drawTextFps90(const char *text) +{ + if(!text) return; + drawText90(10, 256, text, color_red); +} + +void drawTextFps180(const char *text) +{ + if(!text) return; + drawText180(32, 8, text, color_red); +} + +void drawTextFps270(const char *text) +{ + if(!text) return; + drawText270(200, 64, text, color_red); +} + +void drawTextNoticeM2(const char *text) +{ + if(!text) return; + drawTextM2(20, 200, text, color_redM2); +} + +void drawTextNotice0(const char *text) +{ + if(!text) return; + drawText0(2, 216, text, color_red); +} + +void drawTextNoticeFit0(const char *text) +{ + if(!text) return; + drawText0(2, txtheight_fit, text, color_red); +} + +void drawTextNotice90(const char *text) +{ + if(!text) return; + drawText90(10, 34, text, color_red); +} + +void drawTextNotice180(const char *text) +{ + if(!text) return; + drawText180(206, 8, text, color_red); +} + +void drawTextNotice270(const char *text) +{ + if(!text) return; + drawText270(200, 286, text, color_red); +} + + +//////////////////////////////// +// misc drawers + +// draws rect with width - 1 and height - 1 +void drawRect(const TRect &rc, unsigned short color) +{ + if(rc.iTl.iX - rc.iBr.iX && rc.iTl.iY - rc.iBr.iY) { + int stepX = rc.iTl.iX < rc.iBr.iX ? 1 : -1; + int stepY = rc.iTl.iY < rc.iBr.iY ? 1 : -1; + + for(int x = rc.iTl.iX;; x += stepX) { + *(framebuff + rc.iTl.iY*208 + x) = *(framebuff + (rc.iBr.iY - stepY)*208 + x) = color; + if(x == rc.iBr.iX - stepX) break; + } + + for(int y = rc.iTl.iY;; y += stepY) { + *(framebuff + y*208 + rc.iTl.iX) = *(framebuff + y*208 + rc.iBr.iX - stepX) = color; + if(y == rc.iBr.iY - stepY) break; + } + } +} + +// draws fullsize filled rect +void drawRectFilled(const TRect rc, unsigned short color) +{ + if(rc.iTl.iX - rc.iBr.iX && rc.iTl.iY - rc.iBr.iY) { + int stepX = rc.iTl.iX < rc.iBr.iX ? 1 : -1; + int stepY = rc.iTl.iY < rc.iBr.iY ? 1 : -1; + + for(int y = rc.iTl.iY;; y += stepY) { + for(int x = rc.iTl.iX;; x += stepX) { + *(framebuff + y*208 + x) = *(framebuff + y*208 + x) = color; + if(x == rc.iBr.iX) break; + } + if(y == rc.iBr.iY) break; + } + } +} + +// direction: -1 left, 1 right +void drawArrow0(TPoint p, int direction, unsigned short color) +{ + int width = 11; + int x = p.iX; + int y = p.iY; + + for(; width > 0; x+=direction, y++, width -=2) + for(int i=0; i < width; i++) + *(framebuff + x + y*208 + i*208) = color; +} + +void drawArrow90(TPoint p, int direction, unsigned short color) +{ + int width = 11; + int x = p.iX - width; + int y = p.iY; + + for(; width > 0; x++, y+=direction, width -=2) + for(int i=0; i < width; i++) + *(framebuff + x + y*208 + i) = color; +} + + +// copies temporary framebuff to real device framebuffer +void vidBlitRGB444(int full) +{ + unsigned short *ps; + unsigned short *pd; + int pixels; + if(full) { + ps = framebuff; + pd = (unsigned short *) screenbuff; + pixels = 208*320; + } else { + ps = framebuff + framebuff_offs; + pd = (unsigned short *) screenbuff + framebuff_offs; + pixels = framebuff_len; + } + + vidConvCpyRGB444(pd, ps, pixels); + //for(unsigned short *ps_end = ps + pixels; ps < ps_end; ps++) + // Convert 0000bbb0 ggg0rrr0 + // to 0000rrr0 ggg0bbb0 + // *pd++ = ((*ps&0x000F)<<8) | (*ps&0x00F0) | ((*ps&0x0F00)>>8); +} + +void vidBlitRGB565(int full) +{ + unsigned short *ps; + unsigned short *pd; + int pixels; + if(full) { + ps = framebuff; + pd = (unsigned short *) screenbuff; + pixels = 208*320; + } else { + ps = framebuff + framebuff_offs; + pd = (unsigned short *) screenbuff + framebuff_offs; + pixels = framebuff_len; + } + + vidConvCpyRGB565(pd, ps, pixels); + //for(; ps < ps_end; ps++) + // Convert 0000bbb0 ggg0rrr0 + // to rrr00ggg 000bbb00 + // *pd++ = ((*ps&0x000F)<<12) | ((*ps&0x00F0)<<3) | ((*ps&0x0F00)>>7); +} + +void vidBlitRGB32(int full) +{ + unsigned short *ps; + unsigned long *pd; + int pixels; + if(full) { + ps = framebuff; + pd = (unsigned long *) screenbuff; + pixels = 208*320; + } else { + ps = framebuff + framebuff_offs; + pd = (unsigned long *) screenbuff + framebuff_offs; + pixels = framebuff_len; + } + + vidConvCpyRGB32(pd, ps, pixels); + //for(; ps < ps_end; ps++) + // Convert 0000bbb0 ggg0rrr0 + // to ..0 rrr00000 ggg00000 bbb00000 + // *pd++ = ((*ps&0x000F)<<20) | ((*ps&0x00F0)<<8) | ((*ps&0x0F00)>>4); +} + +// -------- rendermode 2 --------- + +void vidBlit16M2(int full) +{ + unsigned short *ps = framebuff+328*8; + unsigned short *pd = (unsigned short *) screenbuff; + + if(currentConfig.iScreenRotation == TPicoConfig::PRot90) { + if(Pico.video.reg[12]&1) + vidConvCpyM2_16_90(pd, ps, 320/8); + else { + if(full) memset(pd, 0, 208*32*2); + pd += 208*32; + vidConvCpyM2_16_90(pd, ps, 256/8); + if(full) memset(pd + 208*256, 0, 208*32*2); + } + } else if(currentConfig.iScreenRotation == TPicoConfig::PRot270) { + if(Pico.video.reg[12]&1) + vidConvCpyM2_16_270(pd, ps, 320/8); + else { + if(full) memset(pd, 0, 208*32*2); + pd += 208*32; + ps -= 64; // the blitter starts copying from the right border, so we need to adjust + vidConvCpyM2_16_270(pd, ps, 256/8); + if(full) memset(pd + 208*256, 0, 208*32*2); + } + } +/* + for(int x=0; x < 320; x++) + for(int y=207; y>=0; y--) { + *pd++ = *(ps+8+x+y*328); + } +*/ +} + +void vidBlitRGB32M2(int full) +{ + unsigned short *ps = framebuff+328*8; + unsigned long *pd = (unsigned long *) screenbuff; + + if(currentConfig.iScreenRotation == TPicoConfig::PRot90) { + if(Pico.video.reg[12]&1) + vidConvCpyM2_RGB32_90(pd, ps, 320/8); + else { + if(full) memset(pd, 0, 208*32*4); + pd += 208*32; + vidConvCpyM2_RGB32_90(pd, ps, 256/8); + if(full) memset(pd + 208*256, 0, 208*32*4); + } + } else if(currentConfig.iScreenRotation == TPicoConfig::PRot270) { + if(Pico.video.reg[12]&1) + vidConvCpyM2_RGB32_270(pd, ps, 320/8); + else { + if(full) memset(pd, 0, 208*32*4); + pd += 208*32; + ps -= 64; // the blitter starts copying from the right border, so we need to adjust + vidConvCpyM2_RGB32_270(pd, ps, 256/8); + if(full) memset(pd + 208*256, 0, 208*32*4); + } + } +} + +void PrepareCramRGB444M2() +{ + vidConvCpyRGB444(cram_high, Pico.cram, 0x40); +} + +void PrepareCramRGB565M2() +{ + vidConvCpyRGB565(cram_high, Pico.cram, 0x40); +} + + +//////////////////////////////// +// main functions + +int vidInit(int displayMode, void *vidmem, int p800, int reinit) +{ + if(!reinit) { + // prepare framebuffer + screenbuff = (unsigned short *) vidmem; + framebuff = (unsigned short *) malloc(framebuffsize); + + if(!screenbuff) return KErrNotSupported; + if(!framebuff) return KErrNoMemory; + + // Cram function: go and hack Pico so it never gets called + PicoCram = EmuCramNull; + } + + // select suitable blitter + switch(displayMode) { + case EColor4K: vidBlit = vidBlitKeyCfg = vidBlitRGB444; break; + case EColor64K: vidBlit = vidBlitKeyCfg = vidBlitRGB565; break; + case EColor16M: vidBlit = vidBlitKeyCfg = vidBlitRGB32; break; + default: return KErrNotSupported; + } + + memset(framebuff, 0, framebuffsize); + + // rendermode 2? + if(PicoOpt&0x10) { + switch(displayMode) { + case EColor4K: + vidBlit = vidBlit16M2; + PicoPrepareCram = PrepareCramRGB444M2; + PicoCramHigh = cram_high; + color_redM2 = 0x0F22; + dt_dmask = 0x0333; + break; + case EColor64K: + vidBlit = vidBlit16M2; + PicoPrepareCram = PrepareCramRGB565M2; + PicoCramHigh = cram_high; + color_redM2 = 0xF882; + dt_dmask = 0x39e7; + break; + case EColor16M: + vidBlit = vidBlitRGB32M2; + break; + } + drawTextFps = drawTextFpsM2; + drawTextNotice = drawTextNoticeM2; + vidBlit(1); + return 0; + } + + framebuff_offs = 0; + framebuff_len = 208*320; + vidBlit(1); + + // setup all orientation related stuff + if(currentConfig.iScreenRotation == TPicoConfig::PRot0) { + if(currentConfig.iScreenMode == TPicoConfig::PMCenter) { + PicoScan = EmuScanCenter0; + framebuff_len = 208*224; + drawTextFps = drawTextFps0; + drawTextNotice = drawTextNotice0; + } else { + if(currentConfig.iScreenMode == TPicoConfig::PMFit2) { + if(p800) { + fc_inc = 6518; // 0.651786 (144+2) + txtheight_fit = 139; + framebuff_len = 208*146; + } else { + fc_inc = 9286; // 0.92857 + txtheight_fit = 201; + framebuff_len = 208*208; + } + } + PicoScan = EmuScanFit0; + drawTextFps = drawTextFpsFit0; + drawTextNotice = drawTextNoticeFit0; + } + } else if(currentConfig.iScreenRotation == TPicoConfig::PRot90) { + if(currentConfig.iScreenMode == TPicoConfig::PMFit) + PicoScan = EmuScanFit90; + else PicoScan = EmuScanCenter90; + drawTextFps = drawTextFps90; + drawTextNotice = drawTextNotice90; + } else if(currentConfig.iScreenRotation == TPicoConfig::PRot180) { + if(currentConfig.iScreenMode == TPicoConfig::PMCenter) { + PicoScan = EmuScanCenter180; + framebuff_len = 208*224; + } else { + if(currentConfig.iScreenMode == TPicoConfig::PMFit2) { + if(p800) { + fc_inc = 6518; // 0.651786 + fc_lines = 146; + framebuff_len = 208*146; + } else { + fc_inc = 9286; // 0.92857 + fc_lines = 208; + framebuff_len = 208*208; + } + } + PicoScan = EmuScanFit180; + } + drawTextFps = drawTextFps180; + drawTextNotice = drawTextNotice180; + } else if(currentConfig.iScreenRotation == TPicoConfig::PRot270) { + if(currentConfig.iScreenMode == TPicoConfig::PMFit) + PicoScan = EmuScanFit270; + else PicoScan = EmuScanCenter270; + drawTextFps = drawTextFps270; + drawTextNotice = drawTextNotice270; + } + + return 0; +} + +void vidFree() +{ + free(framebuff); + framebuff = 0; +} + +void vidDrawFrame(char *noticeStr, char *fpsStr, int num) +{ + PicoFrame(); + if(currentConfig.iFlags & 2) + drawTextFps(fpsStr); + drawTextNotice(noticeStr); + + vidBlit(!num); // copy full frame once a second +} + +void vidKeyConfigFrame(const TUint whichAction, TInt flipClosed) +{ + int i; + char buttonNames[128]; + buttonNames[0] = 0; + memset(framebuff, 0, framebuffsize); + + unsigned long currentActCode = 1 << whichAction; + + if(flipClosed) { + drawRectFilled(TRect(56, 2, 152, 16), color_grey); // 96x14 + drawArrow0(TPoint(64, 3), -1, color_green); + drawArrow0(TPoint(144, 3), 1, color_green); + drawText0(64, 20, "USE@JOG@TO@SELECT", color_red); + + drawText0(68, 6, actionNames[whichAction], color_red); + } else { + // draw all "buttons" in reverse order + const TPicoAreaConfigEntry *e = areaConfig + 1; i = 0; + while(e->rect != TRect(0,0,0,0)) { e++; i++; } + for(e--, i--; e->rect != TRect(0,0,0,0); e--, i--) + drawRect(e->rect, (currentConfig.iAreaBinds[i] & currentActCode) ? color_red : color_red_dim); + + // draw config controls + drawRectFilled(TRect(190, 112, 204, 208), color_grey); + drawArrow90(TPoint(203, 120), -1, color_green); + drawArrow90(TPoint(203, 200), 1, color_green); + + drawText90(200, 124, actionNames[whichAction], color_red); + } + + // draw active button names if there are any + i = 0; + for(TPicoKeyConfigEntry *e = keyConfig; e->name; e++, i++) + if(currentConfig.iKeyBinds[i] & currentActCode) { + if(buttonNames[0]) strcat(buttonNames, ";@"); + strcat(buttonNames, e->name); + } + if(buttonNames[0]) { + if(flipClosed) { + buttonNames[41] = 0; // only 61 chars fit + drawText0(2, 138, buttonNames, color_blue); + } else { + buttonNames[61] = 0; + drawText90(12, 10, buttonNames, color_blue); + } + } + + vidBlitKeyCfg(1); +} + +void vidDrawFCconfigDone() +{ + drawText0(64, 20, "USE@JOG@TO@SELECT", 0); // blank prev text + drawText0(54, 30, "OPEN@FLIP@TO@CONTINUE", color_red); + vidBlitKeyCfg(1); +} + +void vidDrawNotice(const char *txt) +{ + if(framebuff) { + drawTextNotice(txt); + vidBlit(1); + } +} diff --git a/platform/uiq2/vid.h b/platform/uiq2/vid.h new file mode 100644 index 00000000..0b28cb86 --- /dev/null +++ b/platform/uiq2/vid.h @@ -0,0 +1,9 @@ +#include + +// let's do it in more c-like way +int vidInit(int displayMode, void *vidmem, int p800, int reinit=0); +void vidFree(); +void vidDrawFrame(char *noticeStr, char *fpsStr, int num); +void vidKeyConfigFrame(const TUint whichAction, TInt flipClosed); +void vidDrawFCconfigDone(); +void vidDrawNotice(const char *txt); // safe to call anytime, draws text for 1 frame diff --git a/platform/uiq3/App.cpp b/platform/uiq3/App.cpp new file mode 100644 index 00000000..74e7d247 --- /dev/null +++ b/platform/uiq3/App.cpp @@ -0,0 +1,485 @@ +/******************************************************************* + * + * File: App.cpp + * + * Author: Peter van Sebille (peter@yipton.net) + * + * Modified/adapted for picodriveN by notaz, 2006 + * + * (c) Copyright 2006, notaz + * (c) Copyright 2002, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +#include "app.h" +// #include "picodriven.mbg" // bitmap identifiers +#include // resource include +#include +#include +//#include +//#include +//#include // CEikMenuBar +#include // TApaSystemEvent +#include +#include +#include + +#include +#include +#include +#include + +#include "Dialogs.h" +#include "engine/debug.h" + + + +//////////////////////////////////////////////////////////////// +// +// class CPicolAppView +// +//////////////////////////////////////////////////////////////// + +// Creates and constructs the view. +CPicolAppView* CPicolAppView::NewLC(CQikAppUi& aAppUi, TPicoConfig& aCurrentConfig) +{ + CPicolAppView* self = new (ELeave) CPicolAppView(aAppUi, aCurrentConfig); + CleanupStack::PushL(self); + return self; +} + +/** +Constructor for the view. +Passes the application UI reference to the construction of the super class. + +KNullViewId should normally be passed as parent view for the applications +default view. The parent view is the logical view that is normally activated +when a go back command is issued. KNullViewId will activate the system +default view. + +@param aAppUi Reference to the application UI +*/ +CPicolAppView::CPicolAppView(CQikAppUi& aAppUi, TPicoConfig& aCurrentConfig) +: CQikViewBase(aAppUi, KNullViewId), iCurrentConfig(aCurrentConfig) +{ +} + +void CPicolAppView::ConstructL() +{ + BaseConstructL(); +} + +CPicolAppView::~CPicolAppView() +{ +} + + +/** +Inherited from CQikViewBase and called upon by the UI Framework. +It creates the view from resource. +*/ +void CPicolAppView::ViewConstructL() +{ + // Loads information about the UI configurations this view supports + // together with definition of each view. + ViewConstructFromResourceL(R_APP_UI_CONFIGURATIONS); + UpdateCommandList(); +} + +/** +Returns the view Id + +@return Returns the Uid of the view +*/ +TVwsViewId CPicolAppView::ViewId()const +{ + return TVwsViewId(KUidPicolApp, KUidPicolMainView); +} + +/** +Handles all commands in the view. +Called by the UI framework when a command has been issued. +The command Ids are defined in the .hrh file. + +@param aCommand The command to be executed +@see CQikViewBase::HandleCommandL +*/ +void CPicolAppView::HandleCommandL(CQikCommand& aCommand) +{ + TInt res; + + switch(aCommand.Id()) + { + case EEikCmdPicoLoadState: + if(iROMLoaded) { + CEikonEnv::Static()->BusyMsgL(_L("Loading State")); + res = CPicoGameSession::Do(PicoMsgLoadState); + CEikonEnv::Static()->BusyMsgCancel(); + // emu doesn't start to run if load fails, so we can display this + if(res) CEikonEnv::Static()->InfoMsg(_L("Load Failed")); + } + break; + + case EEikCmdPicoSaveState: + if(iROMLoaded) { + CEikonEnv::Static()->BusyMsgL(_L("Saving State")); + res = CPicoGameSession::Do(PicoMsgSaveState); + CEikonEnv::Static()->BusyMsgCancel(); + if(res) CEikonEnv::Static()->InfoMsg(_L("Save Failed")); + } + break; + + case EEikCmdPicoLoadROM: + DisplayOpenROMDialogL(); + DEBUGPRINT(_L("after DisplayOpenROMDialogL()")); + break; + + case EEikCmdPicoResume: + CPicoGameSession::Do(PicoMsgResume); + break; + + case EEikCmdPicoReset: + CPicoGameSession::Do(PicoMsgReset); + break; + + case EEikCmdPicoSettings: + DisplayConfigDialogL(); + break; + + case EEikCmdHelpAbout: + DisplayAboutDialogL(); + break; + + case EEikCmdPicoDebugInfo: + DisplayDebugDialogL(); + break; + + case EEikCmdPicoKeys: + CPicoGameSession::Do(PicoMsgConfigChange, &iCurrentConfig); + CPicoGameSession::Do(PicoMsgKeys); + break; + + case EEikCmdPicoFrameskipAuto: + iCurrentConfig.iFrameskip = TPicoConfig::PFSkipAuto; + iQikAppUi.Document()->SaveL(); + break; + + case EEikCmdPicoFrameskip0: + iCurrentConfig.iFrameskip = 0; + iQikAppUi.Document()->SaveL(); + break; + + case EEikCmdPicoFrameskip1: + iCurrentConfig.iFrameskip = 1; + iQikAppUi.Document()->SaveL(); + break; + + case EEikCmdPicoFrameskip2: + iCurrentConfig.iFrameskip = 2; + iQikAppUi.Document()->SaveL(); + break; + + case EEikCmdPicoFrameskip4: + iCurrentConfig.iFrameskip = 4; + iQikAppUi.Document()->SaveL(); + break; + + case EEikCmdPicoFrameskip8: + iCurrentConfig.iFrameskip = 8; + iQikAppUi.Document()->SaveL(); + break; + + case EEikCmdExit: + iQikAppUi.Document()->SaveL(); + CPicoGameSession::freeResources(); + //break; // this is intentional + + default: + // Go back and exit command will be passed to the CQikViewBase to handle. + CQikViewBase::HandleCommandL(aCommand); + break; + } +} + +void CPicolAppView::DisplayOpenROMDialogL() +{ + // Array of mimetypes that the dialog shall filter on, if empty all + // mimetypes will be visible. + CDesCArray* mimeArray = new (ELeave) CDesCArrayFlat(1); + CleanupStack::PushL(mimeArray); + // Array that will be filled with the file paths that are choosen + // from the dialog. + CDesCArray* fileArray = new (ELeave) CDesCArraySeg(3); + CleanupStack::PushL(fileArray); + _LIT16(KDlgTitle, "Select a ROM file"); + + if( CQikSelectFileDlg::RunDlgLD( *mimeArray, *fileArray, &KDlgTitle, &iCurrentConfig.iLastROMFile) ) + { + CEikonEnv::Static()->BusyMsgL(_L("Loading ROM")); + TPtrC16 file = (*fileArray)[0]; + iCurrentConfig.iLastROMFile.Copy(file); + + // push the config first + CPicoGameSession::Do(PicoMsgSetAppView, this); + CPicoGameSession::Do(PicoMsgConfigChange, &iCurrentConfig); + + TInt res = CPicoGameSession::Do(PicoMsgLoadROM, &file); + + CEikonEnv::Static()->BusyMsgCancel(); + + iROMLoaded = EFalse; + switch (res) + { + case PicoErrRomOpenFailed: + CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed to open file.")); + break; + + case PicoErrOutOfMem: + CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed to allocate memory.")); + break; + + case PicoErrNotRom: + CEikonEnv::Static()->InfoWinL(_L("Error"), _L("The file you selected is not a game ROM.")); + break; + + case PicoErrNoRomsInArchive: + CEikonEnv::Static()->InfoWinL(_L("Error"), _L("No game ROMs found in zipfile.")); + break; + + case PicoErrUncomp: + CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed while unzipping ROM.")); + break; + + case PicoErrEmuThread: + CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed to create emulation thread. Try to restart this application.")); + break; + + default: + iROMLoaded = ETrue; + break; + } + + // errors which leave ROM loaded + switch (res) + { + case PicoErrOutOfMemSnd: + CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed to allocate sound buffer, disabled sound.")); + break; + + case PicoErrGenSnd: + CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed to start soundsystem, disabled sound.")); + break; + } + if(res == 6 || res == 7) iCurrentConfig.iFlags &= ~4; + + if(iROMLoaded) { + if(iTitleAdded) + ViewContext()->ChangeTextL(EEikCidTitleBarLabel, CPicoGameSession::iRomInternalName); + else ViewContext()->AddTextL (EEikCidTitleBarLabel, CPicoGameSession::iRomInternalName); + iTitleAdded = ETrue; + UpdateCommandList(); + } + } + CleanupStack::PopAndDestroy(2, mimeArray); +} + + +void CPicolAppView::DisplayConfigDialogL() +{ + CPicoConfigDialog* configDialog = new(ELeave)CPicoConfigDialog(iCurrentConfig); + configDialog->ExecuteLD(R_PICO_CONFIG); + + CPicoGameSession::Do(PicoMsgConfigChange, &iCurrentConfig); + iQikAppUi.Document()->SaveL(); +} + + +void CPicolAppView::DisplayAboutDialogL() +{ + TInt iButtonRes; + CAboutDialog* dialog = new (ELeave) CAboutDialog; + + dialog->PrepareLC(R_PICO_ABOUT); + iButtonRes = dialog->RunLD(); + + if(iButtonRes == EEikCmdPicoAboutCreditsCmd) { + CCreditsDialog *creditsDialog = new (ELeave) CCreditsDialog(); + creditsDialog->PrepareLC(R_PICO_CREDITS); + creditsDialog->RunLD(); + } +} + +#ifdef __DEBUG_PRINT +extern "C" char *debugString(); +#endif + +void CPicolAppView::DisplayDebugDialogL() +{ +#ifdef __DEBUG_PRINT + CDebugDialog* dialog = new (ELeave) CDebugDialog(debugString()); + + dialog->PrepareLC(R_PICO_DEBUG); + dialog->RunLD(); +#endif +} + +void CPicolAppView::UpdateCommandList() +{ + CQikCommandManager& commandManager = CQikCommandManager::Static(*iCoeEnv); + CQikCommand *cmd_fs[10]; + Mem::FillZ(cmd_fs, sizeof(CQikCommand*)*10); + + CQikCommand* cmd_reset = commandManager.Command(*this, EEikCmdPicoReset); + CQikCommand* cmd_savest = commandManager.Command(*this, EEikCmdPicoSaveState); + CQikCommand* cmd_loadst = commandManager.Command(*this, EEikCmdPicoLoadState); + CQikCommand* cmd_resume = commandManager.Command(*this, EEikCmdPicoResume); + cmd_fs[0] = commandManager.Command(*this, EEikCmdPicoFrameskipAuto); + cmd_fs[1] = commandManager.Command(*this, EEikCmdPicoFrameskip0); + cmd_fs[2] = commandManager.Command(*this, EEikCmdPicoFrameskip1); + cmd_fs[3] = commandManager.Command(*this, EEikCmdPicoFrameskip2); + cmd_fs[5] = commandManager.Command(*this, EEikCmdPicoFrameskip4); + cmd_fs[9] = commandManager.Command(*this, EEikCmdPicoFrameskip8); + + TBool dimmed = !CPicoGameSession::iEmuRunning || !iROMLoaded; + cmd_reset ->SetDimmed(dimmed); + cmd_savest->SetDimmed(dimmed); + cmd_loadst->SetDimmed(dimmed); + cmd_resume->SetDimmed(dimmed); + + // frameskip + TInt fs_index = iCurrentConfig.iFrameskip + 1; + if (fs_index >= 0 && fs_index < 10 && cmd_fs[fs_index]) + { + cmd_fs[fs_index]->SetChecked(ETrue); + } +} + + +//////////////////////////////////////////////////////////////// +// +// class CPicolAppUi +// +//////////////////////////////////////////////////////////////// + + +void CPicolAppUi::ConstructL() +{ + BaseConstructL(); + + // Create the view and add it to the framework + iAppView = CPicolAppView::NewLC(*this, ((CPicolDocument *)Document())->iCurrentConfig); + AddViewL(*iAppView); + CleanupStack::Pop(iAppView); +} + + +//////////////////////////////////////////////////////////////// +// +// CPicolDocument +// +//////////////////////////////////////////////////////////////// + + +CPicolDocument::CPicolDocument(CQikApplication& aApp) +: CQikDocument(aApp) +{ + iCurrentConfig.SetDefaults(); +} + +CQikAppUi* CPicolDocument::CreateAppUiL() +{ + return new(ELeave) CPicolAppUi; +} + +/** +Called by the framework when ::SaveL has been called. +*/ +void CPicolDocument::StoreL(CStreamStore& aStore, CStreamDictionary& aStreamDic) const +{ + RStoreWriteStream stream; + + TStreamId preferenceId = stream.CreateLC(aStore); + aStreamDic.AssignL(KUidPicolStore, preferenceId); + + // Externalize preference + stream << iCurrentConfig; + + // Ensures that any buffered data is written to aStore + stream.CommitL(); + CleanupStack::PopAndDestroy(); // stream + +/* + // tmp + TInt res; + RFile logFile; + res = logFile.Replace(CEikonEnv::Static()->FsSession(), _L("C:\\Shared\\pico.cfg"), EFileWrite|EFileShareAny); + if(!res) { + logFile.Write(TPtr8((TUint8 *)&iCurrentConfig, sizeof(iCurrentConfig), sizeof(iCurrentConfig))); + logFile.Close(); + } +*/ +} + +/** +Called by the framework on application start. +Loads the application data from disk, i.e. domain data and preferences. +*/ +void CPicolDocument::RestoreL(const CStreamStore& aStore, const CStreamDictionary& aStreamDic) +{ + // Find the stream ID of the model data from the stream dictionary: + TStreamId preferenceId(aStreamDic.At(KUidPicolStore)); + RStoreReadStream stream; + stream.OpenLC(aStore, preferenceId); + if(preferenceId != KNullStreamId) + { + // Interalize preference and model + stream >> iCurrentConfig; + } + + CleanupStack::PopAndDestroy(); // stream + + + // tmp +/* TInt res; + RFile logFile; + res = logFile.Open(CEikonEnv::Static()->FsSession(), _L("C:\\Shared\\pico.cfg"), EFileRead|EFileShareAny); + if(!res) { + TPtr8 ptr((TUint8 *)&iCurrentConfig, sizeof(iCurrentConfig), sizeof(iCurrentConfig)); + logFile.Read(ptr); + logFile.Close(); + }*/ +} + +//////////////////////////////////////////////////////////////// +// +// framework +// +//////////////////////////////////////////////////////////////// + + +CApaDocument* CPicolApplication::CreateDocumentL() +{ + return new (ELeave) CPicolDocument(*this); +} + +EXPORT_C CApaApplication* NewApplication() +{ + return new CPicolApplication; +} + + +TUid CPicolApplication::AppDllUid() const +{ + return KUidPicolApp; +} + + +GLDEF_C TInt E32Main() +{ + User::SetExceptionHandler(ExceptionHandler, (TUint32) -1); + + return EikStart::RunApplication(NewApplication); +} + + diff --git a/platform/uiq3/App.h b/platform/uiq3/App.h new file mode 100644 index 00000000..9dcb5723 --- /dev/null +++ b/platform/uiq3/App.h @@ -0,0 +1,112 @@ +/******************************************************************* + * + * File: App.h + * + * Author: Peter van Sebille (peter@yipton.net) + * + * Modified/adapted for picodriveN by notaz, 2006 + * + * (c) Copyright 2006, notaz + * (c) Copyright 2001, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +#ifndef __APP_H +#define __APP_H + +#include +#include +#include + +#include +#include +#include +//#include +#include + +#include "Engine.h" +#include "picodrive.hrh" + +const TUid KUidPicolApp = { 0xA00010F3 }; +const TUid KUidPicolMainView = { 0x00000001 }; +//const TUid KUidPicolFOView = { 0x1000C194 }; +//const TUid KUidPicolFCView = { 0x1000C195 }; +const TUid KUidPicolStore = { 0x00000011 }; // store stream UID + +//enum +//{ +// EScreenModeFlipOpen = 0, +// EScreenModeFlipClosed +//}; + + + +class CPicolAppView : public CQikViewBase +{ +public: + static CPicolAppView* NewLC(CQikAppUi& aAppUi, TPicoConfig& aCurrentConfig); + ~CPicolAppView(); + + // from CQikViewBase + TVwsViewId ViewId()const; + void HandleCommandL(CQikCommand& aCommand); + void UpdateCommandList(); + +protected: + // from CQikViewBase + void ViewConstructL(); + +private: + CPicolAppView(CQikAppUi& aAppUi, TPicoConfig& aCurrentConfig); + void ConstructL(); + +protected: // new stuf + void DisplayAboutDialogL(); + void DisplayOpenROMDialogL(); + void DisplayConfigDialogL(); + void DisplayDebugDialogL(); + +/* void StopGame(); + void RunGameL();*/ + +private: + TPicoConfig& iCurrentConfig; + TBool iROMLoaded; + TBool iTitleAdded; +}; + + + +class CPicolAppUi : public CQikAppUi +{ +public: +// CPicolAppUi(); + void ConstructL(); + + CPicolAppView* iAppView; +}; + + +class CPicolDocument : public CQikDocument +{ +public: + CPicolDocument(CQikApplication& aApp); + void StoreL(CStreamStore& aStore, CStreamDictionary& aStreamDic) const; + void RestoreL(const CStreamStore& aStore, const CStreamDictionary& aStreamDic); + + TPicoConfig iCurrentConfig; + +private: // from CQikDocument + CQikAppUi* CreateAppUiL(); +}; + + +class CPicolApplication : public CQikApplication +{ +private: // from CApaApplication + CApaDocument* CreateDocumentL(); + TUid AppDllUid() const; +}; + +#endif diff --git a/platform/uiq3/CSimpleTextParser.cpp b/platform/uiq3/CSimpleTextParser.cpp new file mode 100644 index 00000000..865e35ee --- /dev/null +++ b/platform/uiq3/CSimpleTextParser.cpp @@ -0,0 +1,477 @@ +/******************************************************************* + * + * File: CSimpleTextParser.cpp + * + * Author: Peter van Sebille (peter@yipton.net) + * + * (c) Copyright 2002, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +#include "CSimpleTextParser.h" + +enum +{ + EBadTag, + EBadZeroLengthTag, + EBadIntegerParam, + EBadAlignmentParam, + EBadRgbColorParam +}; + +void Panic(TInt aPanic) +{ + User::Panic(_L("STP"), aPanic); +} + +CSimpleTextFormatParser* CSimpleTextFormatParser::NewLC() +{ + CSimpleTextFormatParser* self = new(ELeave)CSimpleTextFormatParser; + CleanupStack::PushL(self); + self->ConstructL(); + return self; +} + +CSimpleTextFormatParser::~CSimpleTextFormatParser() +{ + delete iParaFormat; +} + +void CSimpleTextFormatParser::ConstructL() +{ + iParaFormat = CParaFormat::NewL(); +} + + +void CSimpleTextFormatParser::SetBold(TBool aEnable) +{ + iCharFormat.iFontSpec.iFontStyle.SetStrokeWeight(aEnable ? EStrokeWeightBold : EStrokeWeightNormal); + iCharMask.ClearAll(); + iCharMask.SetAttrib(EAttFontStrokeWeight); + iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0); +} + +void CSimpleTextFormatParser::SetItalic(TBool aEnable) +{ + iCharFormat.iFontSpec.iFontStyle.SetPosture(aEnable ? EPostureItalic : EPostureUpright); + iCharMask.ClearAll(); + iCharMask.SetAttrib(EAttFontPosture); + iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0); +} + +void CSimpleTextFormatParser::SetUnderLine(TBool aEnable) +{ + iCharFormat.iFontPresentation.iUnderline = aEnable ? EUnderlineOn : EUnderlineOff; + iCharMask.ClearAll(); + iCharMask.SetAttrib(EAttFontUnderline); + iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0); +} + +void CSimpleTextFormatParser::SetHiddenText(TBool aEnable) +{ + iCharFormat.iFontPresentation.iHiddenText = aEnable; + iCharMask.ClearAll(); + iCharMask.SetAttrib(EAttFontHiddenText); + iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0); +} + +TRgb CSimpleTextFormatParser::ForegroundColor() +{ + iCharMask.ClearAll(); + iCharMask.SetAttrib(EAttColor); + iRichText->GetCharFormat(iCharFormat, iCharMask, TextPos(), 0); + return iCharFormat.iFontPresentation.iTextColor; +} + +void CSimpleTextFormatParser::SetForegroundColor(const TRgb& aColor) +{ + iCharFormat.iFontPresentation.iTextColor = aColor; + iCharMask.ClearAll(); + iCharMask.SetAttrib(EAttColor); + iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0); +} + +void CSimpleTextFormatParser::SetBackgroundColor(const TRgb& aColor) +{ + iParaFormat->iFillColor = aColor; + iParaMask.ClearAll(); + iParaMask.SetAttrib(EAttFillColor); + iRichText->ApplyParaFormatL(iParaFormat, iParaMask, ParaPos(), 0); +} + +void CSimpleTextFormatParser::NewParagraph() +{ + iCurrentPara++; + iRichText->AppendParagraphL(); + AppendTextL(_L("")); +} + + +void CSimpleTextFormatParser::SetAlignment(CParaFormat::TAlignment aAlignment) +{ + iParaFormat->iHorizontalAlignment = aAlignment; + iParaMask.ClearAll(); + iParaMask.SetAttrib(EAttAlignment); + iRichText->ApplyParaFormatL(iParaFormat, iParaMask, ParaPos(), 0); +} + + +void CSimpleTextFormatParser::SetFontHeight(TInt aHeight) +{ + iCharFormat.iFontSpec.iHeight = (aHeight * KTwipsPerInch)/KPointsPerInch; + iCharMask.ClearAll(); + iCharMask.SetAttrib(EAttFontHeight); + iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0); +} + +void CSimpleTextFormatParser::SetFontName(const TDesC& aName) +{ + iCharFormat.iFontSpec.iTypeface.iName = aName; + iCharFormat.iFontSpec.iTypeface.SetAttributes(0); + iCharFormat.iFontSpec.iTypeface.SetIsProportional(ETrue); + iCharMask.ClearAll(); + iCharMask.SetAttrib(EAttFontTypeface); + iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0); +} + + +/* + * Character formatting: + * Bold on + * Bold of + * Italic on + * Italic off + * Underline on + * Underline off + * Hidden text on **doesn't work** + * Hidden text off **doesn't work** + * Fontname: name (type: string) + * Fontsize: size (type: integer) + * Foreground color: color (type: color) + * Restore foreground color + * + * Paragraph formatting: + *

New paragraph - will reset both character & paragraph formatting to defaults + * Alignment: aling (type: alignement) + * Background color: color (type: color) **doesn't work** + * + * Special characters: + * The character: < + * + * Types: + * - string: + * - integer: Either decimal or hexidecimal value + * - color: Either integer specifing rgb value, or (r,g,b) in which r, g and b are of type integer + * - align: element of enumeration {center, left, right} + * + * Comments: + * The syntax/parser is fairly simplistic. The parser is not trying to match a tag like + * as XML/HTML do. Basically, when it encounters a tag (e.g., ) it will + * simply instruct the the editor to apply the formatting from the current position as + * specified by the tag (e.g., enable bold). For example, HelloWorld results + * in Hello displayed in a Bold font and World in a normal font. + * + * The only case where state is maintained is when using and . The current + * fg color is stored when parsing and restored when doing . Again, and + * don't have the XML/HTML behavior. For example: + * Peterwashere + * results in "Peter" displayed in red, "was" displayed in blue and "here" displayed in red. + * It literally goes like this: + * 1) --> apply editor text color red, previous color = whatever the editor's text color is now + * 2) --> apply editor text color blue, previous color = whatever the editor's text color + * is now --> red + * 3) --> apply editor text to previous color --> red + * 4) --> apply editor text to previous color --> red + * + * What you probably wanted was: + * Peterwashere + * Now "Peter" is displayed in red, "was" in blue and "here" in the default editor's color + */ + +static TUint32 ParseInteger(const TDesC& aString) +{ + TUint32 val = 0; + TBool parsed = EFalse; + if (aString.Length() > 2) + { + if ((aString[0] == '0') && ((aString[0] == 'x') || (aString[0] == 'X'))) + { + TLex lex(aString.Right(aString.Length()-2)); + if (lex.Val(val, EHex) != KErrNone) + { + __ASSERT_DEBUG(ETrue, Panic(EBadIntegerParam)); + } + parsed = ETrue; + } + } + if (!parsed) + { + TLex lex(aString); + if (lex.Val(val, EDecimal) != KErrNone) + { + __ASSERT_DEBUG(ETrue, Panic(EBadIntegerParam)); + } + } + return val; +} + +static TRgb ParseColor(const TDesC& aString) +{ + if (aString.Length() > 0) + { + if (aString[0] == 'R') + { + if (aString.Compare(_L("RgbBlack")) == 0) + return KRgbBlack; + else if (aString.Compare(_L("RgbDarkGray")) == 0) + return KRgbDarkGray; + else if (aString.Compare(_L("RgbDarkRed")) == 0) + return KRgbDarkRed; + else if (aString.Compare(_L("RgbDarkGreen")) == 0) + return KRgbDarkGreen; + else if (aString.Compare(_L("RgbDarkYellow")) == 0) + return KRgbDarkYellow; + else if (aString.Compare(_L("RgbDarkBlue")) == 0) + return KRgbDarkBlue; + else if (aString.Compare(_L("RgbDarkMagenta")) == 0) + return KRgbDarkMagenta; + else if (aString.Compare(_L("RgbDarkCyan")) == 0) + return KRgbDarkCyan; + else if (aString.Compare(_L("RgbRed")) == 0) + return KRgbRed; + else if (aString.Compare(_L("RgbGreen")) == 0) + return KRgbGreen; + else if (aString.Compare(_L("RgbYellow")) == 0) + return KRgbYellow; + else if (aString.Compare(_L("RgbBlue")) == 0) + return KRgbBlue; + else if (aString.Compare(_L("RgbMagenta")) == 0) + return KRgbMagenta; + else if (aString.Compare(_L("RgbCyan")) == 0) + return KRgbCyan; + else if (aString.Compare(_L("RgbGray")) == 0) + return KRgbGray; + else if (aString.Compare(_L("RgbWhite")) == 0) + return KRgbWhite; + else + { + __ASSERT_DEBUG(ETrue, Panic(EBadRgbColorParam)); + } + } + return ParseInteger(aString); + } + __ASSERT_DEBUG(ETrue, Panic(EBadRgbColorParam)); + + return KRgbBlack; +} + + + +static CParaFormat::TAlignment ParseAlignment(const TDesC& aString) +{ + if (aString.Compare(_L("center")) == 0) + { + return CParaFormat::ECenterAlign; + } + else if (aString.Compare(_L("left")) == 0) + { + return CParaFormat::ELeftAlign; + } + else if (aString.Compare(_L("right")) == 0) + { + return CParaFormat::ERightAlign; + } + __ASSERT_DEBUG(ETrue, Panic(EBadAlignmentParam)); + + return CParaFormat::ECenterAlign; +} + +void CSimpleTextFormatParser::ParseTagL(const TDesC& aTag) +{ + TInt tagLength = aTag.Length(); + if (tagLength == 0) + { + __ASSERT_DEBUG(ETrue, Panic(EBadZeroLengthTag)); + return; + } + + TPtrC param(_L("")); + TInt pos = aTag.Find(_L("=")); + if (pos>0) + { + param.Set(aTag.Right(aTag.Length()-pos-1)); + tagLength = pos; + } + TPtrC tag = aTag.Left(tagLength); + +// RDebug::Print(_L("tag=%S, param=%S"), &tag, ¶m); + + switch (tagLength) + { + case 1: + { + if (tag.Compare(_L("a")) == 0) + SetAlignment(ParseAlignment(param)); + else if (tag.Compare(_L("b")) == 0) + SetBold(); + else if (tag.Compare(_L("f")) == 0) + SetFontName(param); + else if (tag.Compare(_L("h")) == 0) + SetHiddenText(); + else if (tag.Compare(_L("i")) == 0) + SetItalic(); + else if (tag.Compare(_L("p")) == 0) + NewParagraph(); + else if (tag.Compare(_L("s")) == 0) + SetFontHeight(ParseInteger(param)); + else if (tag.Compare(_L("u")) == 0) + SetUnderLine(); + else + { + __ASSERT_DEBUG(ETrue, Panic(EBadTag)); + } + break; + } + + case 2: + { + if (tag.Compare(_L("/b")) == 0) + SetBold(EFalse); + if (tag.Compare(_L("bg")) == 0) + SetBackgroundColor(ParseColor(param)); + if (tag.Compare(_L("fg")) == 0) + { + iPrevFgColor = ForegroundColor(); + SetForegroundColor(ParseColor(param)); + } + else if (tag.Compare(_L("/h")) == 0) + SetHiddenText(EFalse); + else if (tag.Compare(_L("/i")) == 0) + SetItalic(EFalse); + else if (tag.Compare(_L("/u")) == 0) + SetUnderLine(EFalse); + else if (tag.Compare(_L("/<")) == 0) + AppendTextL(_L("<")); + break; + } + case 3: + { + if (tag.Compare(_L("/fg")) == 0) + SetForegroundColor(iPrevFgColor); + break; + } + default: + ; + } +} + +void CSimpleTextFormatParser::ParseL(const TDesC& aSimpleText, CRichText& aRichText) +{ + iRichText = &aRichText; + iCurrentPara = 0; + + TBool done = EFalse; + TPtrC simpleText(aSimpleText); + do + { + TInt pos = simpleText.Locate('<'); + if (pos > 0) + { + AppendTextL(simpleText.Left(pos)); + simpleText.Set(simpleText.Right(simpleText.Length() - pos)); + } + else if (pos == 0) + { + pos = simpleText.Locate('>'); + if (pos<=0) + User::Leave(KErrArgument); + ParseTagL(simpleText.Mid(1, pos-1)); + simpleText.Set(simpleText.Right(simpleText.Length() - pos - 1)); + } + else + { + AppendTextL(simpleText); + done = ETrue; + } + } while (!done); +} + + +TInt CSimpleTextFormatParser::TextPos() +{ + return iRichText->DocumentLength(); +#if 0 + TInt pos, length; + pos = iRichText->CharPosOfParagraph(length, iCurrentPara); + return pos+length-1; +#endif +} + +TInt CSimpleTextFormatParser::ParaPos() +{ + return TextPos(); +#if 0 + TInt pos, length; + pos = iRichText->CharPosOfParagraph(length, iCurrentPara); + return pos+length-1; +#endif +} + + +void CSimpleTextFormatParser::AppendTextL(const TDesC& aText) +{ +// RDebug::Print(_L("text=%S"), &aText); + iRichText->InsertL(TextPos(), aText); +} + + +#if 0 +void CTestDialog::ShowTextL(CRichText& aRichText) +{ + aRichText.Reset(); + + TCharFormat charFormat; + TCharFormatMask charMask; + aRichText.GetCharFormat(charFormat, charMask, 0, 0); + + TInt para = 0; + AppendTextL(_L("http://www.yipton.net"), aRichText); + + para++; + aRichText.AppendParagraphL(); + + CParaFormat* paraFormat = CParaFormat::NewLC(); + TParaFormatMask paraMask; + aRichText.GetParaFormatL(paraFormat, paraMask, ParaPos(aRichText, para), 0); + paraFormat->iHorizontalAlignment = CParaFormat::ECenterAlign; + paraMask.ClearAll(); + paraMask.SetAttrib(EAttAlignment); + aRichText.ApplyParaFormatL(paraFormat, paraMask, ParaPos(aRichText, para), 0); + + charFormat.iFontPresentation.iUnderline = EUnderlineOn; + charFormat.iFontSpec.iFontStyle.SetPosture(EPostureItalic); + charMask.ClearAll(); + charMask.SetAttrib(EAttFontPosture); + charMask.SetAttrib(EAttFontUnderline); + aRichText.ApplyCharFormatL(charFormat, charMask, TextPos(aRichText, para)); + AppendTextL(_L("mailto:Peter is here"), aRichText, para); + + para++; + aRichText.AppendParagraphL(); + + TFontSpec fontSpec(_L("edmunds"), 20 * KPointsPerInch); +// CFont* font = NULL; +// iCoeEnv->ScreenDevice()->GetNearestFontInTwips(font, fontSpec); + + charFormat.iFontSpec = fontSpec; + charMask.ClearAll(); + charMask.SetAttrib(EAttFontHeight); + charMask.SetAttrib(EAttFontTypeface); + aRichText.ApplyCharFormatL(charFormat, charMask, TextPos(aRichText, para)); + AppendTextL(_L("mailto:Peter is here"), aRichText, para); + + CleanupStack::PopAndDestroy(); +} + +#endif diff --git a/platform/uiq3/CSimpleTextParser.h b/platform/uiq3/CSimpleTextParser.h new file mode 100644 index 00000000..f5bdc7c3 --- /dev/null +++ b/platform/uiq3/CSimpleTextParser.h @@ -0,0 +1,59 @@ +/******************************************************************* + * + * File: CSimpleTextParser.h + * + * Author: Peter van Sebille (peter@yipton.net) + * + * (c) Copyright 2002, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +#ifndef __CSIMPLE_TEXT_PARSER_H +#define __CSIMPLE_TEXT_PARSER_H + +#include +#include // CRichText +#include // CEikRichTextEditor + +class CSimpleTextFormatParser : public CBase +{ +public: + static CSimpleTextFormatParser* NewLC(); + void ParseL(const TDesC& aPSTText, CRichText& aRichText); + +protected: + CSimpleTextFormatParser(){} + ~CSimpleTextFormatParser(); + void ConstructL(); + + void ParseTagL(const TDesC& aTag); + + TRgb ForegroundColor(); + void SetBold(TBool aEnable=ETrue); + void SetItalic(TBool aEnable=ETrue); + void SetUnderLine(TBool aEnable=ETrue); + void SetFontHeight(TInt aHeight); + void SetFontName(const TDesC& aName); + void SetHiddenText(TBool aEnable=ETrue); + void SetForegroundColor(const TRgb& aColor); + + void NewParagraph(); + void SetAlignment(CParaFormat::TAlignment aAlignment); + void SetBackgroundColor(const TRgb& aColor); + + void AppendTextL(const TDesC& aText); + TInt TextPos(); + TInt ParaPos(); + + + CRichText* iRichText; + TCharFormat iCharFormat; + TCharFormatMask iCharMask; + CParaFormat* iParaFormat; + TParaFormatMask iParaMask; + TInt iCurrentPara; + TRgb iPrevFgColor; +}; + +#endif /* __CSIMPLE_TEXT_PARSER_H */ diff --git a/platform/uiq3/Dialogs.cpp b/platform/uiq3/Dialogs.cpp new file mode 100644 index 00000000..60b8685c --- /dev/null +++ b/platform/uiq3/Dialogs.cpp @@ -0,0 +1,324 @@ +/******************************************************************* + * + * File: Dialogs.cpp + * + * Author: Peter van Sebille (peter@yipton.net) + * + * Modified/adapted for picodriveN by notaz, 2006 + * + * (c) Copyright 2006, notaz + * (c) Copyright 2002, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +#include "Dialogs.h" +#include "Engine.h" +#include "picodrive.hrh" +#include + +#include "version.h" +#include "CSimpleTextParser.h" +#include // CRichText +#include // CEikRichTextEditor +#include // CEikHorOptionButtonList +#include // CEikOptionButton +#include // CEikEdwin +#include // EQuartzKeyTwoWayDown + +#include + + +/************************************************ + * + * config Dialog + * + ************************************************/ + +CPicoConfigDialog::CPicoConfigDialog(TPicoConfig &cfg) : config(cfg) +{ +} + +void CPicoConfigDialog::PostLayoutDynInitL() +{ + CEikHorOptionButtonList *buttons_rot = (CEikHorOptionButtonList*) Control( ECtlOptRotation ); + CEikHorOptionButtonList *buttons_disp = (CEikHorOptionButtonList*) Control( ECtlOptScreenMode ); + CEikCheckBox *chkbox_altrend= (CEikCheckBox*) Control( ECtlOptUseAltRend ); + CEikCheckBox *chkbox_acctmng= (CEikCheckBox*) Control( ECtlOptUseAccTiming ); + CEikCheckBox *chkbox_sram = (CEikCheckBox*) Control( ECtlOptUseSRAM ); + CEikCheckBox *chkbox_fps = (CEikCheckBox*) Control( ECtlOptShowFPS ); + CEikCheckBox *chkbox_sound = (CEikCheckBox*) Control( ECtlOptEnableSound ); + CEikCheckBox *chkbox_z80 = (CEikCheckBox*) Control( ECtlOptEmulateZ80 ); + CEikCheckBox *chkbox_ym2612 = (CEikCheckBox*) Control( ECtlOptEmulateYM2612 ); + CEikCheckBox *chkbox_sn76496= (CEikCheckBox*) Control( ECtlOptEmulateSN76496 ); + CEikChoiceListBase *combo_sndq = (CEikChoiceListBase*) Control( ECtlOptSndQuality ); + CEikCheckBox *chkbox_6bpad = (CEikCheckBox*) Control( ECtlOpt6ButtonPad ); + CEikCheckBox *chkbox_gzipst = (CEikCheckBox*) Control( ECtlOptGzipStates ); + CEikCheckBox *chkbox_accsprt= (CEikCheckBox*) Control( ECtlOptUseAccSprites ); + CEikChoiceListBase *combo_region = (CEikChoiceListBase*) Control( ECtlOptRegion ); + CEikOptionButton *opt_fit2 = (CEikOptionButton*) buttons_disp->ComponentControl( TPicoConfig::PMFit2 ); + + buttons_rot ->SetButtonById(ECtlOptRotation0 + config.iScreenRotation); + buttons_disp->SetButtonById(ECtlOptScreenModeCenter + config.iScreenMode); + chkbox_sram ->SetState(config.iFlags & 1 ? CEikButtonBase::ESet : CEikButtonBase::EClear); + chkbox_fps ->SetState(config.iFlags & 2 ? CEikButtonBase::ESet : CEikButtonBase::EClear); + chkbox_sound ->SetState(config.iFlags & 4 ? CEikButtonBase::ESet : CEikButtonBase::EClear); + chkbox_gzipst ->SetState(config.iFlags & 0x80 ? CEikButtonBase::ESet : CEikButtonBase::EClear); + chkbox_z80 ->SetState(config.iPicoOpt & 4 ? CEikButtonBase::ESet : CEikButtonBase::EClear); + chkbox_ym2612 ->SetState(config.iPicoOpt & 1 ? CEikButtonBase::ESet : CEikButtonBase::EClear); + chkbox_sn76496->SetState(config.iPicoOpt & 2 ? CEikButtonBase::ESet : CEikButtonBase::EClear); + chkbox_altrend->SetState(config.iPicoOpt & 0x10? CEikButtonBase::ESet : CEikButtonBase::EClear); + chkbox_6bpad ->SetState(config.iPicoOpt & 0x20? CEikButtonBase::ESet : CEikButtonBase::EClear); + chkbox_acctmng->SetState(config.iPicoOpt & 0x40? CEikButtonBase::ESet : CEikButtonBase::EClear); + chkbox_accsprt->SetState(config.iPicoOpt & 0x80? CEikButtonBase::ESet : CEikButtonBase::EClear); + + // dim "fit2" if we are not in 0 or 180 mode + if(config.iScreenRotation != TPicoConfig::PRot0 && config.iScreenRotation != TPicoConfig::PRot180) opt_fit2->SetDimmed(ETrue); + // dim some stuff for alternative renderer + if(config.iPicoOpt & 0x10) { + // dim accurate sprites + chkbox_accsprt->SetState(CEikButtonBase::EClear); + chkbox_accsprt->SetDimmed(ETrue); + // dim fit + if(buttons_rot->LabeledButtonId() == ECtlOptRotation0 || buttons_rot->LabeledButtonId() == ECtlOptRotation180) + ((CEikOptionButton*)(buttons_disp->ComponentControl(TPicoConfig::PMFit)))->SetDimmed(ETrue); + } + + TInt sel = (config.iPicoOpt&8) ? 5 : 0; + sel+= (config.iFlags>>3)&7; + if (sel >= 10) sel = 0; + combo_sndq->SetCurrentItem(sel); + switch(config.PicoRegion) { + case 1: sel = 4; break; + case 2: sel = 3; break; + case 4: sel = 2; break; + case 8: sel = 1; break; + default:sel = 0; // auto + } + combo_region->SetCurrentItem(sel); +} + +TBool CPicoConfigDialog::OkToExitL(TInt aButtonId) +{ + if(aButtonId != EEikBidOk) return ETrue; + + CEikHorOptionButtonList *buttons_rot = (CEikHorOptionButtonList*) Control( ECtlOptRotation ); + CEikHorOptionButtonList *buttons_disp = (CEikHorOptionButtonList*) Control( ECtlOptScreenMode ); + CEikCheckBox *chkbox_altrend= (CEikCheckBox*) Control( ECtlOptUseAltRend ); + CEikCheckBox *chkbox_acctmng= (CEikCheckBox*) Control( ECtlOptUseAccTiming ); + CEikCheckBox *chkbox_sram = (CEikCheckBox*) Control( ECtlOptUseSRAM ); + CEikCheckBox *chkbox_fps = (CEikCheckBox*) Control( ECtlOptShowFPS ); + CEikCheckBox *chkbox_sound = (CEikCheckBox*) Control( ECtlOptEnableSound ); + CEikCheckBox *chkbox_z80 = (CEikCheckBox*) Control( ECtlOptEmulateZ80 ); + CEikCheckBox *chkbox_ym2612 = (CEikCheckBox*) Control( ECtlOptEmulateYM2612 ); + CEikCheckBox *chkbox_sn76496= (CEikCheckBox*) Control( ECtlOptEmulateSN76496 ); + CEikChoiceListBase *combo_sndq = (CEikChoiceListBase*) Control( ECtlOptSndQuality ); + CEikCheckBox *chkbox_6bpad = (CEikCheckBox*) Control( ECtlOpt6ButtonPad ); + CEikCheckBox *chkbox_gzipst = (CEikCheckBox*) Control( ECtlOptGzipStates ); + CEikCheckBox *chkbox_accsprt= (CEikCheckBox*) Control( ECtlOptUseAccSprites ); + CEikChoiceListBase *combo_region = (CEikChoiceListBase*) Control( ECtlOptRegion ); + + config.iScreenRotation = (TPicoConfig::TPicoScreenRotation) (buttons_rot->LabeledButtonId() - ECtlOptRotation0); + config.iScreenMode = (TPicoConfig::TPicoScreenMode) (buttons_disp->LabeledButtonId() - ECtlOptScreenModeCenter); + + if(chkbox_sram ->State() == CEikButtonBase::ESet) config.iFlags |= 1; else config.iFlags &= ~1; + if(chkbox_fps ->State() == CEikButtonBase::ESet) config.iFlags |= 2; else config.iFlags &= ~2; + if(chkbox_sound ->State() == CEikButtonBase::ESet) config.iFlags |= 4; else config.iFlags &= ~4; + if(chkbox_gzipst ->State() == CEikButtonBase::ESet) config.iFlags |= 0x80; else config.iFlags &= ~0x80; + if(chkbox_z80 ->State() == CEikButtonBase::ESet) config.iPicoOpt |= 4; else config.iPicoOpt &= ~4; + if(chkbox_ym2612 ->State() == CEikButtonBase::ESet) config.iPicoOpt |= 1; else config.iPicoOpt &= ~1; + if(chkbox_sn76496->State() == CEikButtonBase::ESet) config.iPicoOpt |= 2; else config.iPicoOpt &= ~2; + if(chkbox_altrend->State() == CEikButtonBase::ESet) config.iPicoOpt |= 0x10;else config.iPicoOpt &= ~0x10; + if(chkbox_6bpad ->State() == CEikButtonBase::ESet) config.iPicoOpt |= 0x20;else config.iPicoOpt &= ~0x20; + if(chkbox_acctmng->State() == CEikButtonBase::ESet) config.iPicoOpt |= 0x40;else config.iPicoOpt &= ~0x40; + if(chkbox_accsprt->State() == CEikButtonBase::ESet) config.iPicoOpt |= 0x80;else config.iPicoOpt &= ~0x80; + + TInt sel = combo_sndq->CurrentItem(); + if(sel >= 5) { config.iPicoOpt |= 8; sel-=5; } else config.iPicoOpt &= ~8; + config.iFlags &= ~0x38; + config.iFlags |= (sel<<3)&0x38; + + switch(combo_region->CurrentItem()) { + case 4: config.PicoRegion = 1; break; + case 3: config.PicoRegion = 2; break; + case 2: config.PicoRegion = 4; break; + case 1: config.PicoRegion = 8; break; + default:config.PicoRegion = 0; // auto + } + + return ETrue; +} + +// simple GUI stuff needs lots of code +void CPicoConfigDialog::HandleControlStateChangeL(TInt aControlId) +{ + if(aControlId == ECtlOptEnableSound) { + CEikCheckBox *chkbox_sound = (CEikCheckBox*) Control( ECtlOptEnableSound ); + CEikCheckBox *chkbox_z80 = (CEikCheckBox*) Control( ECtlOptEmulateZ80 ); + CEikCheckBox *chkbox_ym2612 = (CEikCheckBox*) Control( ECtlOptEmulateYM2612 ); + CEikCheckBox *chkbox_sn76496= (CEikCheckBox*) Control( ECtlOptEmulateSN76496 ); + + if(chkbox_sound->State() == CEikButtonBase::ESet) { + // check all sound chips too, but only if they all are not set + if((chkbox_z80->State() | chkbox_ym2612->State() | chkbox_sn76496->State()) == CEikButtonBase::EClear) { // (==0) + chkbox_z80 ->SetState(CEikButtonBase::ESet); + chkbox_ym2612 ->SetState(CEikButtonBase::ESet); + chkbox_sn76496->SetState(CEikButtonBase::ESet); + chkbox_z80 ->DrawDeferred(); + chkbox_ym2612 ->DrawDeferred(); + chkbox_sn76496->DrawDeferred(); + } + } else { + // clear everything, but only if everything is set + if((chkbox_z80->State() & chkbox_ym2612->State() & chkbox_sn76496->State()) == CEikButtonBase::ESet) { // (==1) + chkbox_z80 ->SetState(CEikButtonBase::EClear); + chkbox_ym2612 ->SetState(CEikButtonBase::EClear); + chkbox_sn76496->SetState(CEikButtonBase::EClear); + chkbox_z80 ->DrawDeferred(); + chkbox_ym2612 ->DrawDeferred(); + chkbox_sn76496->DrawDeferred(); + } + } + } else if(aControlId == ECtlOptUseAltRend || aControlId == ECtlOptRotation) { + CEikCheckBox *chkbox_altrend= (CEikCheckBox*) Control( ECtlOptUseAltRend ); + CEikCheckBox *chkbox_accsprt= (CEikCheckBox*) Control( ECtlOptUseAccSprites ); + CEikHorOptionButtonList *buttons_rot = (CEikHorOptionButtonList*) Control( ECtlOptRotation ); + CEikHorOptionButtonList *buttons_disp = (CEikHorOptionButtonList*) Control( ECtlOptScreenMode ); + CEikOptionButton *opt_fit = (CEikOptionButton*) buttons_disp->ComponentControl( TPicoConfig::PMFit ); + CEikOptionButton *opt_fit2 = (CEikOptionButton*) buttons_disp->ComponentControl( TPicoConfig::PMFit2 ); + + TBool dimmed = chkbox_altrend->State() == CEikButtonBase::ESet; + // show/hide more stuff for alternative renderer + chkbox_accsprt->SetDimmed(dimmed); + if(buttons_rot->LabeledButtonId() == ECtlOptRotation0 || buttons_rot->LabeledButtonId() == ECtlOptRotation180) { + opt_fit->SetDimmed(dimmed); + if(dimmed && buttons_disp->LabeledButtonId() == ECtlOptScreenModeFit) + buttons_disp->SetButtonById(ECtlOptScreenModeFit2); + } + else opt_fit->SetDimmed(EFalse); + chkbox_accsprt->DrawDeferred(); + buttons_disp->DrawDeferred(); + + if(buttons_rot->LabeledButtonId() == ECtlOptRotation0 || buttons_rot->LabeledButtonId() == ECtlOptRotation180) { + opt_fit2->SetDimmed(EFalse); + } else { + if(opt_fit2->State() == CEikButtonBase::ESet) { + buttons_disp->SetButtonById(ECtlOptScreenModeFit); + buttons_disp->DrawDeferred(); + } + opt_fit2->SetDimmed(ETrue); + } + opt_fit2->DrawDeferred(); + } +} + + +/************************************************ + * + * About Dialog + * + ************************************************/ + +void CAboutDialog::PostLayoutDynInitL() +{ + TBuf<16> versionText; + TBuf<512> text; + + #if (KPicoBuildNumber != 0) + versionText.Format(_L("%d.%d%d"), KPicoMajorVersionNumber, KPicoMinorVersionNumber, KPicoBuildNumber); + #else + versionText.Format(_L("%d.%d"), KPicoMajorVersionNumber, KPicoMinorVersionNumber); + #endif + + CEikRichTextEditor* richTextEd = LocateControlByUniqueHandle(ECtlPicoAboutText); + User::LeaveIfNull(richTextEd); + + HBufC *aboutFormat = CEikonEnv::Static()->AllocReadResourceLC(R_PICO_TEXT_ABOUT); + CSimpleTextFormatParser *parser = CSimpleTextFormatParser::NewLC(); + + text.Format(*aboutFormat, &versionText); + parser->ParseL(text, *richTextEd->RichText()); + + richTextEd->UpdateAllFieldsL(); // Updates all the fields in the document + + CleanupStack::PopAndDestroy(parser); + CleanupStack::PopAndDestroy(aboutFormat); +} + +/************************************************************* +* +* Credits dialog +* +**************************************************************/ + +void CCreditsDialog::PreLayoutDynInitL() +{ + CEikEdwin *edwin = LocateControlByUniqueHandle(ECtlPicoCreditsText); + User::LeaveIfNull(edwin); + + CDesCArrayFlat* desArray = CEikonEnv::Static()->ReadDesCArrayResourceL(R_PICO_TBUF_CREDITS); + CleanupStack::PushL(desArray); + + edwin->SetTextLimit(2048); // to prevent stupid "too big" warning + TInt count = desArray->Count(); + for (TInt i = 0; i < count; i++) + { + edwin->Text()->InsertL(edwin->TextLength(), desArray->operator[](i)); + edwin->Text()->InsertL(edwin->TextLength(), CEditableText::ELineBreak); + } + CleanupStack::PopAndDestroy(desArray); +} + +TKeyResponse CCreditsDialog::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType) +{ + if (aType == EEventKey) + { + CEikEdwin *edwin = LocateControlByUniqueHandle(ECtlPicoCreditsText); + User::LeaveIfNull(edwin); + + if (aKeyEvent.iCode == EQuartzKeyTwoWayDown) + { + edwin->MoveDisplayL(TCursorPosition::EFLineDown); + edwin->UpdateScrollBarsL(); + return EKeyWasConsumed; + } + else if (aKeyEvent.iCode == EQuartzKeyTwoWayUp) + { + edwin->MoveDisplayL(TCursorPosition::EFLineUp); + edwin->UpdateScrollBarsL(); + return EKeyWasConsumed; + } + } + return CQikSimpleDialog::OfferKeyEventL(aKeyEvent, aType); +} + +/************************************************************* +* +* Debug dialog +* +**************************************************************/ + +CDebugDialog::CDebugDialog(char *t) +{ + Mem::Copy(iText, t, 1024); + iText[1023] = 0; +} + +void CDebugDialog::PreLayoutDynInitL() +{ + char *p = iText, *line = iText; + TBool end=0; + TBuf<128> tbuf; + CEikEdwin *editor = LocateControlByUniqueHandle(ECtlPicoCreditsText); + + while(!end) { + while(*p && *p != '\r' && *p != '\n') p++; + if(!*p) end=1; + *p = 0; + TPtrC8 ptr((TUint8*) line); + tbuf.Copy(ptr); + editor->Text()->InsertL(editor->TextLength(), tbuf); + editor->Text()->InsertL(editor->TextLength(), CEditableText::ELineBreak); + line = ++p; + } +} diff --git a/platform/uiq3/Dialogs.h b/platform/uiq3/Dialogs.h new file mode 100644 index 00000000..7184f944 --- /dev/null +++ b/platform/uiq3/Dialogs.h @@ -0,0 +1,94 @@ +/******************************************************************* + * + * File: Dialogs.h + * + * Author: Peter van Sebille (peter@yipton.net) + * + * Modified/adapted for picodriveN by notaz, 2006 + * + * (c) Copyright 2006, notaz + * (c) Copyright 2002, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +#ifndef __DIALOGS_H +#define __DIALOGS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +/************************************************ + * + * config Dialog + * + ************************************************/ + +class TPicoConfig; + +class CPicoConfigDialog : public CEikDialog +{ +public: + CPicoConfigDialog(TPicoConfig &cfg); + +protected: // framework + void PostLayoutDynInitL(); + void HandleControlStateChangeL(TInt aControlId); + TBool OkToExitL(TInt aButtonId); + + TPicoConfig &config; +}; + + +/************************************************ + * + * About Dialog + * + ************************************************/ + +class CAboutDialog : public CQikSimpleDialog +{ +protected: // from CQikSimpleDialog + void PostLayoutDynInitL(); +}; + +/************************************************************* +* +* Credits dialog +* +**************************************************************/ + +class CCreditsDialog : public CQikSimpleDialog +{ +protected: // from CQikSimpleDialog + void PreLayoutDynInitL(); + TKeyResponse OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType); +}; + +/************************************************************* +* +* Debug dialog +* +**************************************************************/ + +class CDebugDialog : public CCreditsDialog +{ +public: + CDebugDialog(char *t); + +protected: + char iText[1024]; + void PreLayoutDynInitL(); +}; + +#endif // __DIALOGS_H diff --git a/platform/uiq3/Engine.cpp b/platform/uiq3/Engine.cpp new file mode 100644 index 00000000..08b81246 --- /dev/null +++ b/platform/uiq3/Engine.cpp @@ -0,0 +1,484 @@ +/******************************************************************* + * + * File: Engine.cpp + * + * Author: Peter van Sebille (peter@yipton.net) + * + * Modified/adapted for picodriveN by notaz, 2006 + * + * (c) Copyright 2006, notaz + * (c) Copyright 2002, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + + +#include "Engine.h" +#include +#include +#include +#include +#include + +#include + +#include "version.h" +#include "../../pico/picoInt.h" +#include "engine/debug.h" +#include "app.h" + +// this is where we start to break a bunch of symbian rules +extern TInt machineUid; +extern int gamestate, gamestate_next; +extern TPicoConfig *currentConfig; +extern const char *actionNames[]; +RSemaphore pauseSemaphore; +RSemaphore initSemaphore; +const char *RomFileName = 0; +int pico_was_reset = 0; +unsigned char *rom_data = 0; +static CPicolAppView *appView = 0; + + +TInt CPicoGameSession::Do(const TPicoServRqst what, TAny *param) +{ + switch (what) { + case PicoMsgLoadState: + if(!rom_data) return -1; // no ROM + return saveLoadGame(1); + + case PicoMsgSaveState: + if(!rom_data) return -1; + return saveLoadGame(0); + + case PicoMsgLoadROM: + return loadROM((TPtrC16 *)param); + + case PicoMsgResume: + DEBUGPRINT(_L("resume with rom %08x"), rom_data); + if(rom_data) { + return ChangeRunState(PGS_Running); + } + return 1; + + case PicoMsgReset: + if(rom_data) { + PicoReset(0); + pico_was_reset = 1; + return ChangeRunState(PGS_Running); + } + return 1; + + case PicoMsgKeys: + return ChangeRunState(PGS_KeyConfig); + + case PicoMsgPause: + return ChangeRunState(PGS_Paused); + + case PicoMsgQuit: + DEBUGPRINT(_L("got quit msg.")); + return ChangeRunState(PGS_Quit); + + // config change + case PicoMsgConfigChange: + return changeConfig((TPicoConfig *)param); + + case PicoMsgSetAppView: + appView = (CPicolAppView *)param; + return 1; + + default: + return 1; + } +} + +TInt EmuThreadFunction(TAny* anArg); + +TInt CPicoGameSession::StartEmuThread() +{ + TInt res=KErrNone; + iEmuRunning = EFalse; + + if (initSemaphore.Handle() > 0) + initSemaphore.Close(); + initSemaphore.CreateLocal(0); + if (pauseSemaphore.Handle() <= 0) + pauseSemaphore.CreateLocal(0); + + RThread thread; + if(iThreadWatcher && (res = thread.Open(iThreadWatcher->iTid)) == KErrNone) { + // should be a dead thread in some strange state. + DEBUGPRINT(_L("found thread with the same id (id=%i, RequestCount=%i), killing.."), + (TInt32)thread.Id(), thread.RequestCount()); + // what can we do in this situation? Nothing seems to help, it just stays in this state. + delete iThreadWatcher; + iThreadWatcher = 0; + thread.Kill(1); + thread.Terminate(1); + thread.Close(); + } + + //semaphore.CreateLocal(0); // create a semaphore so we know when thread init is finished + res=thread.Create(_L("PicoEmuThread"), // create new server thread + EmuThreadFunction, // thread's main function + KDefaultStackSize, + KMinHeapSize, + KPicoMaxHeapSize, + 0 // &semaphore // passed as TAny* argument to thread function + ); + + if(res == KErrNone) { // thread created ok - now start it going + thread.SetPriority(EPriorityMore); + iEmuRunning = ETrue; + if (iThreadWatcher) delete iThreadWatcher; + iThreadWatcher = CThreadWatcher::NewL(thread.Id()); + thread.Resume(); // start it going + DEBUGPRINT(_L("initSemaphore.Wait()")); + res = initSemaphore.Wait(1000*1000); // wait until it's initialized + DEBUGPRINT(_L("initSemaphore resume, ExitReason() == %i"), thread.ExitReason()); + res |= thread.ExitReason(); + thread.Close(); // we're no longer interested in the other thread + if(res != KErrNone) iEmuRunning = EFalse; + return res; + } + + return res; +} + +TInt CPicoGameSession::ChangeRunState(TPicoGameState newstate, TPicoGameState newstate_next) +{ + if (!iEmuRunning) { + gamestate = PGS_Paused; + TInt res = StartEmuThread(); + if(res != KErrNone) DEBUGPRINT(_L("StartEmuThread() returned %i"), res); + if (!iEmuRunning) return PicoErrEmuThread; + } + + int oldstate = gamestate; + gamestate = newstate; + gamestate_next = newstate_next ? newstate_next : PGS_Paused; + if (oldstate == PGS_Paused) pauseSemaphore.Signal(); + return 0; +} + + +TInt CPicoGameSession::loadROM(TPtrC16 *pptr) +{ + TInt res, i; + char buff[0x31]; + + if(rom_data) { + // save SRAM for previous ROM + if(currentConfig->iFlags & 1) + saveLoadGame(0, 1); + } + + RomFileName = 0; + if(rom_data) { + free(rom_data); + rom_data = 0; + } + + // read the contents of the client pointer into a TPtr. + static TBuf8 writeBuf; + writeBuf.Copy(*pptr); + + // detect wrong extensions (.srm and .mds) + TBuf8<5> ext; + ext.Copy(writeBuf.Right(4)); + ext.LowerCase(); + if(!strcmp((char *)ext.PtrZ(), ".srm") || !strcmp((char *)ext.PtrZ(), "s.gz") || // .mds.gz + !strcmp((char *)ext.PtrZ(), ".mds")) { + return PicoErrNotRom; + } + + FILE *rom = fopen((char *) writeBuf.PtrZ(), "rb"); + if(!rom) { + DEBUGPRINT(_L("failed to open rom.")); + return PicoErrRomOpenFailed; + } + + // make sure emu thread is ok + res = ChangeRunState(PGS_Paused); + if(res) { + fclose(rom); + return res; + } + + unsigned int rom_size = 0; + // zipfile support + if(!strcmp((char *)ext.PtrZ(), ".zip")) { + fclose(rom); + res = CartLoadZip((const char *) writeBuf.PtrZ(), &rom_data, &rom_size); + if(res) { + DEBUGPRINT(_L("CartLoadZip() failed (%i)"), res); + return res; + } + } else { + if( (res = PicoCartLoad(rom, &rom_data, &rom_size)) ) { + DEBUGPRINT(_L("PicoCartLoad() failed (%i)"), res); + fclose(rom); + return PicoErrOutOfMem; + } + fclose(rom); + } + + // detect wrong files (Pico crashes on very small files), also see if ROM EP is good + if(rom_size <= 0x200 || strncmp((char *)rom_data, "Pico", 4) == 0 || + ((*(TUint16 *)(rom_data+4)<<16)|(*(TUint16 *)(rom_data+6))) >= (int)rom_size) { + free(rom_data); + rom_data = 0; + return PicoErrNotRom; + } + + DEBUGPRINT(_L("PicoCartInsert(0x%08X, %d);"), rom_data, rom_size); + if(PicoCartInsert(rom_data, rom_size)) { + return PicoErrOutOfMem; + } + + pico_was_reset = 1; + + // global ROM file name for later use + RomFileName = (const char *) writeBuf.PtrZ(); + + // name from the ROM itself + for(i = 0; i < 0x30; i++) + buff[i] = rom_data[0x150 + (i^1)]; // unbyteswap + for(buff[i] = 0, i--; i >= 0; i--) { + if(buff[i] != ' ') break; + buff[i] = 0; + } + TPtrC8 buff8((TUint8*) buff); + iRomInternalName.Copy(buff8); + + // load SRAM for this ROM + if(currentConfig->iFlags & 1) + saveLoadGame(1, 1); + + // debug + #ifdef __DEBUG_PRINT + TInt cells = User::CountAllocCells(); + TInt mem; + User::AllocSize(mem); + DEBUGPRINT(_L("comm: cels=%d, size=%d KB"), cells, mem/1024); + ChangeRunState(PGS_DebugHeap, PGS_Running); + #else + ChangeRunState(PGS_Running); + #endif + + return 0; +} + + +TInt CPicoGameSession::changeConfig(TPicoConfig *aConfig) +{ + DEBUGPRINT(_L("got new config.")); + + currentConfig = aConfig; + + // set PicoOpt and rate + PicoRegionOverride = currentConfig->PicoRegion; + PicoOpt = currentConfig->iPicoOpt; + switch((currentConfig->iFlags>>3)&7) { + case 1: PsndRate=11025; break; + case 2: PsndRate=16000; break; + case 3: PsndRate=22050; break; + case 4: PsndRate=44100; break; + default: PsndRate= 8000; break; + } + + // 6 button pad, enable XYZM config if needed + if(PicoOpt & 0x20) { + actionNames[8] = "Z"; + actionNames[9] = "Y"; + actionNames[10] = "X"; + actionNames[11] = "MODE"; + } else { + actionNames[8] = actionNames[9] = actionNames[10] = actionNames[11] = 0; + } + + // if we are in center 90||270 modes, we can bind renderer switcher + if(currentConfig->iScreenMode == TPicoConfig::PMFit && + (currentConfig->iScreenRotation == TPicoConfig::PRot0 || currentConfig->iScreenRotation == TPicoConfig::PRot180)) + actionNames[25] = 0; + else actionNames[25] = "RENDERER"; + + return 0; +} + + +void MainOldCleanup(); // from main.cpp +#ifdef __DEBUG_PRINT_FILE +extern RMutex logMutex; +#endif + +void CPicoGameSession::freeResources() +{ + RThread thread; + TInt i; + + DEBUGPRINT(_L("CPicoGameSession::freeResources()")); + + if(iThreadWatcher && thread.Open(iThreadWatcher->iTid) == KErrNone) + { + // try to stop our emu thread + gamestate = PGS_Quit; + if(pauseSemaphore.Handle() > 0) + pauseSemaphore.Signal(); + + if(thread.Handle() > 0) + { + // tried reopening thread handle here over time intervals to detect if thread is alive, + // but would run into handle panics. + + for(i = 0; i < 8; i++) { + User::After(100 * 1000); + if(thread.ExitReason() != 0) break; + } + + if(thread.ExitReason() == 0) { + // too late, time to die + DEBUGPRINT(_L("thread %i not responding, killing.."), (TInt32) thread.Id()); + thread.Terminate(1); + } + thread.Close(); + } + + } + + if(iThreadWatcher != NULL) + { + DEBUGPRINT(_L("delete iThreadWatcher")); + delete iThreadWatcher; + DEBUGPRINT(_L("after delete iThreadWatcher")); + iThreadWatcher = NULL; + } + + MainOldCleanup(); + + if (initSemaphore.Handle() > 0) + initSemaphore.Close(); + if (pauseSemaphore.Handle() > 0) + pauseSemaphore.Close(); +#ifdef __DEBUG_PRINT_FILE + if (logMutex.Handle() > 0) + logMutex.Close(); +#endif +} + +TBool CPicoGameSession::iEmuRunning = EFalse; +CThreadWatcher *CPicoGameSession::iThreadWatcher = 0; +TBuf<0x30> CPicoGameSession::iRomInternalName; + + +void TPicoConfig::SetDefaults() +{ + iLastROMFile.SetLength(0); + iScreenRotation = PRot270; + iScreenMode = PMCenter; + iFlags = 1; // use_sram + iPicoOpt = 0; // all off + iFrameskip = PFSkipAuto; + + Mem::FillZ(iKeyBinds, sizeof(iKeyBinds)); + Mem::FillZ(iAreaBinds, sizeof(iAreaBinds)); + iKeyBinds[0xd5] = 1<<26; // bind back +} + +// load config +void TPicoConfig::InternalizeL(RReadStream &aStream) +{ + TInt32 version, fname_len; + version = aStream.ReadInt32L(); + fname_len = aStream.ReadInt32L(); + + // not sure if this is safe + iLastROMFile.SetMax(); + aStream.ReadL((TUint8 *) iLastROMFile.Ptr(), KMaxFileName*2); + iLastROMFile.SetLength(fname_len); + + iScreenRotation = aStream.ReadInt32L(); + iScreenMode = aStream.ReadInt32L(); + iFlags = aStream.ReadUint32L(); + iPicoOpt = aStream.ReadInt32L(); + iFrameskip = aStream.ReadInt32L(); + + aStream.ReadL((TUint8 *)iKeyBinds, sizeof(iKeyBinds)); + aStream.ReadL((TUint8 *)iAreaBinds, sizeof(iAreaBinds)); + + PicoRegion = aStream.ReadInt32L(); +} + +// save config +void TPicoConfig::ExternalizeL(RWriteStream &aStream) const +{ + TInt version = (KPicoMajorVersionNumber<<24)+(KPicoMinorVersionNumber<<16); + + aStream.WriteInt32L(version); + aStream.WriteInt32L(iLastROMFile.Length()); + aStream.WriteL((const TUint8 *)iLastROMFile.Ptr(), KMaxFileName*2); + + aStream.WriteInt32L(iScreenRotation); + aStream.WriteInt32L(iScreenMode); + aStream.WriteUint32L(iFlags); + aStream.WriteInt32L(iPicoOpt); + aStream.WriteInt32L(iFrameskip); + + aStream.WriteL((const TUint8 *)iKeyBinds, sizeof(iKeyBinds)); + aStream.WriteL((const TUint8 *)iAreaBinds, sizeof(iAreaBinds)); + + aStream.WriteInt32L(PicoRegion); +} + + +// CThreadWatcher +CThreadWatcher::~CThreadWatcher() +{ + Cancel(); + DEBUGPRINT(_L("after CThreadWatcher::Cancel();")); +} + +CThreadWatcher::CThreadWatcher(const TThreadId& aTid) +: CActive(CActive::EPriorityStandard), iTid(aTid) +{ +} + + +CThreadWatcher* CThreadWatcher::NewL(const TThreadId& aTid) +{ + CThreadWatcher* self = new(ELeave) CThreadWatcher(aTid); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); // self + return self; +} + +void CThreadWatcher::ConstructL() +{ + CActiveScheduler::Add(this); + RThread thread; + if(thread.Open(iTid) == KErrNone) { + thread.Logon(iStatus); + thread.Close(); + SetActive(); + } +} + +void CThreadWatcher::RunL() +{ + DEBUGPRINT(_L("CThreadWatcher::RunL()")); + CPicoGameSession::iEmuRunning = EFalse; + if(appView) appView->UpdateCommandList(); + //initSemaphore.Signal(); // no point to do that here, AS can't get here if it is waiting +} + +void CThreadWatcher::DoCancel() +{ + RThread thread; + DEBUGPRINT(_L("CThreadWatcher::DoCancel()")); + if(thread.Open(iTid) == KErrNone) { + DEBUGPRINT(_L("thread.LogonCancel(iStatus);")); + thread.LogonCancel(iStatus); + thread.Close(); + } +} diff --git a/platform/uiq3/Engine.h b/platform/uiq3/Engine.h new file mode 100644 index 00000000..19bd84ea --- /dev/null +++ b/platform/uiq3/Engine.h @@ -0,0 +1,159 @@ +/******************************************************************* + * + * File: Engine.h + * + * Author: Peter van Sebille (peter@yipton.net) + * + * Modified/adapted for picodriveN by notaz, 2006 + * + * (c) Copyright 2006, notaz + * (c) Copyright 2002, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +#ifndef __ENGINE_H +#define __ENGINE_H + +#include + +class RReadStream; +class RWriteStream; + + +// engine states +enum TPicoGameState { + PGS_Running = 1, + PGS_Paused, + PGS_Quit, + PGS_KeyConfig, + PGS_DebugHeap, +}; + +enum TPicoServRqst { + PicoMsgLoadState, + PicoMsgSaveState, + PicoMsgLoadROM, + PicoMsgResume, + PicoMsgReset, + PicoMsgKeys, + PicoMsgPause, + PicoMsgQuit, + PicoMsgConfigChange, + PicoMsgSetAppView, + kDefaultMessageSlots // this is how many messages we need :) +}; + +enum TPicoGenErrors { // generic errors + PicoErrNoErr = 0, // OK + PicoErrRomOpenFailed, + PicoErrOutOfMem, + PicoErrNotRom, + PicoErrNoRomsInArchive, + PicoErrUncomp, // 5 + PicoErrOutOfMemSnd, + PicoErrGenSnd, // 7 generic sound system error + PicoErrEmuThread +}; + + +// needed for creating server thread. +const TUint KPicoMaxHeapSize=0x00800000; + +// key config entry (touchpad areas) +struct TPicoAreaConfigEntry { + TRect rect; + //unsigned long actions; +}; + +struct TPicoKeyConfigEntry +{ + unsigned short keyCode; + unsigned char scanCode; + unsigned char flags; // lsb->msb: key_down, pulse_only, ?, ?, ?, ?, not_configurable, disabled + TInt32 handle1; // for CancelCaptureKeyUpAndDowns() + TInt32 handle2; // for CancelCaptureKey() + char *name; +}; + + +// configuration data +class TPicoConfig +{ +public: + void SetDefaults(); + void InternalizeL(RReadStream &aStream); + void ExternalizeL(RWriteStream &aStream) const; + + enum TPicoScreenRotation { + PRot0, + PRot90, + PRot180, + PRot270 + }; + enum TPicoScreenMode { + PMCenter, + PMFit, + PMFit2 + }; + enum TPicoFrameSkip { + PFSkipAuto = -1, + PFSkip0 + }; + +public: + TFileName iLastROMFile; + + TInt32 iScreenRotation; + TInt32 iScreenMode; + TUint32 iFlags; // LSb->MSb: use_sram, show_fps, enable_sound, sound_rate(3bits), gzip_saves{=0x40}, dont_use_mot_vol + // enable_ym2612&dac, enable_sn76496, enable_z80, stereo_sound; + // alt_renderer, 6button_gamepad, accurate_timing + TInt32 iPicoOpt; + TInt32 iFrameskip; + TUint32 iKeyBinds[256]; // a binding for every keycode + TUint32 iAreaBinds[19]; + TInt32 PicoRegion; +}; + + +class CThreadWatcher : public CActive +{ +public: + static CThreadWatcher* NewL(const TThreadId& aTid); + ~CThreadWatcher(); + + TThreadId iTid; // thread id + +protected: + CThreadWatcher(const TThreadId& aTid); + void ConstructL(); + + virtual void RunL(); + virtual void DoCancel(); +}; + + +class CPicoGameSession +{ +public: + static TInt Do(const TPicoServRqst what, TAny *param=0); + static void freeResources(); + + static TBool iEmuRunning; + static TBuf<0x30> iRomInternalName; + +private: + // services available + static TInt StartEmuThread(); + static TInt ChangeRunState(TPicoGameState newstate, TPicoGameState newstate_next=(TPicoGameState)0); + static TInt loadROM(TPtrC16 *pptr); + static TInt changeConfig(TPicoConfig *aConfig); + + static CThreadWatcher *iThreadWatcher; +}; + +// global +int saveLoadGame(int load, int sram=0); + +#endif diff --git a/platform/uiq3/Makefile b/platform/uiq3/Makefile new file mode 100644 index 00000000..fa14569a --- /dev/null +++ b/platform/uiq3/Makefile @@ -0,0 +1,307 @@ +# makefile for GCCE + +# settings +#dprint = 1 +asm_memory = 1 +asm_render = 1 +asm_blit = 1 +#use_musashi = 1 +#up = 1 +#sis = 1 + +# targets +all: $(EPOCROOT2)epoc32 MAKEDIRS RESOURCES PicoDrive.exe + +clean : + @perl -S ermdir.pl _build + @erase 2>>nul rsc\*.rsc + @erase 2>>nul rsc\*.rsg + @erase 2>>nul rsc\PicoDrive.mb? + + +# paths +$(EPOCROOT2)epoc32 : + @echo Please set EPOCROOT2 environmental variable to full path to your SDK + @echo with ending slash (something like C:\Uiq_21\) + @cd : 2> NUL # do something stupid to make it silently fail + +# resource compiler hates drive lettered paths +EPOCROOT2_NODRV = $(filter \\%,$(subst :, ,$(EPOCROOT2))) +EPOCLIB = $(EPOCROOT2)EPOC32\RELEASE\ARMV5 + +# C/C++ Compiler +CC=arm-none-symbianelf-gcc + +# Linker +LD=arm-none-symbianelf-ld + +# Assembler +ASM=arm-none-symbianelf-as + +# Archiver +AR=arm-none-symbianelf-ar + +# Strip +STRIP=arm-none-symbianelf-strip + +# gcc config +GCCDEFINES = -DNDEBUG -D_UNICODE -D__GCCE__ -D__SYMBIAN32__ -D__EPOC32__ -D__MARM__ \ + -D__EABI__ -D__MARM_ARMV5__ -D__EXE__ -D__SUPPORT_CPP_EXCEPTIONS__ \ + -D__MARM_ARMV5__ -D__PRODUCT_INCLUDE__=\"$(EPOCROOT2)epoc32/include/variant/UIQ_3.0.hrh\" + +GCCDEFINES += -D_UNZIP_SUPPORT -D__BROKEN_FWRITE + +# 'CSL Arm Toolchain' stuff must be specified after Symbian includes +GCCINCLUDES = -I "$(EPOCROOT2)epoc32\include\variant" -I "$(EPOCROOT2)EPOC32\INCLUDE" -I "$(EPOCROOT2)EPOC32\INCLUDE\LIBC" \ + -I "$(EPOCROOT2)\CSL Arm Toolchain\lib\gcc\arm-none-symbianelf\3.4.3\include" -I. + +# -funit-at-a-time is not compatible with SDK, it either has linker problems or does not start on device +GCCCOMMFLAGS = -Wall -Wno-unknown-pragmas -fexceptions -march=armv5t -mapcs -pipe -nostdinc -msoft-float \ + $(GCCINCLUDES) -include "$(EPOCROOT2)EPOC32/INCLUDE/GCCE/GCCE.h" -marm + +GCCCPPFLAGS = -x c++ -Wno-ctor-dtor-privacy -O3 -fno-unit-at-a-time +GCCCFLAGS = -x c -O3 -fno-unit-at-a-time + +GCCLDFLAGS = -L"$(EPOCROOT2)CSL Arm Toolchain\arm-none-symbianelf\lib" \ + -L"$(EPOCROOT2)CSL Arm Toolchain\lib\gcc\arm-none-symbianelf\3.4.3" \ + --target1-abs --no-undefined -nostdlib -shared -Ttext 0x8000 -Tdata 0x400000 --default-symver + +# libs +LIBS = \ + $(EPOCLIB)\LIB\ESTLIB.dso \ + $(EPOCLIB)\urel\qikalloc.lib \ + $(EPOCLIB)\LIB\euser.dso \ + $(EPOCLIB)\LIB\apparc.dso \ + $(EPOCLIB)\LIB\cone.dso \ + $(EPOCLIB)\LIB\eikcore.dso \ + $(EPOCLIB)\LIB\eikcoctl.dso \ + $(EPOCLIB)\LIB\qikcore.dso \ + $(EPOCLIB)\LIB\qikdlg.dso \ + $(EPOCLIB)\LIB\etext.dso \ + $(EPOCLIB)\LIB\bafl.dso \ + $(EPOCLIB)\LIB\efsrv.dso \ + $(EPOCLIB)\LIB\eikctl.dso \ + $(EPOCLIB)\LIB\WS32.dso \ + $(EPOCLIB)\LIB\EIKDLG.dso \ + $(EPOCLIB)\LIB\GDI.dso \ + $(EPOCLIB)\LIB\estor.dso \ + $(EPOCLIB)\LIB\EZLIB.dso \ + $(EPOCLIB)\LIB\HAL.dso \ + $(EPOCLIB)\LIB\mediaclient.dso \ + $(EPOCLIB)\LIB\mediaclientaudiostream.dso + +LIBS += \ + $(EPOCLIB)\LIB\qikallocdll.dso \ + $(EPOCLIB)\UREL\usrt2_2.lib \ + $(EPOCLIB)\LIB\dfpaeabi.dso \ + $(EPOCLIB)\LIB\dfprvct2_2.dso \ + $(EPOCLIB)\LIB\drtaeabi.dso \ + $(EPOCLIB)\LIB\scppnwdl.dso \ + $(EPOCLIB)\LIB\drtrvct2_2.dso + + +# objects + +# launcher +OBJECTS += _build\App.o _build\Engine.o _build\Dialogs.o _build\CSimpleTextParser.o +# engine +OBJECTS += _build\main.o _build\vid.o _build\polledas.o _build\audio_mediaserver.o _build\debug.o + +# Pico +OBJECTS += _build\Area.o _build\Cart.o _build\Utils.o _build\Memory.o _build\Misc.o \ + _build\Pico.o _build\Sek.o _build\VideoPort.o _build\Draw2.o _build\Draw.o +# asm stuff +ifeq "$(asm_render)" "1" +GCCDEFINES += -D_ASM_DRAW_C +OBJECTS += _build\draw_asm.o _build\draw2_asm.o +endif +ifeq "$(asm_memory)" "1" +GCCDEFINES += -D_ASM_MEMORY_C +OBJECTS += _build\memory_asm.o +endif +# Pico - sound +OBJECTS += _build\sound.o _build\sn76496.o _build\ym2612.o +# misc +OBJECTS += _build\unzip.o _build\gzio_symb.o +# CPU cores +ifeq "$(use_musashi)" "1" +GCCDEFINES += -DEMU_M68K +OBJECTS += _build\m68kcpu.o _build\m68kopac.o _build\m68kopdm.o _build\m68kopnz.o _build\m68kops.o +else +GCCDEFINES += -DEMU_C68K +OBJECTS += _build\Cyclone.o +endif +ifeq "$(asm_blit)" "1" +OBJECTS += _build\blit_asm.o +else +OBJECTS += _build\blit.o +endif +GCCDEFINES += -D_USE_DRZ80 +OBJECTS += _build\DrZ80.o +GCCDEFINES += -D_ASM_YM2612_C +OBJECTS += _build\ym2612_asm.o + + + +# dprint +ifeq "$(dprint)" "1" +GCCDEFINES += -D__DEBUG_PRINT +endif + + +define crule + @echo * $< + @$(CC) -c $(GCCCOMMFLAGS) $(GCCDEFINES) $(GCCCFLAGS) $< -o $@ +endef + +define cpprule + @echo * $< + @$(CC) -c $(GCCCOMMFLAGS) $(GCCDEFINES) $(GCCCPPFLAGS) $< -o $@ +endef + +define asmrule + @echo * $< + @$(ASM) -marmv4t -mthumb-interwork -o $@ $^ +endef + +# object making rules +_build\App.o : App.cpp + $(cpprule) +_build\Engine.o : Engine.cpp + $(cpprule) +_build\Dialogs.o : Dialogs.cpp + $(cpprule) +_build\CSimpleTextParser.o : CSimpleTextParser.cpp + $(cpprule) + +_build\main.o : engine\main.cpp + $(cpprule) +_build\vid.o : engine\vid.cpp + $(cpprule) +_build\polledas.o: engine\polledas.cpp + $(cpprule) +_build\audio_mediaserver.o : engine\audio_mediaserver.cpp + $(cpprule) +_build\debug.o : engine\debug.cpp + $(cpprule) +_build\blit.o : engine\blit.c + $(crule) + +_build\Area.o : ..\..\Pico\Area.c + $(crule) +_build\Cart.o : ..\..\Pico\Cart.c + $(crule) +_build\Draw.o : ..\..\Pico\Draw.c + $(crule) +_build\Draw2.o : ..\..\Pico\Draw2.c + $(crule) +_build\Memory.o : ..\..\Pico\Memory.c + $(crule) +_build\Misc.o : ..\..\Pico\Misc.c + $(crule) +_build\Pico.o : ..\..\Pico\Pico.c + $(crule) +_build\Sek.o : ..\..\Pico\Sek.c + $(crule) +_build\Utils.o : ..\..\Pico\Utils.c + $(crule) +_build\VideoPort.o : ..\..\Pico\VideoPort.c + $(crule) +_build\sound.o : ..\..\Pico\sound\sound.c + $(crule) +_build\sn76496.o : ..\..\Pico\sound\sn76496.c + $(crule) +_build\ym2612.o : ..\..\Pico\sound\ym2612.c + $(crule) + +_build\unzip.o : ..\..\unzip\unzip.c + $(crule) +_build\gzio_symb.o : ..\..\zlib\gzio_symb.c + $(crule) + +_build\m68kcpu.o : ..\..\musashi\m68kcpu.c + $(crule) +_build\m68kopac.o : ..\..\musashi\m68kopac.c + $(crule) +_build\m68kopdm.o : ..\..\musashi\m68kopdm.c + $(crule) +_build\m68kopnz.o : ..\..\musashi\m68kopnz.c + $(crule) +_build\m68kops.o : ..\..\musashi\m68kops.c + $(crule) + +_build\Cyclone.o : ..\..\cpu\Cyclone\proj\Cyclone.s + $(asmrule) +_build\DrZ80.o : ..\..\cpu\DrZ80\drz80.s + $(asmrule) +_build\draw_asm.o : ..\..\Pico\draw.s + $(asmrule) +_build\draw2_asm.o : ..\..\Pico\draw2.s + $(asmrule) +_build\memory_asm.o : ..\..\Pico\memory.s + $(asmrule) +_build\ym2612_asm.o : ..\..\Pico\sound\ym2612.s + $(asmrule) +_build\blit_asm.o : engine\blit.s + $(asmrule) + + +PicoDrive.exe : $(OBJECTS) + @echo * ld + @$(LD) $(GCCLDFLAGS) -soname PicoDrive{000a0000}[a00010f3].exe --entry _E32Startup -u _E32Startup \ + $(EPOCROOT2)EPOC32\RELEASE\ARMV5\UREL\EEXE.LIB -o "_build\PicoDrive_elf.exe" -Map "_build\PicoDrive.exe.map" $(OBJECTS) $(LIBS) -lsupc++ -lgcc +# @echo * strip +# @$(STRIP) _build\PicoDrive_elf.exe + @echo * elf2e32 + @elf2e32 --sid=0xa00010f3 --heap=0x00000100,0x00800000 --stack=0x00003000 \ + --uid1=0x1000007a --uid2=0x100039ce --uid3=0xa00010f3 \ + --capability=none --fpu=softvfp --targettype=EXE --output="$@" \ + --elfinput="_build\PicoDrive_elf.exe" --linkas=PicoDrive{000a0000}[a00010f3].exe --libpath="$(EPOCLIB)\LIB" +ifeq "$(sis)" "1" + @make -C _out +ifeq "$(up)" "1" + @qup.cmd +endif +endif + + +MAKEDIRS : _build + +_build : +# @echo * making build dir + @perl -S emkdir.pl $@ + + +# BitMap PicoDrive.mbm + +RESOURCES : rsc\PicoDrive.mbm rsc\PicoDrive.RSC rsc\PicoDrive_reg.RSC rsc\PicoDrive_loc.RSC rsc\PicoDrive.mbg + +rsc\PicoDrive.mbg : rsc\PicoDrive.mbm + +rsc\PicoDrive.mbm : rsc\pico18x18.bmp rsc\pico18x18m.bmp rsc\pico40x40.bmp rsc\pico40x40m.bmp rsc\pico64x64.bmp rsc\pico64x64m.bmp + @echo * $@ + @perl -S epocmbm.pl -h"rsc\PicoDrive.mbg" -o"rsc\PicoDrive.mbm" -l"\Z\Resource\Apps\:rsc" \ + -b"/c24rsc\pico18x18.bmp /8rsc\pico18x18m.bmp /c24rsc\pico40x40.bmp /8rsc\pico40x40m.bmp /c24rsc\pico64x64.bmp /8rsc\pico64x64m.bmp" -l"\Z\Resource\Apps\:rsc" + @perl -S ecopyfile.pl "rsc\PicoDrive.mbg" "$(EPOCROOT2)EPOC32\INCLUDE\PicoDrive.mbg" + +# Resource Z\Resource\Apps\PicoDrive.RSC + +rsc\PicoDrive.RSC : rsc\PicoDrive.rss picodrive.hrh + @echo * $@ + @perl -S epocrc.pl -m045,046,047 -I "." -I- -I "$(EPOCROOT2_NODRV)EPOC32\include" -DLANGUAGE_SC -u "rsc\PicoDrive.rss" -o$@ \ + -h"rsc\PicoDrive.rsg" -t"rsc" -l"Z\Resource\Apps:rsc" + @perl -S ecopyfile.pl "rsc\PicoDrive.rsg" "$(EPOCROOT2)EPOC32\INCLUDE\PicoDrive.RSG" + +# Resource Z\private\10003a3f\apps\PicoDrive_reg.RSC + +rsc\PicoDrive_reg.RSC : rsc\PicoDrive_reg.rss + @echo * $@ + @perl -S epocrc.pl -m045,046,047 -I "." -I- -I "$(EPOCROOT2)EPOC32\include" -DLANGUAGE_SC -u "rsc\PicoDrive_reg.rss" -o$@ \ + -t"rsc" -l"Z\private\10003a3f\apps:rsc" + +# Resource Z\Resource\Apps\PicoDrive_loc.RSC + +rsc\PicoDrive_loc.RSC : rsc\PicoDrive_loc.rss + @echo * $@ + @perl -S epocrc.pl -m045,046,047 -I "." -I- -I "$(EPOCROOT2)EPOC32\include" -DLANGUAGE_SC -u "rsc\PicoDrive_loc.rss" -o$@ \ + -t"rsc" -l"Z\Resource\Apps:rsc" diff --git a/platform/uiq3/PicoDrive.hrh b/platform/uiq3/PicoDrive.hrh new file mode 100644 index 00000000..910fde8f --- /dev/null +++ b/platform/uiq3/PicoDrive.hrh @@ -0,0 +1,78 @@ + +enum TAppMenuCommands +{ + // Emu menu + EEikCmdPicoMain = 10000, + EEikCmdPicoResume, + EEikCmdPicoLoadState, + EEikCmdPicoSaveState, + EEikCmdPicoLoadROM, + EEikCmdPicoReset, + EEikCmdPicoConfig, + EEikCmdPicoKeys, + EEikCmdPicoSettings, + + // Frameskip submenu + EEikCmdPicoFrameskip, + EEikCmdPicoFrameskipAuto, + EEikCmdPicoFrameskip0, + EEikCmdPicoFrameskip1, + EEikCmdPicoFrameskip2, + EEikCmdPicoFrameskip4, + EEikCmdPicoFrameskip8, + + // Debug menu + EEikCmdPicoDebug, +// EEikCmdPicoDebugKillEmu, + EEikCmdPicoDebugInfo, + + // config Dialog + ECtlOptDone, + // pages + ECtlOptPageMain, + ECtlOptPageSound, + ECtlOptPageMisc, + // main page + ECtlOptRotationLabel, + ECtlOptRotation, + ECtlOptRotation0, + ECtlOptRotation90, + ECtlOptRotation180, + ECtlOptRotation270, + ECtlOptScreenModeLabel, + ECtlOptScreenMode, + ECtlOptScreenModeCenter, + ECtlOptScreenModeFit, + ECtlOptScreenModeFit2, + ECtlOptUseAltRend, + ECtlOptUseAccTiming, + ECtlOptUseAccSprites, + ECtlOptShowFPS, + // sound page + ECtlOptEnableSound, + ECtlOptChipSelLabel, + ECtlOptEmulateZ80, + ECtlOptEmulateYM2612, + ECtlOptEmulateSN76496, + ECtlOptSndQLabel, + ECtlOptSndQuality, + // misc page + ECtlOpt6ButtonPad, + ECtlOptGzipStates, + ECtlOptUseSRAM, + ECtlOptMotDontUseVol, + ECtlOptRegion, + // about dialog + EEikCmdPicoAboutDoneCmd, + EEikCmdPicoAboutCreditsCmd, + ECtlPicoAboutText, + // credits + ECtlPicoCreditsText, + // debug + ECtlDebugEdit +}; + + +#define ECtlAboutVersion 1 +#define ECtlAboutLinks 2 + diff --git a/platform/uiq3/PicoDrive.mmp b/platform/uiq3/PicoDrive.mmp new file mode 100644 index 00000000..01565267 --- /dev/null +++ b/platform/uiq3/PicoDrive.mmp @@ -0,0 +1,140 @@ +TARGET PicoDrive.exe +TARGETTYPE exe +//TARGETPATH ? +UID 0x100039CE 0xA00010F3 +EPOCSTACKSIZE 0x3000 // required by CQikSelectFileDlg +EPOCHEAPSIZE 0x100 0x00800000 // required by large ROMs :) + +// resource +SOURCEPATH Rsc +START RESOURCE PicoDrive.rss +HEADER +TARGETPATH \Resource\Apps +LANG SC +END + +START RESOURCE PicoDrive_reg.rss +TARGETPATH \private\10003a3f\apps +END + +START RESOURCE PicoDrive_loc.rss +TARGETPATH \Resource\Apps +LANG SC +END + +CAPABILITY none // SwEvent // forbidden + +USERINCLUDE ..\.. + +SYSTEMINCLUDE \epoc32\include +SYSTEMINCLUDE \epoc32\include\libc + +// launcher +SOURCEPATH . +SYSTEMINCLUDE . // for port_config.h +SOURCE App.cpp +SOURCE Engine.cpp +SOURCE Dialogs.cpp +SOURCE CSimpleTextParser.cpp + +// engine +SOURCEPATH engine +SOURCE main.cpp +SOURCE vid.cpp +SOURCE polledas.cpp +SOURCE debug.cpp +SOURCE audio_mediaserver.cpp +SOURCE blit.c + +// pico +MACRO _UNZIP_SUPPORT +SOURCEPATH ..\..\Pico +USERINCLUDE ..\..\Pico +SOURCE Area.c +SOURCE Cart.c +SOURCE Draw.c +SOURCE Draw2.c +SOURCE Memory.c +SOURCE Misc.c +SOURCE Pico.c +SOURCE Sek.c +SOURCE Utils.c +SOURCE VideoPort.c + +// pico - sound +SOURCEPATH ..\..\Pico\Sound +SOURCE sound.c +SOURCE sn76496.c +SOURCE ym2612.c + +// CPU cores +MACRO EMU_M68K +SOURCEPATH ..\..\cpu\Musashi +USERINCLUDE ..\..\cpu\Musashi +SOURCE m68kcpu.c +SOURCE m68kopac.c +SOURCE m68kopdm.c +SOURCE m68kopnz.c +SOURCE m68kops.c + +//MACRO _USE_MZ80 +//SOURCEPATH ..\win32\z80 +//SOURCE mz80_asm.obj + +// misc +SOURCEPATH ..\..\unzip +USERINCLUDE ..\..\unzip +SOURCE unzip.c +SOURCEPATH ..\..\zlib +USERINCLUDE ..\..\zlib +SOURCE gzio_symb.c + + +// TODO: get rid of unneeded stuff +LIBRARY ESTLIB.LIB +LIBRARY euser.lib +LIBRARY apparc.lib +LIBRARY cone.lib +LIBRARY eikcore.lib +LIBRARY eikcoctl.lib +LIBRARY qikcore.lib +LIBRARY qikdlg.lib // CQikSelectFileDlg +LIBRARY etext.lib // TCharFormat +LIBRARY bafl.lib // CDesCArrayFlat +LIBRARY efsrv.lib +LIBRARY eikctl.lib + +LIBRARY WS32.LIB +LIBRARY EIKDLG.LIB +//LIBRARY EGUL.LIB // CColorList +LIBRARY GDI.LIB // TTypeface +LIBRARY estor.lib // RWriteStream + +LIBRARY EZLIB.LIB +LIBRARY HAL.LIB + +LIBRARY mediaclient.LIB +LIBRARY mediaclientaudiostream.LIB + + + +STATICLIBRARY qikalloc.lib +LIBRARY qikallocdll.lib + + +MACRO __DEBUG_PRINT +MACRO __BROKEN_FWRITE + + +USERINCLUDE . +START BITMAP PicoDrive.mbm +HEADER +TARGETPATH \Resource\Apps +SOURCEPATH Rsc +SOURCE c24 Pico18x18.bmp +SOURCE 8 Pico18x18m.bmp +SOURCE c24 Pico40x40.bmp +SOURCE 8 Pico40x40m.bmp +SOURCE c24 Pico64x64.bmp +SOURCE 8 Pico64x64m.bmp +END diff --git a/platform/uiq3/_out/Makefile b/platform/uiq3/_out/Makefile new file mode 100644 index 00000000..1e176720 --- /dev/null +++ b/platform/uiq3/_out/Makefile @@ -0,0 +1,7 @@ +all: PicoDrive.SIS + +PicoDrive.SIS: ..\PicoDrive.exe ..\rsc\PicoDrive.rsc ..\rsc\PicoDrive.mbm ..\rsc\PicoDrive_loc.rsc ..\rsc\PicoDrive_reg.rsc + makesis PicoDrive.pkg + +clean: + @erase 2>>nul PicoDrive.pkg diff --git a/platform/uiq3/_out/PicoDrive.pkg b/platform/uiq3/_out/PicoDrive.pkg new file mode 100644 index 00000000..63412a52 --- /dev/null +++ b/platform/uiq3/_out/PicoDrive.pkg @@ -0,0 +1,25 @@ +; + +; List of localised vendor names - one per language. At least one must be provided (English [EN]). +; List must correspond to list of languages specified elsewhere in the .pkg +%{"notaz"} + +; The non-localised, globally unique vendor name (mandatory) +:"notaz" + +; Package header +; Name, UID3, Major, Minor, Build, Package-type +#{"PicoDrive"}, (0xA00010F3), 0, 96, 0, TYPE=SA + +; ProductID for UIQ 3.0 +; Product/platform version UID, Major, Minor, Build, Component name +(0x101F6300), 3, 0, 0, {"UIQ30ProductID"} + + +; Files to install for the application +; If you move the example to another destination then you also need to change these paths. +"..\PicoDrive.exe"-"!:\sys\bin\PicoDrive.exe" +"..\rsc\PicoDrive.rsc"-"!:\resource\apps\PicoDrive.rsc" +"..\rsc\PicoDrive.mbm"-"!:\resource\apps\PicoDrive.mbm" +"..\rsc\PicoDrive_loc.rsc"-"!:\resource\apps\PicoDrive_loc.rsc" +"..\rsc\PicoDrive_reg.rsc"-"!:\private\10003a3f\import\apps\PicoDrive_reg.rsc" diff --git a/platform/uiq3/_out/PicoDrive.zip b/platform/uiq3/_out/PicoDrive.zip new file mode 100644 index 00000000..ccb557d6 Binary files /dev/null and b/platform/uiq3/_out/PicoDrive.zip differ diff --git a/platform/uiq3/_out/PicoDrive_gcce.pkg b/platform/uiq3/_out/PicoDrive_gcce.pkg new file mode 100644 index 00000000..44c88f31 --- /dev/null +++ b/platform/uiq3/_out/PicoDrive_gcce.pkg @@ -0,0 +1,25 @@ +; + +; List of localised vendor names - one per language. At least one must be provided (English [EN]). +; List must correspond to list of languages specified elsewhere in the .pkg +%{"notaz"} + +; The non-localised, globally unique vendor name (mandatory) +:"notaz" + +; Package header +; Name, UID3, Major, Minor, Build, Package-type +#{"PicoDrive"}, (0xA00010F3), 0, 92, 0, TYPE=SA + +; ProductID for UIQ 3.0 +; Product/platform version UID, Major, Minor, Build, Component name +(0x101F6300), 3, 0, 0, {"UIQ30ProductID"} + + +; Files to install for the application +; If you move the example to another destination then you also need to change these paths. +"..\..\..\..\..\..\UIQ3SDK\epoc32\release\gcce\urel\PicoDrive.exe"-"!:\sys\bin\PicoDrive.exe" +"..\..\..\..\..\..\UIQ3SDK\epoc32\data\Z\Resource\Apps\PicoDrive.rsc"-"!:\resource\apps\PicoDrive.rsc" +"..\..\..\..\..\..\UIQ3SDK\epoc32\data\Z\Resource\Apps\PicoDrive_loc.rsc"-"!:\resource\apps\PicoDrive_loc.rsc" +"..\..\..\..\..\..\UIQ3SDK\epoc32\data\z\Private\10003a3f\Apps\PicoDrive_reg.rsc"-"!:\private\10003a3f\import\apps\PicoDrive_reg.rsc" +"..\..\..\..\..\..\UIQ3SDK\epoc32\data\Z\Resource\Apps\PicoDrive.mbm"-"!:\resource\apps\PicoDrive.mbm" diff --git a/platform/uiq3/_out/config.txt b/platform/uiq3/_out/config.txt new file mode 100644 index 00000000..c3db1b11 --- /dev/null +++ b/platform/uiq3/_out/config.txt @@ -0,0 +1,110 @@ +1. Keys: + +If it looks confusing to you, check this tutorial first: +http://notaz.atspace.com/pico_tut/ + +There are no default settings. +When you start key configuration mode, black screen with dark-red squares will +appear. Also there will be little 'control' on the top with the function +name in it, and arrows on the corners of it. You can tap on these corners to +select a function. You can also tap on these squares to bind that function to +them. This way you can associate touchpad areas with game-controls or functions. +I also made a small square in every corner of the screen to be used as a virtual +button for some function, like save state. You can bind it as you like. To +bind phone buttons, simply select the function you need, and press a button +you want. To unbind any key or touchpad area, simply push or tap it again. + +When finished, select 'done' and press any key. You can also press 'Power' +to exit. + +You need to bind 'pause emu' function to be able exit game when ROM is loaded. +It is bound to 'back' button by default. + +2. Main Settings: + +Here you can set the orientation of screen and the drawing mode. The "fit" +option will scale the image so it better fits in the screen, but some detail +will be lost. "center" displays the game at the center of the screen, but +non-fitting parts are not visible then. "fit2" is simmilar to "fit" but is +a bit more stretched (fit modes are only meaningful in 0 or 180 rotation +modes). + +"Fast renderer" enables faster rendering method, but it works only with some +games (some other have serious glitches or even hang). + +"Accurate timing" is needed for some games to run (like Red Zone). It should +be kept off for all other games, because it slows emulation down. Some games +also need this option for proper sound, so enable this if game has any +glitches. + +"Accurate sprites" fixes sprite priority problems, for example if game +character is in front of or behind some object it should not be, this option +should fix it. This option does not work in "Fast renderer" mode. + +"Show FPS" shows game frames per second in format XX/YY, where XX is the +number of frames shown per previous second, and YY is the number of frames +emulated, but not necessarily shown. By calculating YY-XX you get the number +of skipped frames per second. + +3. Sound settings: + +Sound emulation is very picky on CPU power (in most cases sound alone uses +more CPU power than everything else altogether), but it is still possible to +play some games. When using sound, the recommended display modes are "fit 0" +and "fit 180", because these are the fastest ones. Also try "Alternative +renderer", but it might cause graphical glitches. You must use auto frameskip +when using sound, or else you will get stuttering sound. Also, it is +recommended to exit all other non-vital apps (you can use SMan for this), +disable bluetooth and any other devices your phone may have. I also noticed +that simply connecting the phone battery charger strangely slows everything +down. + +"Enable sound" tries to enable sound output on your device, but that alone is +not enough to get sound. You need to enable the sound chips below: +"Z80" is secondary CPU in genesis and is mostly used to control the other 2 +sound chips. So if you disable Z80, sound will be lost in most games, with +some exceptions like Sonic1. It is possible to use Z80 for other things, +some games do that and Z80 must be enabled to run them at all. + +"YM2612" is a fairly complex Frequency Modulation (FM) sound synthesis chip. +It was the main sound output device in genesis and is horrible CPU hog when +is tried to be emulated in software. Disabling it gives large speed +improvement, but most of the sound is lost. + +"SN76496" is programmable sound generator (PSG) chip, used for various sound +effects and music elements. + +Note: if you change sound settings AFTER loading a ROM, you may need to reset +game to get sound. This is because most games initialize sound chips on +startup, and this data is lost when sound chips are being enabled/disabled. + +4. Misc: + +"6 button pad" will enable 6 button gamepad emulation and will add additional +X, Y, Z and MODE actions to key configuration. +Note: if you enable this, games may detect that and use different button +configuration, for example A ("high punch") will change to "low punch" in +Mortal Kombat and you will need to bind X for "high punch". + +"gzip save states" enables gzip (similar to ordinary zip, but a little +different) compression on your save states to save space. The compression +ratio is 50-90%, so it's worth to enable this. + +"Use SRAM saves" option enables emulation of batery-backed save RAM some game +cartridges had. RPG games used it alot, but there were some others too, like +Sonic 3. If this is enabled, .srm files are generated when you exit +the emulator or load another ROM. Format is compatible with other popular +emulators (like Gens and Fusion). + +"Region" lets you set the region of emulated genesis machine. + + +5. Frameskip: + +"Auto" option tries to run the game in it's original speed by skipping next + frame if the previous was rendered too slow. +"0" displays every frame, thus game runs very slow, sound skips. +"1" skips every other frame. Use this for a game which is smoother, but a bit + too slow (actually depends on display mode you use). +"2" also makes the game smoother, but it will be too fast in most areas. +"4","8" similar to above, but skips more frames and often becomes choppy. diff --git a/platform/uiq3/engine/PolledAS.h b/platform/uiq3/engine/PolledAS.h new file mode 100644 index 00000000..14d4a3ff --- /dev/null +++ b/platform/uiq3/engine/PolledAS.h @@ -0,0 +1,32 @@ +/******************************************************************* + * + * File: PolledAS.h + * + * Author: Peter van Sebille (peter@yipton.net) + * + * (c) Copyright 2001, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +#ifndef __POLLED_AS_H +#define __POLLED_AS_H + +class CPrivatePolledActiveScheduler; + +class CPolledActiveScheduler : public CBase +{ +public: + ~CPolledActiveScheduler(); + static CPolledActiveScheduler* NewL(); + static CPolledActiveScheduler* Instance(); + void Schedule(); +protected: + CPolledActiveScheduler(){}; + void ConstructL(); + CPrivatePolledActiveScheduler* iPrivatePolledActiveScheduler; +}; + + +#endif /* __POLLED_AS_H */ + diff --git a/platform/uiq3/engine/audio_mediaserver.cpp b/platform/uiq3/engine/audio_mediaserver.cpp new file mode 100644 index 00000000..aff12d11 --- /dev/null +++ b/platform/uiq3/engine/audio_mediaserver.cpp @@ -0,0 +1,293 @@ +/******************************************************************* + * + * File: Audio_mediaserver.cpp + * + * Author: Peter van Sebille (peter@yipton.net) + * + * Modified/adapted for picodriveN by notaz, 2006 + * + * (c) Copyright 2006, notaz + * (c) Copyright 2001, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +#include "audio_mediaserver.h" +#include "debug.h" + +//#undef DEBUGPRINT +//#define DEBUGPRINT(x...) + + +const TInt KUpdatesPerSec = 10; +const TInt KBlockTime = 1000000 / KUpdatesPerSec; +const TInt KMaxLag = 200000; // max sound lag, lower values increase chance of underflow +const TInt KMaxUnderflows = 50; // max underflows/API errors we are going allow in a row (to prevent lockups) + + +/******************************************* + * + * CGameAudioMS + * + *******************************************/ + +CGameAudioMS::CGameAudioMS(TInt aRate, TBool aStereo, TInt aWritesPerSec) +: iRate(aRate), iStereo(aStereo), iWritesPerSec(aWritesPerSec) +{ +} + + +CGameAudioMS* CGameAudioMS::NewL(TInt aRate, TBool aStereo, TInt aWritesPerSec) +{ + DEBUGPRINT(_L("CGameAudioMS::NewL(%i, %i, %i)"), aRate, aStereo, aWritesPerSec); + CGameAudioMS* self = new(ELeave) CGameAudioMS(aRate, aStereo, aWritesPerSec); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); // self + return self; +} + + +CGameAudioMS::~CGameAudioMS() +{ + DEBUGPRINT(_L("CGameAudioMS::~CGameAudioMS()")); + if(iMdaAudioOutputStream) { + iScheduler->Schedule(); // let it finish it's stuff + iMdaAudioOutputStream->Stop(); + delete iMdaAudioOutputStream; + } + if(iServer) delete iServer; + + for (TInt i=0; iDes().FillZ (bytesPerFrame * iBufferedFrames); + } + + iCurrentBuffer = 0; + iCurrentBufferSize = 0; + + // here we actually test if we can create and open CMdaAudioOutputStream at all, but really create and use it later. + iMdaAudioOutputStream = CMdaAudioOutputStream::NewL(iListener, iServer); + if(iMdaAudioOutputStream) { + iVolume = iMdaAudioOutputStream->MaxVolume(); + DEBUGPRINT(_L("MaxVolume: %i"), iVolume); + delete iMdaAudioOutputStream; + iMdaAudioOutputStream = 0; + } +} + +// returns a pointer to buffer for next frame, +// to be used when iSoundBuffers are used directly +TInt16 *CGameAudioMS::NextFrameL(TInt aPcmFrames) +{ + iCurrentPosition += aPcmFrames << (iStereo?1:0); + iCurrentBufferSize += aPcmFrames << (iStereo?2:1); + + if (++iFrameCount == iBufferedFrames) + { + WriteBlockL(); + } + + iScheduler->Schedule(); + + if(iListener.iUnderflowed) { + if(iListener.iUnderflowed > KMaxUnderflows) { + delete iMdaAudioOutputStream; + iMdaAudioOutputStream = 0; + return 0; + } + UnderflowedL(); // not again! + } + + return iCurrentPosition; +} + +void CGameAudioMS::WriteBlockL() +{ + iScheduler->Schedule(); + // do not write until stream is open + if(!iListener.iIsOpen) WaitForOpenToCompleteL(); + //if(!iListener.iHasCopied) WaitForCopyToCompleteL(); // almost never happens anyway and sometimes even deadlocks? + //iListener.iHasCopied = EFalse; + + + if(!iListener.iUnderflowed) { + TInt64 delta; + // don't write if sound is lagging too much + delta = iTime - iMdaAudioOutputStream->Position().Int64(); + if (delta > MAKE_TINT64(0, KMaxLag)) + // another query sometimes returns very different result + delta = iTime - iMdaAudioOutputStream->Position().Int64(); + + if(delta <= MAKE_TINT64(0, KMaxLag)) { + //RDebug::Print(_L("delta: %i"), iTime.Low() - iMdaAudioOutputStream->Position().Int64().Low()); + iSoundBuffers[iCurrentBuffer]->Des().SetLength(iCurrentBufferSize); + iMdaAudioOutputStream->WriteL(*iSoundBuffers[iCurrentBuffer]); + iTime += KBlockTime; + } else { + DEBUGPRINT(_L("lag: %i"), I64LOW(delta)); + } + } + + iFrameCount = 0; + if (++iCurrentBuffer == KSoundBuffers) + iCurrentBuffer = 0; + iCurrentPosition = (TInt16*) iSoundBuffers[iCurrentBuffer]->Ptr(); + iCurrentBufferSize = 0; +} + +void CGameAudioMS::Pause() +{ + if(!iMdaAudioOutputStream) return; + + iScheduler->Schedule(); // let it finish it's stuff + iMdaAudioOutputStream->Stop(); + delete iMdaAudioOutputStream; + iMdaAudioOutputStream = 0; +} + +// call this before doing any playback! +TInt16 *CGameAudioMS::ResumeL() +{ + DEBUGPRINT(_L("CGameAudioMS::Resume()")); + iScheduler->Schedule(); + + // we act a bit strange here: simulate buffer underflow, which actually starts audio + iListener.iIsOpen = ETrue; + iListener.iUnderflowed = 1; + iListener.iLastError = 0; + iFrameCount = 0; + iCurrentBufferSize = 0; + iCurrentPosition = (TInt16*) iSoundBuffers[iCurrentBuffer]->Ptr(); + return iCurrentPosition; +} + +// handles underflow condition +void CGameAudioMS::UnderflowedL() +{ + DEBUGPRINT(_L("UnderflowedL()")); + + if (iListener.iLastError != KErrUnderflow) + { + // recreate the stream + //iMdaAudioOutputStream->Stop(); + if(iMdaAudioOutputStream) delete iMdaAudioOutputStream; + iMdaAudioOutputStream = CMdaAudioOutputStream::NewL(iListener, iServer); + iMdaAudioOutputStream->Open(&iMdaAudioDataSettings); + iMdaAudioOutputStream->SetAudioPropertiesL(iMdaAudioDataSettings.iSampleRate, iMdaAudioDataSettings.iChannels); + iMdaAudioOutputStream->SetVolume(iVolume); // new in UIQ3 + + iListener.iIsOpen = EFalse; // wait for it to open + //iListener.iHasCopied = ETrue; // but don't wait for last copy to complete + // let it open and feed some stuff to make it happy + User::After(0); + iScheduler->Schedule(); + iListener.iLastError = 0; + if(!iListener.iIsOpen) WaitForOpenToCompleteL(); + } else { + iListener.iLastError = iListener.iUnderflowed = 0; + } + iTime = iMdaAudioOutputStream->Position().Int64(); +} + +void CGameAudioMS::WaitForOpenToCompleteL() +{ + DEBUGPRINT(_L("CGameAudioMS::WaitForOpenToCompleteL")); + TInt count = 20; // 2 seconds + TInt waitPeriod = 100 * 1000; + + if(!iListener.iIsOpen) { + // it is often enough to do this + User::After(0); + iScheduler->Schedule(); + } + while (!iListener.iIsOpen && --count) + { + User::After(waitPeriod); + iScheduler->Schedule(); + } + if (!iListener.iIsOpen) + User::LeaveIfError(KErrNotSupported); +} + +void CGameAudioMS::ChangeVolume(TInt aUp) +{ + //DEBUGPRINT(_L("CGameAudioMS::ChangeVolume(%i)"), aUp); + + if (iMdaAudioOutputStream) { + if (aUp) { + if (iVolume < iMdaAudioOutputStream->MaxVolume()) iVolume+=5; + } else { + if (iVolume > 0) iVolume-=5; + } + iMdaAudioOutputStream->SetVolume(iVolume); + } +} + +void TGameAudioEventListener::MaoscOpenComplete(TInt aError) +{ + DEBUGPRINT(_L("CGameAudioMS::MaoscOpenComplete, error=%d"), aError); + + iIsOpen = ETrue; + if(aError) { + iLastError = aError; + iUnderflowed++; + } + else iUnderflowed = 0; +} + +void TGameAudioEventListener::MaoscBufferCopied(TInt aError, const TDesC8& aBuffer) +{ + if (aError) + DEBUGPRINT(_L("CGameAudioMS::MaoscBufferCopied, error=%d"), aError); + +// iHasCopied = ETrue; + + if(aError) { // shit! + iLastError = aError; + iUnderflowed++; + } +} + +void TGameAudioEventListener::MaoscPlayComplete(TInt aError) +{ + DEBUGPRINT(_L("CGameAudioMS::MaoscPlayComplete: %i"), aError); + if(aError) { + iLastError = aError; + iUnderflowed++; // never happened to me while testing, but just in case + } +} + diff --git a/platform/uiq3/engine/audio_mediaserver.h b/platform/uiq3/engine/audio_mediaserver.h new file mode 100644 index 00000000..25d10275 --- /dev/null +++ b/platform/uiq3/engine/audio_mediaserver.h @@ -0,0 +1,85 @@ +/******************************************************************* + * + * File: Audio_mediaserver.h + * + * Author: Peter van Sebille (peter@yipton.net) + * + * Modified/adapted for picodriveN by notaz, 2006 + * + * (c) Copyright 2006, notaz + * (c) Copyright 2001, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +#ifndef __AUDIO_MEDIASERVER_H +#define __AUDIO_MEDIASERVER_H + +#include +#include + +//#include "audio.h" +#include "polledas.h" + +const TInt KSoundBuffers = 4; + + +class TGameAudioEventListener : public MMdaAudioOutputStreamCallback +{ +public: // implements MMdaAudioOutputStreamCallback + void MaoscOpenComplete(TInt aError); + void MaoscBufferCopied(TInt aError, const TDesC8& ); + void MaoscPlayComplete(TInt aError); + + TBool iIsOpen; +// TBool iHasCopied; + TInt iUnderflowed; + TInt iLastError; +}; + + +class CGameAudioMS // : public IGameAudio // IGameAudio MUST be specified first! +{ +public: // implements IGameAudio + TInt16 *NextFrameL(TInt aPcmFrames); + TInt16 *ResumeL(); + void Pause(); + void ChangeVolume(TInt aUp); + +public: + ~CGameAudioMS(); + CGameAudioMS(TInt aRate, TBool aStereo, TInt aWritesPerSec); + static CGameAudioMS* NewL(TInt aRate, TBool aStereo, TInt aWritesPerSec); + +protected: + void WriteBlockL(); + void UnderflowedL(); + void ConstructL(); + +protected: + void WaitForOpenToCompleteL(); + + TInt iRate; + TBool iStereo; + + CMdaAudioOutputStream *iMdaAudioOutputStream; + TMdaAudioDataSettings iMdaAudioDataSettings; + + TGameAudioEventListener iListener; + + CPolledActiveScheduler *iScheduler; + + HBufC8* iSoundBuffers[KSoundBuffers]; + TInt iWritesPerSec; + TInt iBufferedFrames; + TInt16* iCurrentPosition; + TInt iCurrentBuffer; + TInt iCurrentBufferSize; + TInt iFrameCount; + CMdaServer* iServer; + + TInt64 iTime; + TInt iVolume; +}; + +#endif /* __AUDIO_MEDIASERVER_H */ diff --git a/platform/uiq3/engine/blit.c b/platform/uiq3/engine/blit.c new file mode 100644 index 00000000..809f0f70 --- /dev/null +++ b/platform/uiq3/engine/blit.c @@ -0,0 +1,34 @@ + +/* +void vidConvCpyRGB32 (void *to, void *from, int lines, int p240) +{ + unsigned short *ps = (unsigned short *) from; + unsigned long *pd = (unsigned long *) to; + int x, y; + int to_x = p240 ? 240 : 224; + if(!p240) pd += 8; + + for(y = 0; y < lines; y++) // ps < ps_end; ps++) + for(x = 0; x < to_x; x++, ps++) + // Convert 0000bbb0 ggg0rrr0 + // to ..0 rrr00000 ggg00000 bbb00000 + *(pd+y*256+x) = ((*ps&0x000F)<<20) | ((*ps&0x00F0)<<8) | ((*ps&0x0F00)>>4); +} +*/ + +// stubs +void vidConvCpyRGB32 (void *to, void *from, int pixels) {} +void vidConvCpyRGB32sh(void *to, void *from, int pixels) {} +void vidConvCpyRGB32hi(void *to, void *from, int pixels) {} + +void vidConvCpy_90 (void *to, void *from, void *pal, int width) {} +void vidConvCpy_270 (void *to, void *from, void *pal, int width) {} +void vidConvCpy_center_0 (void *to, void *from, void *pal) {} +void vidConvCpy_center_180(void *to, void *from, void *pal) {} +void vidConvCpy_center2_40c_0 (void *to, void *from, void *pal, int lines) {} +void vidConvCpy_center2_40c_180(void *to, void *from, void *pal, int lines) {} +void vidConvCpy_center2_32c_0 (void *to, void *from, void *pal, int lines) {} +void vidConvCpy_center2_32c_180(void *to, void *from, void *pal, int lines) {} + +void vidClear(void *to, int lines) {} + diff --git a/platform/uiq3/engine/blit.h b/platform/uiq3/engine/blit.h new file mode 100644 index 00000000..4255b387 --- /dev/null +++ b/platform/uiq3/engine/blit.h @@ -0,0 +1,22 @@ +// (c) Copyright 2006 notaz, All rights reserved. +// Free for non-commercial use. + +// For commercial use, separate licencing terms must be obtained. + +extern "C" +{ + void vidConvCpyRGB32 (void *to, void *from, int pixels); + void vidConvCpyRGB32sh(void *to, void *from, int pixels); + void vidConvCpyRGB32hi(void *to, void *from, int pixels); + + void vidConvCpy_90 (void *to, void *from, void *pal, int width); + void vidConvCpy_270 (void *to, void *from, void *pal, int width); + void vidConvCpy_center_0 (void *to, void *from, void *pal); + void vidConvCpy_center_180(void *to, void *from, void *pal); + void vidConvCpy_center2_40c_0 (void *to, void *from, void *pal, int lines); + void vidConvCpy_center2_40c_180(void *to, void *from, void *pal, int lines); + void vidConvCpy_center2_32c_0 (void *to, void *from, void *pal, int lines); + void vidConvCpy_center2_32c_180(void *to, void *from, void *pal, int lines); + + void vidClear(void *to, int lines); +} diff --git a/platform/uiq3/engine/blit.s b/platform/uiq3/engine/blit.s new file mode 100644 index 00000000..521c31a4 --- /dev/null +++ b/platform/uiq3/engine/blit.s @@ -0,0 +1,695 @@ +@ some color conversion and blitting routines + +@ (c) Copyright 2006, notaz +@ All Rights Reserved + + +@ Convert 0000bbb0 ggg0rrr0 0000bbb0 ggg0rrr0 +@ to 00000000 rrr00000 ggg00000 bbb00000 ... + +@ lr = 0x00e000e0, out: r3=lower_pix, r2=higher_pix; trashes rin +@ if sh==2, r8=0x00404040 (sh!=0 destroys flags!) +.macro convRGB32_2 rin sh=0 + and r2, lr, \rin, lsr #4 @ blue + and r3, \rin, lr + orr r2, r2, r3, lsl #8 @ g0b0g0b0 + + mov r3, r2, lsl #16 @ g0b00000 + and \rin,lr, \rin, ror #12 @ 00r000r0 (reversed) + orr r3, r3, \rin, lsr #16 @ g0b000r0 +.if \sh == 1 + mov r3, r3, ror #17 @ shadow mode +.elseif \sh == 2 + adds r3, r3, #0x40000000 @ green + orrcs r3, r3, #0xe0000000 + mov r3, r3, ror #8 + adds r3, r3, #0x40000000 + orrcs r3, r3, #0xe0000000 + mov r3, r3, ror #16 + adds r3, r3, #0x40000000 + orrcs r3, r3, #0xe0000000 + mov r3, r3, ror #24 + orr r3, r3, r3, lsr #3 +.else + mov r3, r3, ror #16 @ r3=low + orr r3, r3, r3, lsr #3 +.endif + + str r3, [r0], #4 + + mov r2, r2, lsr #16 + orr r2, r2, \rin, lsl #16 +.if \sh == 1 + mov r2, r2, lsr #1 +.elseif \sh == 2 + mov r2, r2, ror #8 + adds r2, r2, #0x40000000 @ blue + orrcs r2, r2, #0xe0000000 + mov r2, r2, ror #8 + adds r2, r2, #0x40000000 + orrcs r2, r2, #0xe0000000 + mov r2, r2, ror #8 + adds r2, r2, #0x40000000 + orrcs r2, r2, #0xe0000000 + mov r2, r2, ror #8 + orr r2, r2, r2, lsr #3 +.else + orr r2, r2, r2, lsr #3 +.endif + + str r2, [r0], #4 +.endm + + +.global vidConvCpyRGB32 @ void *to, void *from, int pixels + +vidConvCpyRGB32: + stmfd sp!, {r4-r7,lr} + + mov r12, r2, lsr #3 @ repeats + mov lr, #0x00e00000 + orr lr, lr, #0x00e0 + +.loopRGB32: + subs r12, r12, #1 + + ldmia r1!, {r4-r7} + convRGB32_2 r4 + convRGB32_2 r5 + convRGB32_2 r6 + convRGB32_2 r7 + + bgt .loopRGB32 + + ldmfd sp!, {r4-r7,lr} + bx lr + + +.global vidConvCpyRGB32sh @ void *to, void *from, int pixels + +vidConvCpyRGB32sh: + stmfd sp!, {r4-r7,lr} + + mov r12, r2, lsr #3 @ repeats + mov lr, #0x00e00000 + orr lr, lr, #0x00e0 + +.loopRGB32sh: + subs r12, r12, #1 + + ldmia r1!, {r4-r7} + convRGB32_2 r4, 1 + convRGB32_2 r5, 1 + convRGB32_2 r6, 1 + convRGB32_2 r7, 1 + + bgt .loopRGB32sh + + ldmfd sp!, {r4-r7,lr} + bx lr + + +.global vidConvCpyRGB32hi @ void *to, void *from, int pixels + +vidConvCpyRGB32hi: + stmfd sp!, {r4-r7,lr} + + mov r12, r2, lsr #3 @ repeats + mov lr, #0x00e00000 + orr lr, lr, #0x00e0 + +.loopRGB32hi: + ldmia r1!, {r4-r7} + convRGB32_2 r4, 2 + convRGB32_2 r5, 2 + convRGB32_2 r6, 2 + convRGB32_2 r7, 2 + + subs r12, r12, #1 + bgt .loopRGB32hi + + ldmfd sp!, {r4-r7,lr} + bx lr + + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +@ -------- M2 stuff --------- +/* +.global vidConvCpy_90 @ void *to, void *from, int width + +vidConvCpy_90: + stmfd sp!, {r4-r10,lr} + + mov lr, #0x00F00000 + orr lr, lr, #0x00F0 + + mov r12, #224/4 @ row counter + mov r10, r2, lsl #2 @ we do 2 pixel wide copies + + add r8, r0, #256*4 @ parallel line + add r1, r1, #0x23000 + add r1, r1, #0x00B80 @ r1+=328*223*2+8*2 + mov r9, r1 + + mov r4, #0 @ fill bottom border + mov r5, #0 + mov r6, #0 + mov r7, #0 + stmia r0!, {r4-r7} + stmia r0!, {r4-r7} + stmia r8!, {r4-r7} + stmia r8!, {r4-r7} + +.loopM2RGB32_90: + subs r12, r12, #1 + + @ at first this loop was written differently: src pixels were fetched with ldm's and + @ dest was not sequential. It ran nearly 2 times slower. It seems it is very important + @ to do sequential memory access on those items, which we have more (to offload addressing bus?). + + ldr r4, [r1], #-328*2 + ldr r5, [r1], #-328*2 + ldr r6, [r1], #-328*2 + ldr r7, [r1], #-328*2 + + convRGB32_2 r4, 1 + convRGB32_2 r5, 1 + convRGB32_2 r6, 1 + convRGB32_2 r7, 1 + + str r4, [r8], #4 + str r5, [r8], #4 + str r6, [r8], #4 + str r7, [r8], #4 + + bne .loopM2RGB32_90 + + mov r4, #0 @ top border + mov r5, #0 + mov r6, #0 + stmia r0!, {r4-r6,r12} + stmia r0!, {r4-r6,r12} + stmia r8!, {r4-r6,r12} + stmia r8!, {r4-r6,r12} + + subs r10, r10, #1 + ldmeqfd sp!, {r4-r10,pc} @ return + + add r0, r8, #16*4 @ set new dst pointer + add r8, r0, #256*4 + add r9, r9, #2*2 @ fix src pointer + mov r1, r9 + + stmia r0!, {r4-r6,r12} @ bottom border + stmia r0!, {r4-r6,r12} + stmia r8!, {r4-r6,r12} + stmia r8!, {r4-r6,r12} + + mov r12, #224/4 @ restore row counter + b .loopM2RGB32_90 + + + +@ converter for vidConvCpy_270 +@ lr = 0x00F000F0, out: r3=lower_pix, r2=higher_pix; trashes rin +.macro convRGB32_3 rin + and r2, lr, \rin, lsr #4 @ blue + and r3, \rin, lr + orr r2, r2, r3, lsl #8 @ g0b0g0b0 + + mov r3, r2, lsl #16 @ g0b00000 + and \rin,lr, \rin, ror #12 @ 00r000r0 (reversed) + orr r3, r3, \rin, lsr #16 @ g0b000r0 + + mov r2, r2, lsr #16 + orr r2, r2, \rin, lsl #16 + str r2, [r0], #4 + + mov \rin,r3, ror #16 @ r3=low +.endm +*/ +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + +@ takes byte-sized pixels from r3-r6, fetches from pal and stores to r7,r8,r10,lr +@ r2=pal +.macro mode2_4pix shift + and r7, r11, r3, lsr #\shift + ldr r7, [r2, r7, lsl #2] + + and r8, r11, r4, lsr #\shift + ldr r8, [r2, r8, lsl #2] + + and r10,r11, r5, lsr #\shift + ldr r10,[r2, r10,lsl #2] + + and lr, r11, r6, lsr #\shift + ldr lr, [r2, lr, lsl #2] +.endm + +@ r2=pal, r11=0xff +.macro mode2_4pix_getpix0 dreg sreg + and \dreg, r11, \sreg + ldr \dreg, [r2, \dreg, lsl #2] +.endm + +.macro mode2_4pix_getpix1 dreg sreg + and \dreg, r11, \sreg, lsr #8 + ldr \dreg, [r2, \dreg, lsl #2] +.endm + +.macro mode2_4pix_getpix2 dreg sreg + and \dreg, r11, \sreg, lsr #16 + ldr \dreg, [r2, \dreg, lsl #2] +.endm + +.macro mode2_4pix_getpix3 dreg sreg + and \dreg, r11, \sreg, lsr #24 + ldr \dreg, [r2, \dreg, lsl #2] +.endm + +@ takes byte-sized pixels from reg, fetches from pal and stores to r3-r6 +@ r11=0xFF, r2=pal +.macro mode2_4pix2_0 reg + mode2_4pix_getpix0 r3, \reg + mode2_4pix_getpix1 r4, \reg + mode2_4pix_getpix2 r5, \reg + mode2_4pix_getpix3 r6, \reg +.endm + +@ ... +.macro mode2_4pix2_180 reg + mode2_4pix_getpix3 r3, \reg + mode2_4pix_getpix2 r4, \reg + mode2_4pix_getpix1 r5, \reg + mode2_4pix_getpix0 r6, \reg +.endm + +@ takes byte-sized pixels from reg, fetches from pal and stores to r3-r5 +@ r11=0xFF, r2=pal, r10=0xfcfcfc, r6=tmp +.macro mode2_4pix_to3 reg is180 +.if \is180 + mode2_4pix_getpix3 r3, \reg + mode2_4pix_getpix2 r4, \reg +.else + mode2_4pix_getpix0 r3, \reg @ gathering loads cause a weird-hang + mode2_4pix_getpix1 r4, \reg +.endif + + sub r3, r3, r3, lsr #2 @ r3 *= 0.75 + add r3, r3, r4, lsr #2 @ r3 += r4 * 0.25 + and r3, r3, r10 + +.if \is180 + mode2_4pix_getpix1 r5, \reg + mode2_4pix_getpix0 r6, \reg +.else + mode2_4pix_getpix2 r5, \reg + mode2_4pix_getpix3 r6, \reg +.endif + + mov r4, r4, lsr #1 + add r4, r4, r5, lsr #1 @ r4 = (r4 + r5) / 2; +@ and r4, r4, r10 + sub r6, r6, r6, lsr #2 @ r6 *= 0.75 + add r5, r6, r5, lsr #2 @ r5 = r6 + r5 * 0.25 + and r5, r5, r10 +.endm + + +@ void *to, void *from, void *pal, int width +.macro vidConvCpyM2_landscape is270 + stmfd sp!, {r4-r11,lr} + + mov r11, #0xff + + mov r12, #(224/4-1)<<16 @ row counter + orr r12, r12, r3, lsl #1 @ we do 4 pixel wide copies (right to left) + +.if \is270 + add r1, r1, #324 +.else + add r1, r1, #0x11c00 + add r1, r1, #0x00308 @ 328*224+8 +.endif + mov r9, r1 + + mov r3, #0 @ fill top border + mov r4, #0 + mov r5, #0 + mov r6, #0 + stmia r0!, {r3-r6} + stmia r0!, {r3-r6} + add r7, r0, #256*4-8*4 + stmia r7!, {r3-r6} + stmia r7!, {r3-r6} + add r7, r7, #256*4-8*4 + stmia r7!, {r3-r6} + stmia r7!, {r3-r6} + add r7, r7, #256*4-8*4 + stmia r7!, {r3-r6} + stmia r7!, {r3-r6} + +0: @ .loopM2RGB32_270: + subs r12, r12, #1<<16 + +.if \is270 + ldr r3, [r1], #328 + ldr r4, [r1], #328 + ldr r5, [r1], #328 + ldr r6, [r1], #328 +.else + ldr r3, [r1, #-328]! + ldr r4, [r1, #-328]! + ldr r5, [r1, #-328]! + ldr r6, [r1, #-328]! +.endif + +.if \is270 + mode2_4pix 24 +.else + mode2_4pix 0 +.endif + stmia r0, {r7,r8,r10,lr} + add r0, r0, #256*4 + +.if \is270 + mode2_4pix 16 +.else + mode2_4pix 8 +.endif + stmia r0, {r7,r8,r10,lr} + add r0, r0, #256*4 + +.if \is270 + mode2_4pix 8 +.else + mode2_4pix 16 +.endif + stmia r0, {r7,r8,r10,lr} + add r0, r0, #256*4 + +.if \is270 + mode2_4pix 0 +.else + mode2_4pix 24 +.endif + stmia r0!,{r7,r8,r10,lr} + sub r0, r0, #256*4*3 + + bpl 0b @ .loopM2RGB32_270 + + mov r3, #0 @ bottom border + mov r4, #0 + mov r5, #0 + mov r6, #0 + stmia r0!, {r3-r6} + stmia r0!, {r3-r6} + add r0, r0, #256*4-8*4 + stmia r0!, {r3-r6} + stmia r0!, {r3-r6} + add r0, r0, #256*4-8*4 + stmia r0!, {r3-r6} + stmia r0!, {r3-r6} + add r0, r0, #256*4-8*4 + stmia r0!, {r3-r6} + nop @ phone crashes if this is commented out. Do I stress it too much? + stmia r0!, {r3-r6} + + add r12, r12, #1<<16 + subs r12, r12, #1 + ldmeqfd sp!, {r4-r11,pc} @ return + + add r0, r0, #16*4 +.if \is270 + sub r9, r9, #4 @ fix src pointer +.else + add r9, r9, #4 +.endif + mov r1, r9 + + stmia r0!, {r3-r6} @ top border + stmia r0!, {r3-r6} + add r7, r0, #256*4-8*4 + stmia r7!, {r3-r6} + stmia r7!, {r3-r6} + add r7, r7, #256*4-8*4 + stmia r7!, {r3-r6} + stmia r7!, {r3-r6} + add r7, r7, #256*4-8*4 + stmia r7!, {r3-r6} + stmia r7!, {r3-r6} + + orr r12, r12, #(224/4-1)<<16 @ restore row counter + b 0b @ .loopM2RGB32_270 +.endm + + +.global vidConvCpy_90 @ void *to, void *from, void *pal, int width + +vidConvCpy_90: + vidConvCpyM2_landscape 0 + + +.global vidConvCpy_270 @ void *to, void *from, void *pal, int width + +vidConvCpy_270: + vidConvCpyM2_landscape 1 + + +.global vidConvCpy_center_0 @ void *to, void *from, void *pal + +vidConvCpy_center_0: + stmfd sp!, {r4-r6,r11,lr} + + mov r11, #0xff + add r1, r1, #8 @ not border (centering 32col here) + + mov r12, #(240/4-1)<<16 + orr r12, r12, #224 + +.loopRGB32_c0: + ldr lr, [r1], #4 + subs r12, r12, #1<<16 + + mode2_4pix2_0 lr + stmia r0!, {r3-r6} + bpl .loopRGB32_c0 + + sub r12, r12, #1 + adds r12, r12, #1<<16 + ldmeqfd sp!, {r4-r6,r11,pc} @ return + add r0, r0, #16*4 + add r1, r1, #88 + orr r12, #(240/4-1)<<16 + b .loopRGB32_c0 + + +.global vidConvCpy_center_180 @ void *to, void *from, void *pal + +vidConvCpy_center_180: + stmfd sp!, {r4-r6,r11,lr} + + mov r11, #0xff + add r1, r1, #0x11c00 + add r1, r1, #0x002B8 @ #328*224-72 + + mov r12, #(240/4-1)<<16 + orr r12, r12, #224 + +.loopRGB32_c180: + ldr lr, [r1, #-4]! + subs r12, r12, #1<<16 + + mode2_4pix2_180 lr + stmia r0!, {r3-r6} + bpl .loopRGB32_c180 + + sub r12, r12, #1 + adds r12, r12, #1<<16 + ldmeqfd sp!, {r4-r6,r11,pc} @ return + add r0, r0, #16*4 + sub r1, r1, #88 + orr r12, #(240/4-1)<<16 + b .loopRGB32_c180 + + +@ note: the following code assumes that (pal[x] & 0x030303) == 0 + +.global vidConvCpy_center2_40c_0 @ void *to, void *from, void *pal, int lines + +vidConvCpy_center2_40c_0: + stmfd sp!, {r4-r6,r10,r11,lr} + + mov r11, #0xff + mov r10, #0xfc + orr r10, r10, lsl #8 + orr r10, r10, lsl #8 + add r1, r1, #8 @ border + + mov r12, #(240/3-1)<<16 + orr r12, r12, r3 + +.loopRGB32_c2_40c_0: + ldr lr, [r1], #4 + subs r12, r12, #1<<16 + + mode2_4pix_to3 lr, 0 + + stmia r0!, {r3-r5} + bpl .loopRGB32_c2_40c_0 + + sub r12, r12, #1 + adds r12, r12, #1<<16 + ldmeqfd sp!, {r4-r6,r10,r11,pc} @ return + add r0, r0, #16*4 + add r1, r1, #8 + orr r12, #(240/3-1)<<16 + b .loopRGB32_c2_40c_0 + + +.global vidConvCpy_center2_40c_180 @ void *to, void *from, void *pal, int lines + +vidConvCpy_center2_40c_180: + stmfd sp!, {r4-r6,r10,r11,lr} + + mov r11, #0xff + mov r10, #0xfc + orr r10, r10, lsl #8 + orr r10, r10, lsl #8 + + mov r4, #328 + mla r1, r3, r4, r1 +@ add r1, r1, #0x11000 +@ add r1, r1, #0x00f00 @ #328*224 + + mov r12, #(240/3-1)<<16 + orr r12, r12, r3 + +.loop_c2_40c_180: + ldr lr, [r1, #-4]! + subs r12, r12, #1<<16 + + mode2_4pix_to3 lr, 1 + + stmia r0!, {r3-r5} + bpl .loop_c2_40c_180 + + sub r12, r12, #1 + adds r12, r12, #1<<16 + ldmeqfd sp!, {r4-r6,r10,r11,pc} @ return + add r0, r0, #16*4 + sub r1, r1, #8 + orr r12, #(240/3-1)<<16 + b .loop_c2_40c_180 + + +.global vidConvCpy_center2_32c_0 @ void *to, void *from, void *pal, int lines + +vidConvCpy_center2_32c_0: + stmfd sp!, {r4-r11,lr} + + mov r10, #0xfc + orr r10, r10, lsl #8 + orr r10, r10, lsl #8 + mov r11, #0xff + add r1, r1, #8 @ border + + mov r12, #(240/15-1)<<16 + orr r12, r12, r3 + +.loop_c2_32c_0: + ldmia r1!, {r7-r9,lr} + subs r12, r12, #1<<16 + + mode2_4pix2_0 r7 + stmia r0!, {r3-r6} + mode2_4pix2_0 r8 + stmia r0!, {r3-r6} + mode2_4pix2_0 r9 + stmia r0!, {r3-r6} + mode2_4pix_to3 lr, 0 + stmia r0!, {r3-r5} + bpl .loop_c2_32c_0 + + sub r12, r12, #1 + adds r12, r12, #1<<16 + ldmeqfd sp!, {r4-r11,pc} @ return + add r0, r0, #16*4 + add r1, r1, #64+8 + orr r12, #(240/15-1)<<16 + b .loop_c2_32c_0 + + +.global vidConvCpy_center2_32c_180 @ void *to, void *from, void *pal, int lines + +vidConvCpy_center2_32c_180: + stmfd sp!, {r4-r11,lr} + + mov r10, #0xfc + orr r10, r10, lsl #8 + orr r10, r10, lsl #8 + mov r11, #0xff + + mov r4, #328 + mla r1, r3, r4, r1 +@ add r1, r1, #0x11000 +@ add r1, r1, #0x00f00 @ #328*224 + + mov r12, #(240/15-1)<<16 + orr r12, r12, r3 + +.loop_c2_32c_180: + ldmdb r1!, {r7-r9,lr} + subs r12, r12, #1<<16 + + mode2_4pix2_180 lr + stmia r0!, {r3-r6} + mode2_4pix2_180 r9 + stmia r0!, {r3-r6} + mode2_4pix2_180 r8 + stmia r0!, {r3-r6} + mode2_4pix_to3 r7, 1 + stmia r0!, {r3-r5} + bpl .loop_c2_32c_180 + + sub r12, r12, #1 + adds r12, r12, #1<<16 + ldmeqfd sp!, {r4-r11,pc} @ return + add r0, r0, #16*4 + sub r1, r1, #64+8 + orr r12, #(240/15-1)<<16 + b .loop_c2_32c_180 + + +@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + +.global vidClear @ void *to, int lines + +vidClear: + stmfd sp!, {lr} + mov r12, #240/16-1 + orr r12, r1, r12, lsl #16 + mov r1, #0 + mov r2, #0 + mov r3, #0 + mov lr, #0 + +.loopVidClear: + subs r12, r12, #1<<16 + + stmia r0!, {r1-r3,lr} + stmia r0!, {r1-r3,lr} + stmia r0!, {r1-r3,lr} + stmia r0!, {r1-r3,lr} + bpl .loopVidClear + + sub r12, r12, #1 + adds r12, r12, #1<<16 + ldmeqfd sp!, {pc} @ return + add r0, r0, #16*4 + orr r12, #(240/16-1)<<16 + b .loopVidClear + diff --git a/platform/uiq3/engine/debug.cpp b/platform/uiq3/engine/debug.cpp new file mode 100644 index 00000000..c5321871 --- /dev/null +++ b/platform/uiq3/engine/debug.cpp @@ -0,0 +1,259 @@ + +#include // RDebug +#include "debug.h" + +#ifdef __WINS__ + +void ExceptionHandler(TExcType exc) {} + +#else + +static const wchar_t * const exception_names[] = { + L"General", + L"IntegerDivideByZero", + L"SingleStep", + L"BreakPoint", + L"IntegerOverflow", + L"BoundsCheck", + L"InvalidOpCode", + L"DoubleFault", + L"StackFault", + L"AccessViolation", + L"PrivInstruction", + L"Alignment", + L"PageFault", + L"FloatDenormal", + L"FloatDivideByZero", + L"FloatInexactResult", + L"FloatInvalidOperation", + L"FloatOverflow", + L"FloatStackCheck", + L"FloatUnderflow", + L"Abort", + L"Kill", + L"DataAbort", + L"CodeAbort", + L"MaxNumber", + L"InvalidVector", + L"UserInterrupt", + L"Unknown" +}; + + +static void getASpace(TUint *code_start, TUint *code_end, TUint *stack_start, TUint *stack_end) +{ + TUint pc, sp; + RChunk chunk; + TFullName chunkname; + TFindChunk findChunk(_L("*")); + + asm volatile ("str pc, %0" : "=m" (pc) ); + asm volatile ("str sp, %0" : "=m" (sp) ); + + while( findChunk.Next(chunkname) != KErrNotFound ) { + chunk.Open(findChunk); + if((TUint)chunk.Base()+chunk.Bottom() < pc && pc < (TUint)chunk.Base()+chunk.Top()) { + if(code_start) *code_start = (TUint)chunk.Base()+chunk.Bottom(); + if(code_end) *code_end = (TUint)chunk.Base()+chunk.Top(); + } else + if((TUint)chunk.Base()+chunk.Bottom() < sp && sp < (TUint)chunk.Base()+chunk.Top()) { + if(stack_start) *stack_start = (TUint)chunk.Base()+chunk.Bottom(); + if(stack_end) *stack_end = (TUint)chunk.Base()+chunk.Top(); + } + chunk.Close(); + } +} + +// tmp +#if defined(__DEBUG_PRINT) +extern "C" char *debugString(); +#endif + +// our very own exception handler +void ExceptionHandler(TExcType exc) +{ + TUint lr, sp, i; + TUint stack_end = 0; // ending address of our stack chunk + TUint code_start = 0, code_end = 0; // starting and ending addresses of our code chunk + TUint guessed_address = 0; + + DEBUGPRINT(_L("ExceptionHandler()")); // this seems to never be called + + asm volatile ("str lr, %0" : "=m" (lr) ); + asm volatile ("str sp, %0" : "=m" (sp) ); + + // first get some info about the chunks we live in + getASpace(&code_start, &code_end, 0, &stack_end); + + // now we begin some black magic tricks + // we go up our stack until we pass our caller address + for(; sp < stack_end; sp += 4) + if(*(TUint *)sp == lr) break; + + // there might be mirored caller address + for(i = sp + 4; i < sp + 0x300 && i < stack_end; i += 4) + if(*(TUint *)i == lr) { sp = i; break; } + + // aah, it is always 0x9c bytes away from the caller address in my firmware, + // don't know how to detect it in any other way + sp += 0x9c; + guessed_address = *(TUint *)sp; + + // output the info + TUint exec_show = exc; + if(exec_show > 27) exec_show = 27; + TPtrC ptrExc((TUint16 *) exception_names[exec_show]); + + RDebug::Print(_L("!!!Exception %i (%S) @ 0x%08x (guessed; relative=0x%08x)"), exc, &ptrExc, guessed_address, guessed_address - code_start); +#ifdef __DEBUG_PRINT_FILE + DEBUGPRINT( _L("!!!Exception %i (%S) @ 0x%08x (guessed; relative=0x%08x)"), exc, &ptrExc, guessed_address, guessed_address - code_start); +#endif + + TBuf<148> buff1; + TBuf<10> buff2; + buff1.Copy(_L(" guessed stack: ")); + + for(sp += 4, i = 0; i < 5 && sp < stack_end; sp += 4) { + if((*(TUint *)sp >> 28) == 5) { + if(i++) buff1.Append(_L(", ")); + buff2.Format(_L("0x%08x"), *(TUint *)sp); + buff1.Append(buff2); + } + else if(code_start < *(TUint *)sp && *(TUint *)sp < code_end) { + if(i++) buff1.Append(_L(", ")); + buff2.Format(_L("0x%08x"), *(TUint *)sp); + buff1.Append(buff2); + buff1.Append(_L(" (")); + buff2.Format(_L("0x%08x"), *(TUint *)sp - code_start); + buff1.Append(buff2); + buff1.Append(_L(")")); + } + } + RDebug::Print(_L("%S"), &buff1); +#ifdef __DEBUG_PRINT_FILE + DEBUGPRINT(_L("%S"), &buff1); +#endif + + // tmp +#if defined(__DEBUG_PRINT) + char *ps, *cstr = debugString(); + for(ps = cstr; *ps; ps++) { + if(*ps == '\n') { + *ps = 0; + dprintf(cstr); + cstr = ps+1; + } + } +#endif + +// RDebug::Print(_L("Stack dump:")); +// asm volatile ("str sp, %0" : "=m" (sp) ); +// for(TUint i = sp+0x400; i >= sp-16; i-=4) +// RDebug::Print(_L("%08x: %08x"), i, *(int *)i); + + // more descriptive replacement of "KERN-EXEC 3" panic + buff1.Format(_L("K-EX3: %S"), &ptrExc); + User::Panic(buff1, exc); +} + +#endif // ifdef __WINS__ + + +#if defined(__DEBUG_PRINT) || defined(__WINS__) + +#ifndef __DLL__ + // c string dumper for RDebug::Print() + static TBuf<1024> sTextBuffer; + TDesC* DO_CONV(const char* s) + { + TPtrC8 text8((TUint8*) (s)); + sTextBuffer.Copy(text8); + return &sTextBuffer; + } +#endif + +#ifdef __DEBUG_PRINT_C + #include // va_* + #include // vsprintf + + // debug print from c code + extern "C" void dprintf(char *format, ...) + { + va_list args; + char buffer[512]; + + va_start(args,format); + vsprintf(buffer,format,args); + va_end(args); + + DEBUGPRINT(_L("%S"), DO_CONV(buffer)); + } +#endif + +#ifdef __DEBUG_PRINT_FILE + #include + + //static RFile logFile; +// static TBool logInited = 0; + RMutex logMutex; + + static void debugPrintFileInit() + { + // try to open + logMutex.CreateLocal(); + RFs fserv; + fserv.Connect(); + RFile logFile; + logFile.Replace(fserv, _L("C:\\logs\\pico.log"), EFileWrite|EFileShareAny); + logFile.Close(); + fserv.Close(); + } + + // debug print to file + void debugPrintFile(TRefByValue aFmt, ...) + { + if (logMutex.Handle() <= 0) debugPrintFileInit(); + + logMutex.Wait(); + RFs fserv; + fserv.Connect(); + + TTime now; now.UniversalTime(); + TBuf<512> tmpBuff; + TBuf8<512> tmpBuff8; + TInt size, res; + + RThread thisThread; + RFile logFile; + res = logFile.Open(fserv, _L("C:\\logs\\pico.log"), EFileWrite|EFileShareAny); + if(res) goto fail1; + + logFile.Size(size); logFile.Seek(ESeekStart, size); + + now.FormatL(tmpBuff, _L("%H:%T:%S.%C: ")); + tmpBuff8.Copy(tmpBuff); + logFile.Write(tmpBuff8); + + tmpBuff8.Format(TPtr8((TUint8 *)"%03i: ", 6, 6), (TInt32) thisThread.Id()); + logFile.Write(tmpBuff8); + + VA_LIST args; + VA_START(args, aFmt); + tmpBuff.FormatList(aFmt, args); + VA_END(args); + tmpBuff8.Copy(tmpBuff); + logFile.Write(tmpBuff8); + + logFile.Write(TPtrC8((TUint8 const *) "\n")); + logFile.Flush(); + logFile.Close(); + fail1: + thisThread.Close(); + fserv.Close(); + + logMutex.Signal(); + } +#endif + +#endif + diff --git a/platform/uiq3/engine/debug.h b/platform/uiq3/engine/debug.h new file mode 100644 index 00000000..bcd82875 --- /dev/null +++ b/platform/uiq3/engine/debug.h @@ -0,0 +1,27 @@ +#include + +#define __DEBUG_PRINT_C +#define __DEBUG_PRINT_FILE + +#if defined(__DEBUG_PRINT) || defined(__WINS__) + #include // RDebug + #ifdef __DEBUG_PRINT_FILE + void debugPrintFile(TRefByValue aFmt, ...); + #define DEBUGPRINT debugPrintFile + #else + #define DEBUGPRINT RDebug::Print + #endif + TDesC* DO_CONV(const char* s); + #ifdef __DEBUG_PRINT_C + #ifdef __cplusplus + extern "C" + #endif + void dprintf(char *format, ...); + #endif +#else + #define DEBUGPRINT(x...) + #undef __DEBUG_PRINT_C + #undef __DEBUG_PRINT_FILE +#endif + +void ExceptionHandler(TExcType exc); diff --git a/platform/uiq3/engine/main.cpp b/platform/uiq3/engine/main.cpp new file mode 100644 index 00000000..93ef0470 --- /dev/null +++ b/platform/uiq3/engine/main.cpp @@ -0,0 +1,999 @@ +// mainloop with window server event handling +// event polling mechnism was taken from +// Peter van Sebille's projects + +// (c) Copyright 2006, notaz +// All Rights Reserved + +#include +#include +#include +#include + +#include +#include +#include + +#include "debug.h" +#include "../Engine.h" + +#include "../../../pico/picoInt.h" +#include "vid.h" +#include "polledAS.h" +//#include "audio.h" +#include "audio_mediaserver.h" + +#include +#include "../../../zlib/gzio_symb.h" + + +//#define BENCHMARK + + +// scancodes we care about +enum TUsedScanCodes { + EStdKeyM600JogUp = EStdKeyDevice1, + EStdKeyM600JogDown = EStdKeyDevice2, +}; + +static unsigned char keyFlags[256]; // lsb->msb: key_down, pulse_only, ?, ?, ?, ?, not_configurable, disabled +static unsigned char pressedKeys[11]; // List of pressed key scancodes, up to 10 + +// list of areas +TPicoAreaConfigEntry areaConfig[] = { + { TRect( 0, 0, 0, 0) }, + // small corner bottons + { TRect( 0, 0, 15, 15) }, + { TRect(224, 0, 239, 15) }, + { TRect( 0, 304, 15, 319) }, + { TRect(224, 304, 239, 319) }, + // normal buttons + { TRect( 0, 0, 79, 63) }, + { TRect( 80, 0, 159, 63) }, + { TRect(160, 0, 239, 63) }, + { TRect( 0, 64, 79, 127) }, + { TRect( 80, 64, 159, 127) }, + { TRect(160, 64, 239, 127) }, + { TRect( 0, 128, 79, 191) }, + { TRect( 80, 128, 159, 191) }, + { TRect(160, 128, 239, 191) }, + { TRect( 0, 192, 79, 255) }, + { TRect( 80, 192, 159, 255) }, + { TRect(160, 192, 239, 255) }, + { TRect( 0, 256, 79, 319) }, + { TRect( 80, 256, 159, 319) }, + { TRect(160, 256, 239, 319) }, + { TRect( 0, 0, 0, 0) } +}; + +// PicoPad[] format: SACB RLDU +const char *actionNames[] = { + "UP", "DOWN", "LEFT", "RIGHT", "B", "C", "A", "START", + 0, 0, 0, 0, 0, 0, 0, 0, // Z, Y, X, MODE (enabled only when needed), ?, ?, ?, ? + 0, 0, 0, 0, "VOLUME@UP", "VOLUME@DOWN", "NEXT@SAVE@SLOT", "PREV@SAVE@SLOT", // ?, ?, ?, ?, vol_up, vol_down, next_slot, prev_slot + 0, 0, "PAUSE@EMU", "SAVE@STATE", "LOAD@STATE", 0, 0, "DONE" // ?, switch_renderer, [...], "FRAMESKIP@8", "AUTO@FRAMESKIP" +}; + + +// globals are allowed, so why not to (ab)use them? +//TInt machineUid = 0; +int gamestate = PGS_Paused, gamestate_next = PGS_Paused; +TPicoConfig *currentConfig = 0; +static char noticeMsg[64]; // notice msg to draw +static timeval noticeMsgTime = { 0, 0 }; // when started showing +static CGameAudioMS *gameAudio = 0; // the audio object itself +static int reset_timing, pico_was_reset; +static int state_slot = 0; +extern const char *RomFileName; +extern RSemaphore initSemaphore; +extern RSemaphore pauseSemaphore; + +// some forward declarations +static void MainInit(); +static void MainExit(); +static void DumpMemInfo(); +void MainOldCleanup(); + + +class TPicoDirectScreenAccess : public MDirectScreenAccess +{ +public: // implements MDirectScreenAccess + void Restart(RDirectScreenAccess::TTerminationReasons aReason); +public: // implements MAbortDirectScreenAccess + void AbortNow(RDirectScreenAccess::TTerminationReasons aReason); +}; + + +// just for a nicer grouping of WS related stuff +class CGameWindow +{ +public: + static void ConstructResourcesL(void); + static void FreeResources(void); + static void DoKeys(void); + static void DoKeysConfig(TUint &which); + static void RunEvents(TUint32 which); + + static RWsSession* iWsSession; + static RWindowGroup iWsWindowGroup; + static RWindow iWsWindow; + static CWsScreenDevice* iWsScreen; + static CWindowGc* iWindowGc; + static TRequestStatus iWsEventStatus; +// static TThreadId iLauncherThreadId; +// static RDirectScreenAccess* iDSA; +// static TRequestStatus iDSAstatus; + static TPicoDirectScreenAccess iPDSA; + static CDirectScreenAccess* iDSA; +}; + + +static int snd_excess_add = 0, snd_excess_cnt = 0; // hack + +static void updateSound(void) +{ + int len = PsndLen; + + snd_excess_cnt += snd_excess_add; + if (snd_excess_cnt >= 0x10000) { + snd_excess_cnt -= 0x10000; + if (PicoOpt&8) { + PsndOut[len*2] = PsndOut[len*2-2]; + PsndOut[len*2+1] = PsndOut[len*2-1]; + } else { + PsndOut[len] = PsndOut[len-1]; + } + len++; + } + + PsndOut = gameAudio->NextFrameL(len); + if(!PsndOut) { // sound output problems? + strcpy(noticeMsg, "SOUND@OUTPUT@ERROR;@SOUND@DISABLED"); + gettimeofday(¬iceMsgTime, 0); + } +} + + +static void SkipFrame(void) +{ + PicoSkipFrame=1; + PicoFrame(); + PicoSkipFrame=0; +} + + +static void simpleWait(int thissec, int lim_time) +{ + struct timeval tval; + int sleep = 0; + + gettimeofday(&tval, 0); + if(thissec != tval.tv_sec) tval.tv_usec+=1000000; + + sleep = lim_time - tval.tv_usec - 2000; + if (sleep > 0) { +// User::After((sleep = lim_time - tval.tv_usec)); + User::AfterHighRes(sleep); + } +} + + +static void TargetEpocGameL() +{ + char buff[24]; // fps count c string + struct timeval tval; // timing + int thissec = 0, frames_done = 0, frames_shown = 0; + int target_fps, target_frametime; + int i, lim_time; + //TRawEvent blevent; + + MainInit(); + buff[0] = 0; + + // just to keep the backlight on (works only on UIQ2) + //blevent.Set(TRawEvent::EActive); + + // loop? + for(;;) { + if(gamestate == PGS_Running) { + // switch context to other thread + User::After(50000); + // prepare window and stuff + CGameWindow::ConstructResourcesL(); + + // if the system has something to do, it should better do it now + User::After(50000); + //CPolledActiveScheduler::Instance()->Schedule(); + + // pal/ntsc might have changed, reset related stuff + if(Pico.m.pal) { + target_fps = 50; + if(!noticeMsgTime.tv_sec) strcpy(noticeMsg, "PAL@SYSTEM@/@50@FPS"); + } else { + target_fps = 60; + if(!noticeMsgTime.tv_sec) strcpy(noticeMsg, "NTSC@SYSTEM@/@60@FPS"); + } + target_frametime = 1000000/target_fps; + if(!noticeMsgTime.tv_sec && pico_was_reset) + gettimeofday(¬iceMsgTime, 0); + + if (PsndOut) { + snd_excess_cnt = 0; + snd_excess_add = ((PsndRate - PsndLen*target_fps)<<16) / target_fps; + } + + pico_was_reset = 0; + reset_timing = 1; + + while(gamestate == PGS_Running) { + gettimeofday(&tval, 0); + if(reset_timing) { + reset_timing = 0; + thissec = tval.tv_sec; + frames_done = tval.tv_usec/target_frametime; + } + + // show notice message? + char *notice = 0; + if(noticeMsgTime.tv_sec) { + if((tval.tv_sec*1000000+tval.tv_usec) - (noticeMsgTime.tv_sec*1000000+noticeMsgTime.tv_usec) > 2000000) // > 2.0 sec + noticeMsgTime.tv_sec = noticeMsgTime.tv_usec = 0; + else notice = noticeMsg; + } + + // second changed? + if(thissec != tval.tv_sec) { +#ifdef BENCHMARK + static int bench = 0, bench_fps = 0, bench_fps_s = 0, bfp = 0, bf[4]; + if(++bench == 10) { + bench = 0; + bench_fps_s = bench_fps; + bf[bfp++ & 3] = bench_fps; + bench_fps = 0; + } + bench_fps += frames_shown; + sprintf(buff, "%02i/%02i/%02i", frames_shown, bench_fps_s, (bf[0]+bf[1]+bf[2]+bf[3])>>2); +#else + if(currentConfig->iFlags & 2) + sprintf(buff, "%02i/%02i", frames_shown, frames_done); +#endif + + + thissec = tval.tv_sec; + + if(PsndOut == 0 && currentConfig->iFrameskip >= 0) { + frames_done = frames_shown = 0; + } else { + // it is quite common for this implementation to leave 1 fame unfinished + // when second changes, but we don't want buffer to starve. + if(PsndOut && frames_done < target_fps && frames_done > target_fps-5) { + SkipFrame(); frames_done++; + } + + frames_done -= target_fps; if (frames_done < 0) frames_done = 0; + frames_shown -= target_fps; if (frames_shown < 0) frames_shown = 0; + if (frames_shown > frames_done) frames_shown = frames_done; + } + } + + + lim_time = (frames_done+1) * target_frametime; + if(currentConfig->iFrameskip >= 0) { // frameskip enabled + for(i = 0; i < currentConfig->iFrameskip; i++) { + CGameWindow::DoKeys(); + SkipFrame(); frames_done++; + if (PsndOut) { // do framelimitting if sound is enabled + gettimeofday(&tval, 0); + if(thissec != tval.tv_sec) tval.tv_usec+=1000000; + if(tval.tv_usec < lim_time) { // we are too fast + simpleWait(thissec, lim_time); + } + } + lim_time += target_frametime; + } + } else if(tval.tv_usec > lim_time) { // auto frameskip + // no time left for this frame - skip + CGameWindow::DoKeys(); + SkipFrame(); frames_done++; + continue; + } + + CGameWindow::DoKeys(); + PicoFrame(); + + // check time + gettimeofday(&tval, 0); + if(thissec != tval.tv_sec) tval.tv_usec+=1000000; + + // sleep if we are still too fast + if(PsndOut != 0 || currentConfig->iFrameskip < 0) + { + // TODO: check if User::After() is accurate + gettimeofday(&tval, 0); + if(thissec != tval.tv_sec) tval.tv_usec+=1000000; + if(tval.tv_usec < lim_time) + { + // we are too fast + simpleWait(thissec, lim_time); + } + } + + CPolledActiveScheduler::Instance()->Schedule(); + + if (gamestate != PGS_Paused) + vidDrawFrame(notice, buff, frames_shown); + + frames_done++; frames_shown++; + } + + // save SRAM + if((currentConfig->iFlags & 1) && SRam.changed) { + saveLoadGame(0, 1); + SRam.changed = 0; + } + CGameWindow::FreeResources(); + } else if(gamestate == PGS_Paused) { + DEBUGPRINT(_L("pausing..")); + pauseSemaphore.Wait(); + } else if(gamestate == PGS_KeyConfig) { + // switch context to other thread + User::After(50000); + // prepare window and stuff + CGameWindow::ConstructResourcesL(); + + TUint whichAction = 0; + while(gamestate == PGS_KeyConfig) { + CGameWindow::DoKeysConfig(whichAction); + CPolledActiveScheduler::Instance()->Schedule(); + if (gamestate != PGS_Paused) + vidKeyConfigFrame(whichAction); + User::After(150000); + } + + CGameWindow::FreeResources(); + } else if(gamestate == PGS_DebugHeap) { + #ifdef __DEBUG_PRINT + TInt cells = User::CountAllocCells(); + TInt mem; + User::AllocSize(mem); + DEBUGPRINT(_L("worker: cels=%d, size=%d KB"), cells, mem/1024); + gamestate = gamestate_next; + #endif + } else if(gamestate == PGS_Quit) { + break; + } + } + + MainExit(); +} + + +// main initialization +static void MainInit() +{ + DEBUGPRINT(_L("\r\n\r\nstarting..")); + + // our thread might have been crashed previously, so many other objects may be still floating around + MainOldCleanup(); + + DEBUGPRINT(_L("CPolledActiveScheduler::NewL()")); + CPolledActiveScheduler::NewL(); // create Polled AS for the sound engine + +// HAL::Get(HALData::EMachineUid, machineUid); // find out the machine UID + + DumpMemInfo(); + + // try to start pico + DEBUGPRINT(_L("PicoInit();")); + PicoInit(); + PicoDrawSetColorFormat(2); + PicoWriteSound = updateSound; + +// if (pauseSemaphore.Handle() <= 0) +// pauseSemaphore.CreateLocal(0); + DEBUGPRINT(_L("initSemaphore.Signal()")); + initSemaphore.Signal(); +} + + +// does not return +static void MainExit() +{ + RThread thisThread; + + DEBUGPRINT(_L("%i: cleaning up.."), (TInt32) thisThread.Id()); + + // save SRAM + if((currentConfig->iFlags & 1) && SRam.changed) { + saveLoadGame(0, 1); + SRam.changed = 0; + } + + PicoExit(); +// pauseSemaphore.Close(); + + if(gameAudio) delete gameAudio; + + // Polled AS + delete CPolledActiveScheduler::Instance(); +} + +void MainOldCleanup() +{ + DEBUGPRINT(_L("MainOldCleanup..")); + + // There was previously a handle leak here, so thread stuff was not cleaned + // and I thought I would have to do it mself. + + // clean any resources which might be left after a thread crash + //CGameWindow::FreeResources(ETrue); + + //if(CPolledActiveScheduler::Instance()) + // delete CPolledActiveScheduler::Instance(); +} + +static void DumpMemInfo() +{ + TInt ramSize, ramSizeFree, romSize; + + HAL::Get(HALData::EMemoryRAM, ramSize); + HAL::Get(HALData::EMemoryRAMFree, ramSizeFree); + HAL::Get(HALData::EMemoryROM, romSize); + + DEBUGPRINT(_L("ram=%dKB, ram_free=%dKB, rom=%dKB"), ramSize/1024, ramSizeFree/1024, romSize/1024); +} + + +TInt EmuThreadFunction(TAny*) +{ + const TUint32 exs = KExceptionAbort|KExceptionKill|KExceptionUserInterrupt|KExceptionFpe|KExceptionFault|KExceptionInteger|KExceptionDebug; + + DEBUGPRINT(_L("EmuThreadFunction()")); + User::SetExceptionHandler(ExceptionHandler, exs/*(TUint32) -1*/); // does not work? + + //TInt pc, sp; + //asm volatile ("str pc, %0" : "=m" (pc) ); + //asm volatile ("str sp, %0" : "=m" (sp) ); + //RDebug::Print(_L("executing @ 0x%08x, sp=0x%08x"), pc, sp); + +/* + RDebug::Print(_L("Base Bottom Top Size RW Name")); + TBuf<4> l_r(_L("R")), l_w(_L("W")), l_d(_L("-")); + RChunk chunk; + TFullName chunkname; + TFindChunk findChunk(_L("*")); + while( findChunk.Next(chunkname) != KErrNotFound ) { + chunk.Open(findChunk); + RDebug::Print(_L("%08x %08x %08x %08x %S%S %S"), chunk.Base(), chunk.Base()+chunk.Bottom(), chunk.Base()+chunk.Top(), chunk.Size(), chunk.IsReadable() ? &l_r : &l_d, chunk.IsWritable() ? &l_w : &l_d, &chunkname); + chunk.Close(); + } +*/ + + // can't do that, will crash here +// if(cleanup) { +// DEBUGPRINT(_L("found old CTrapCleanup, deleting..")); +// delete cleanup; +// } + + CTrapCleanup *cleanup = CTrapCleanup::New(); + + TRAPD(error, TargetEpocGameL()); + + __ASSERT_ALWAYS(!error, User::Panic(_L("Picosmall"), error)); + delete cleanup; + + DEBUGPRINT(_L("exitting..")); + return 1; +} + + +void TPicoDirectScreenAccess::Restart(RDirectScreenAccess::TTerminationReasons aReason) +{ + DEBUGPRINT(_L("TPicoDirectScreenAccess::Restart(%i)"), aReason); + +// if (CGameWindow::iDSA) { +// TRAPD(error, CGameWindow::iDSA->StartL()); +// if (error) DEBUGPRINT(_L("iDSA->StartL() error: %i"), error); +// } +} + + +void TPicoDirectScreenAccess::AbortNow(RDirectScreenAccess::TTerminationReasons aReason) +{ + DEBUGPRINT(_L("TPicoDirectScreenAccess::AbortNow(%i)"), aReason); + + // the WS wants us to stop, so let's obey + gamestate = PGS_Paused; +} + + +void CGameWindow::ConstructResourcesL() +{ + DEBUGPRINT(_L("ConstructResourcesL()")); + // connect to window server + // tried to create it globally and not re-connect everytime, + // but my window started to lose focus strangely + iWsSession = new(ELeave) RWsSession(); + User::LeaveIfError(iWsSession->Connect()); + + // * Tell the Window Server not to mess about with our process priority + // * Also, because of the way legacy games are written, they never sleep + // * and thus never voluntarily yield the CPU. We set our process priority + // * to EPriorityForeground and hope that a Telephony application on + // * this device runs at EPriorityForeground as well. If not, tough! ;-) + + iWsSession->ComputeMode(RWsSession::EPriorityControlDisabled); + RProcess me; + me.SetPriority(EPriorityForeground); + + iWsScreen = new(ELeave) CWsScreenDevice(*iWsSession); + User::LeaveIfError(iWsScreen->Construct()); +// User::LeaveIfError(iWsScreen->CreateContext(iWindowGc)); + + iWsWindowGroup = RWindowGroup(*iWsSession); + User::LeaveIfError(iWsWindowGroup.Construct((TUint32)&iWsWindowGroup)); + //iWsWindowGroup.SetOrdinalPosition(0); + //iWsWindowGroup.SetName(KServerWGName); + iWsWindowGroup.EnableScreenChangeEvents(); // flip events (EEventScreenDeviceChanged) + iWsWindowGroup.EnableFocusChangeEvents(); // EEventFocusGroupChanged + iWsWindowGroup.SetOrdinalPosition(0, 1); // TInt aPos, TInt aOrdinalPriority + + iWsWindow=RWindow(*iWsSession); + User::LeaveIfError(iWsWindow.Construct(iWsWindowGroup, (TUint32)&iWsWindow)); + iWsWindow.SetSize(iWsScreen->SizeInPixels()); + iWsWindow.PointerFilter(EPointerFilterDrag, 0); + iWsWindow.SetPointerGrab(ETrue); + iWsWindow.SetVisible(ETrue); + iWsWindow.Activate(); + +#if 0 + // request access through RDirectScreenAccess api, but don't care about the result + // hangs? + RRegion *dsa_region = 0; + iDSA = new(ELeave) RDirectScreenAccess(*iWsSession); + if(iDSA->Construct() == KErrNone) + iDSA->Request(dsa_region, iDSAstatus, iWsWindow); + DEBUGPRINT(_L("DSA: %i"), dsa_region ? dsa_region->Count() : -1); +#endif + + TInt ret; + + // request access through CDirectScreenAccess + iDSA = CDirectScreenAccess::NewL(*iWsSession, *iWsScreen, iWsWindow, iPDSA); + + // now get the screenbuffer + TScreenInfoV01 screenInfo; + TPckg sI(screenInfo); + UserSvr::ScreenInfo(sI); + + if(!screenInfo.iScreenAddressValid) + User::Leave(KErrNotSupported); + + DEBUGPRINT(_L("framebuffer=0x%08x (%dx%d)"), screenInfo.iScreenAddress, + screenInfo.iScreenSize.iWidth, screenInfo.iScreenSize.iHeight); + + // vidInit + DEBUGPRINT(_L("vidInit()")); + ret = vidInit((void *)screenInfo.iScreenAddress, 0); + DEBUGPRINT(_L("vidInit() done (%i)"), ret); + + User::LeaveIfError(ret); + + memset(keyFlags, 0, 256); + keyFlags[EStdKeyM600JogUp] = keyFlags[EStdKeyM600JogDown] = 2; // add "pulse only" for jog up/down + keyFlags[EStdKeyOff] = 0x40; // not configurable + + // try to start the audio engine + static int PsndRate_old = 0, PicoOpt_old = 0, pal_old = 0; + + if(gamestate == PGS_Running && (currentConfig->iFlags & 4)) { + TInt err = 0; + if(PsndRate != PsndRate_old || (PicoOpt&11) != (PicoOpt_old&11) || Pico.m.pal != pal_old) { + // if rate changed, reset all enabled chips, else reset only those chips, which were recently enabled + //sound_reset(PsndRate != PsndRate_old ? PicoOpt : (PicoOpt&(PicoOpt^PicoOpt_old))); + sound_rerate(); + } + if(!gameAudio || PsndRate != PsndRate_old || ((PicoOpt&8) ^ (PicoOpt_old&8)) || Pico.m.pal != pal_old) { // rate or stereo or pal/ntsc changed + if(gameAudio) delete gameAudio; gameAudio = 0; + DEBUGPRINT(_L("starting audio: %i len: %i stereo: %i, pal: %i"), PsndRate, PsndLen, PicoOpt&8, Pico.m.pal); + TRAP(err, gameAudio = CGameAudioMS::NewL(PsndRate, (PicoOpt&8) ? 1 : 0, Pico.m.pal ? 50 : 60)); + } + if( gameAudio) { + TRAP(err, PsndOut = gameAudio->ResumeL()); + } + if(err) { + if(gameAudio) delete gameAudio; + gameAudio = 0; + PsndOut = 0; + strcpy(noticeMsg, "SOUND@STARTUP@FAILED"); + gettimeofday(¬iceMsgTime, 0); + } + PsndRate_old = PsndRate; + PicoOpt_old = PicoOpt; + pal_old = Pico.m.pal; + } else { + if(gameAudio) delete gameAudio; + gameAudio = 0; + PsndOut = 0; + } + + CPolledActiveScheduler::Instance()->Schedule(); + + // start key WS event polling + iWsSession->EventReady(&iWsEventStatus); + + iWsSession->Flush(); // check: short hang in UIQ2 + User::After(1); + + // I don't know why but the Window server sometimes hangs completely (hanging the phone too) after calling StartL() + // Is this a sync broblem? weird bug? + TRAP(ret, iDSA->StartL()); + if (ret) DEBUGPRINT(_L("iDSA->StartL() error: %i"), ret); + +// User::After(1); +// CPolledActiveScheduler::Instance()->Schedule(); + + DEBUGPRINT(_L("CGameWindow::ConstructResourcesL() finished.")); +} + +// this may be run even if there is nothing to free +void CGameWindow::FreeResources() +{ + if(gameAudio) gameAudio->Pause(); + + //DEBUGPRINT(_L("CPolledActiveScheduler::Instance(): %08x"), CPolledActiveScheduler::Instance()); + if(CPolledActiveScheduler::Instance()) + CPolledActiveScheduler::Instance()->Schedule(); + +#if 0 + // free RDirectScreenAccess stuff (seems to be deleted automatically after crash?) + if(iDSA) { + iDSA->Cancel(); + iDSA->Close(); + delete iDSA; + } + iDSA = NULL; +#endif + if(iDSA) delete iDSA; + iDSA = 0; + + if(iWsSession->WsHandle() > 0 && iWsEventStatus != KRequestPending) // TODO: 2 UIQ2 (?) + iWsSession->EventReadyCancel(); + + if(iWsWindow.WsHandle() > 0) + iWsWindow.Close(); + + if(iWsWindowGroup.WsHandle() > 0) + iWsWindowGroup.Close(); + + // these must be deleted before calling iWsSession->Close() + if(iWsScreen) { + delete iWsScreen; + iWsScreen = NULL; + } + + if(iWsSession->WsHandle() > 0) { + iWsSession->Close(); + delete iWsSession; + } + + vidFree(); + + // emu might change renderer by itself, so we may need to sync config + if(currentConfig && currentConfig->iPicoOpt != PicoOpt) { + currentConfig->iFlags |= 0x80; + } +} + + +void CGameWindow::DoKeys(void) +{ + TWsEvent iWsEvent; + TInt iWsEventType; + unsigned long allActions = 0; + static unsigned long areaActions = 0, forceUpdate = 0; + int i, nEvents; + + for(nEvents = 0; iWsEventStatus != KRequestPending; nEvents++) + { + iWsSession->GetEvent(iWsEvent); + iWsEventType = iWsEvent.Type(); + + // pointer events? + if(iWsEventType == EEventPointer) { + if(iWsEvent.Pointer()->iType == TPointerEvent::EButton1Up) { + areaActions = 0; // remove all directionals + } else { // if(iWsEvent.Pointer()->iType == TPointerEvent::EButton1Down) { + TPoint p = iWsEvent.Pointer()->iPosition; + const TPicoAreaConfigEntry *e = areaConfig + 1; + for(i = 0; !e->rect.IsEmpty(); e++, i++) + if(e->rect.Contains(p)) { + areaActions = currentConfig->iAreaBinds[i]; + break; + } + //DEBUGPRINT(_L("pointer event: %i %i"), p.iX, p.iY); + } + } + else if(iWsEventType == EEventKeyDown || iWsEventType == EEventKeyUp) { + TInt iScanCode = iWsEvent.Key()->iScanCode; + //DEBUGPRINT(_L("key event: 0x%02x"), iScanCode); + + if(iScanCode < 256) + { + if(iWsEventType == EEventKeyDown) { + keyFlags[iScanCode] |= 1; + for(i=0; i < 10; i++) { + if( pressedKeys[i] == (TUint8) iScanCode) break; + if(!pressedKeys[i]) { pressedKeys[i] = (TUint8) iScanCode; break; } + } + } else if(!(keyFlags[iScanCode]&2)) { + keyFlags[iScanCode] &= ~1; + for(i=0; i < 10; i++) { + if(pressedKeys[i] == (TUint8) iScanCode) { pressedKeys[i] = 0; break; } + } + } + + // power? + if(iScanCode == EStdKeyOff) gamestate = PGS_Paused; + } else { + DEBUGPRINT(_L("weird scancode: 0x%02x"), iScanCode); + } + } + else if(iWsEventType == EEventScreenDeviceChanged) { + // ??? + //User::After(500000); + //reset_timing = 1; + DEBUGPRINT(_L("EEventScreenDeviceChanged, focus: %i, our: %i"), + iWsSession->GetFocusWindowGroup(), iWsWindowGroup.Identifier()); + } + else if(iWsEventType == EEventFocusGroupChanged) { + TInt focusGrpId = iWsSession->GetFocusWindowGroup(); + DEBUGPRINT(_L("EEventFocusGroupChanged: %i, our: %i"), + focusGrpId, iWsWindowGroup.Identifier()); + // if it is not us and not launcher that got focus, pause emu + if(focusGrpId != iWsWindowGroup.Identifier()) + gamestate = PGS_Paused; + } + + iWsEventStatus = KRequestPending; + iWsSession->EventReady(&iWsEventStatus); + } + + if(nEvents || forceUpdate) { + allActions = areaActions; + forceUpdate = 0; + + // add all pushed button actions + for(i = 9; i >= 0; i--) { + int scan = pressedKeys[i]; + if(scan) { + if(keyFlags[scan] & 1) allActions |= currentConfig->iKeyBinds[scan]; + if((keyFlags[scan]& 3)==3) forceUpdate = 1; + if(keyFlags[scan] & 2) keyFlags[scan] &= ~1; + } + } + + PicoPad[0] = (unsigned short) allActions; + if(allActions & 0xFFFF0000) { + RunEvents(allActions >> 16); + areaActions = 0; + } + } +} + + +void CGameWindow::DoKeysConfig(TUint &which) +{ + TWsEvent iWsEvent; + int i; + + while(iWsEventStatus != KRequestPending) + { + TUint currentActCode = 1 << which; + + iWsSession->GetEvent(iWsEvent); + + // pointer events? + if(iWsEvent.Type() == EEventPointer) { + TPoint p = iWsEvent.Pointer()->iPosition; + TRect prev(56, 0, 120, 26); + TRect next(120, 0, 180, 26); + + if(iWsEvent.Pointer()->iType == TPointerEvent::EButton1Down) { + if(prev.Contains(p)) do { which = (which-1) & 0x1F; } while(!actionNames[which]); + else if(next.Contains(p)) do { which = (which+1) & 0x1F; } while(!actionNames[which]); + else if(which == 31) gamestate = PGS_Paused; // done + else { + const TPicoAreaConfigEntry *e = areaConfig + 1; + for(i = 0; e->rect != TRect(0,0,0,0); e++, i++) + if(e->rect.Contains(p)) { + currentConfig->iAreaBinds[i] ^= currentActCode; + break; + } + } + } + } + else if(iWsEvent.Type() == EEventKeyDown || iWsEvent.Type() == EEventKeyUp) + { + TUint scan = (TUint) iWsEvent.Key()->iScanCode; + + // key events? + if(iWsEvent.Type() == EEventKeyDown) { + if(which == 31) { + gamestate = PGS_Paused; + } else if (scan < 256) { + if(!(keyFlags[scan]&0x40)) currentConfig->iKeyBinds[scan] ^= currentActCode; + } + } + + // power? + if(iWsEvent.Key()->iScanCode == EStdKeyOff) gamestate = PGS_Paused; + } + else if(iWsEvent.Type() == EEventFocusGroupChanged) { + TInt focusGrpId = iWsSession->GetFocusWindowGroup(); + // if we lost focus, exit config mode + if(focusGrpId != iWsWindowGroup.Identifier()) + gamestate = PGS_Paused; + } + +// iWsEventStatus = KRequestPending; + iWsSession->EventReady(&iWsEventStatus); + } +} + + +void CGameWindow::RunEvents(TUint32 which) +{ + if(which & 0x4000) currentConfig->iFrameskip = -1; + if(which & 0x2000) currentConfig->iFrameskip = 8; + if(which & 0x1800) { // save or load (but not both) + if(PsndOut) gameAudio->Pause(); // this may take a while, so we pause sound output + + vidDrawNotice((which & 0x1000) ? "LOADING@GAME" : "SAVING@GAME"); + saveLoadGame(which & 0x1000); + + if(PsndOut) PsndOut = gameAudio->ResumeL(); + reset_timing = 1; + } + if(which & 0x0400) gamestate = PGS_Paused; + if(which & 0x0200) { // switch renderer + if(!(currentConfig->iScreenMode == TPicoConfig::PMFit && + (currentConfig->iScreenRotation == TPicoConfig::PRot0 || currentConfig->iScreenRotation == TPicoConfig::PRot180))) { + + PicoOpt^=0x10; + vidInit(0, 1); + + strcpy(noticeMsg, (PicoOpt&0x10) ? "ALT@RENDERER" : "DEFAULT@RENDERER"); + gettimeofday(¬iceMsgTime, 0); + } + } + if(which & 0x00c0) { + if(which&0x0080) { + state_slot -= 1; + if(state_slot < 0) state_slot = 9; + } else { + state_slot += 1; + if(state_slot > 9) state_slot = 0; + } + sprintf(noticeMsg, "SAVE@SLOT@%i@SELECTED", state_slot); + gettimeofday(¬iceMsgTime, 0); + } + if(which & 0x0020) if(gameAudio) gameAudio->ChangeVolume(0); + if(which & 0x0010) if(gameAudio) gameAudio->ChangeVolume(1); +} + + +// must use wrappers, or else will run into some weird loader error (see pico/area.c) +static size_t fRead2(void *p, size_t _s, size_t _n, void *file) +{ + return fread(p, _s, _n, (FILE *) file); +} + +static size_t fWrite2(void *p, size_t _s, size_t _n, void *file) +{ + return fwrite(p, _s, _n, (FILE *) file); +} + +static size_t gzRead2(void *p, size_t, size_t _n, void *file) +{ + return gzread(file, p, _n); +} + +static size_t gzWrite2(void *p, size_t, size_t _n, void *file) +{ + return gzwrite(file, p, _n); +} + + +// this function is shared between both threads +int saveLoadGame(int load, int sram) +{ + int res = 0; + + if(!RomFileName) return -1; + + // make save filename + char saveFname[KMaxFileName]; + strcpy(saveFname, RomFileName); + saveFname[KMaxFileName-8] = 0; + if(saveFname[strlen(saveFname)-4] == '.') saveFname[strlen(saveFname)-4] = 0; + if(sram) strcat(saveFname, ".srm"); + else { + if(state_slot > 0 && state_slot < 10) sprintf(saveFname, "%s.%i", saveFname, state_slot); + strcat(saveFname, ".mds"); + } + + DEBUGPRINT(_L("saveLoad (%i, %i): %S"), load, sram, DO_CONV(saveFname)); + + if(sram) { + FILE *sramFile; + int sram_size = SRam.end-SRam.start+1; + if(SRam.reg_back & 4) sram_size=0x2000; + if(!SRam.data) return 0; // SRam forcefully disabled for this game + if(load) { + sramFile = fopen(saveFname, "rb"); + if(!sramFile) return -1; + fread(SRam.data, 1, sram_size, sramFile); + fclose(sramFile); + } else { + // sram save needs some special processing + // see if we have anything to save + for(; sram_size > 0; sram_size--) + if(SRam.data[sram_size-1]) break; + + if(sram_size) { + sramFile = fopen(saveFname, "wb"); + res = fwrite(SRam.data, 1, sram_size, sramFile); + res = (res != sram_size) ? -1 : 0; + fclose(sramFile); + } + } + return res; + } else { + void *PmovFile = NULL; + // try gzip first + if(currentConfig->iFlags & 0x80) { + strcat(saveFname, ".gz"); + if( (PmovFile = gzopen(saveFname, load ? "rb" : "wb")) ) { + areaRead = gzRead2; + areaWrite = gzWrite2; + if(!load) gzsetparams(PmovFile, 9, Z_DEFAULT_STRATEGY); + } else + saveFname[strlen(saveFname)-3] = 0; + } + if(!PmovFile) { // gzip failed or was disabled + if( (PmovFile = fopen(saveFname, load ? "rb" : "wb")) ) { + areaRead = fRead2; + areaWrite = fWrite2; + } + } + if(PmovFile) { + PmovState(load ? 6 : 5, PmovFile); // load/save + strcpy(noticeMsg, load ? "GAME@LOADED" : "GAME@SAVED"); + if(areaRead == gzRead2) + gzclose(PmovFile); + else fclose ((FILE *) PmovFile); + PmovFile = 0; + if (load) Pico.m.dirtyPal=1; + } else { + strcpy(noticeMsg, load ? "LOAD@FAILED" : "SAVE@FAILED"); + res = -1; + } + + gettimeofday(¬iceMsgTime, 0); + return res; + } +} + +// static class members +RWsSession* CGameWindow::iWsSession; +RWindowGroup CGameWindow::iWsWindowGroup; +RWindow CGameWindow::iWsWindow; +CWsScreenDevice* CGameWindow::iWsScreen = NULL; +CWindowGc* CGameWindow::iWindowGc = NULL; +TRequestStatus CGameWindow::iWsEventStatus = KRequestPending; +//RDirectScreenAccess* CGameWindow::iDSA; +//TRequestStatus CGameWindow::iDSAstatus = KRequestPending; +TPicoDirectScreenAccess CGameWindow::iPDSA; +CDirectScreenAccess* CGameWindow::iDSA = NULL; + diff --git a/platform/uiq3/engine/polledas.cpp b/platform/uiq3/engine/polledas.cpp new file mode 100644 index 00000000..898f76e1 --- /dev/null +++ b/platform/uiq3/engine/polledas.cpp @@ -0,0 +1,269 @@ +/******************************************************************* + * + * File: PolledAS.cpp + * + * Author: Peter van Sebille (peter@yipton.net) + * + * (c) Copyright 2002, Peter van Sebille + * All Rights Reserved + * + *******************************************************************/ + +/* + * Oh Lord, forgive me for I have sinned. + * In their infinite wisdom, Symbian Engineers have decided that + * the Active Scheduler's queue of Active Objects is private + * and no getters are provided... sigh. + * This mere mortal will have to excercise the power of C pre-processor + * once more to circumvent the will of the gods. + */ + + +#include + +// from e32base.h +class CBase + { +public: + /** + Default constructor + */ + inline CBase() {} + IMPORT_C virtual ~CBase(); + inline TAny* operator new(TUint aSize, TAny* aBase) __NO_THROW { Mem::FillZ(aBase, aSize); return aBase; } + inline TAny* operator new(TUint aSize) __NO_THROW { return User::AllocZ(aSize); } + inline TAny* operator new(TUint aSize, TLeave) { return User::AllocZL(aSize); } + inline TAny* operator new(TUint aSize, TUint aExtraSize) { return User::AllocZ(aSize + aExtraSize); } + inline TAny* operator new(TUint aSize, TLeave, TUint aExtraSize) { return User::AllocZL(aSize + aExtraSize); } + IMPORT_C static void Delete(CBase* aPtr); +protected: + IMPORT_C virtual TInt Extension_(TUint aExtensionId, TAny*& a0, TAny* a1); +private: + CBase(const CBase&); + CBase& operator=(const CBase&); +private: + }; + + +class TRequestStatusFaked + { +public: + inline TRequestStatusFaked() : iFlags(0) {}; + inline TRequestStatusFaked(TInt aVal) : iStatus(aVal), iFlags(aVal==KRequestPending ? TRequestStatusFaked::ERequestPending : 0) {} +/* inline TInt operator=(TInt aVal); + inline TBool operator==(TInt aVal) const; +*/ + inline TBool operator!=(TInt aVal) const {return(iStatus!=aVal);} +/* + inline TBool operator>=(TInt aVal) const; + inline TBool operator<=(TInt aVal) const; + inline TBool operator>(TInt aVal) const; + inline TBool operator<(TInt aVal) const; + inline TInt Int() const; +private: +*/ + enum + { + EActive = 1, //bit0 + ERequestPending = 2, //bit1 + }; + TInt iStatus; + TUint iFlags; + friend class CActive; + friend class CActiveScheduler; + friend class CServer2; + }; + + +class CActive : public CBase + { +public: +enum TPriority + { + EPriorityIdle=-100, + EPriorityLow=-20, + EPriorityStandard=0, + EPriorityUserInput=10, + EPriorityHigh=20, + }; +public: + IMPORT_C ~CActive(); + IMPORT_C void Cancel(); + IMPORT_C void Deque(); + IMPORT_C void SetPriority(TInt aPriority); + inline TBool IsActive() const {return(iStatus.iFlags&TRequestStatus::EActive);} + inline TBool IsAdded() const {return(iLink.iNext!=NULL);} + inline TInt Priority() const {return iLink.iPriority;} +protected: + IMPORT_C CActive(TInt aPriority); + IMPORT_C void SetActive(); + virtual void DoCancel() =0; + virtual void RunL() =0; + IMPORT_C virtual TInt RunError(TInt aError); +protected: + IMPORT_C virtual TInt Extension_(TUint aExtensionId, TAny*& a0, TAny* a1); +public: + TRequestStatusFaked iStatus; // hope this will work +private: +// TBool iActive; + TPriQueLink iLink; + TAny* iSpare; + friend class CActiveScheduler; + friend class CServer; + friend class CServer2; + friend class CPrivatePolledActiveScheduler; // added + }; + + + +class CActiveScheduler : public CBase + { + friend class CActiveSchedulerWait; +public: + struct TLoop; + typedef TLoop* TLoopOwner; +public: + IMPORT_C CActiveScheduler(); + IMPORT_C ~CActiveScheduler(); + IMPORT_C static void Install(CActiveScheduler* aScheduler); + IMPORT_C static CActiveScheduler* Current(); + IMPORT_C static void Add(CActive* aActive); + IMPORT_C static void Start(); + IMPORT_C static void Stop(); + IMPORT_C static TBool RunIfReady(TInt& aError, TInt aMinimumPriority); + IMPORT_C static CActiveScheduler* Replace(CActiveScheduler* aNewActiveScheduler); + IMPORT_C virtual void WaitForAnyRequest(); + IMPORT_C virtual void Error(TInt aError) const; + IMPORT_C void Halt(TInt aExitCode) const; + IMPORT_C TInt StackDepth() const; +private: + static void Start(TLoopOwner* aOwner); + IMPORT_C virtual void OnStarting(); + IMPORT_C virtual void OnStopping(); + IMPORT_C virtual void Reserved_1(); + IMPORT_C virtual void Reserved_2(); + void Run(TLoopOwner* const volatile& aLoop); + void DoRunL(TLoopOwner* const volatile& aLoop, CActive* volatile & aCurrentObj); + friend class CPrivatePolledActiveScheduler; // added +protected: + IMPORT_C virtual TInt Extension_(TUint aExtensionId, TAny*& a0, TAny* a1); +protected: + inline TInt Level() const {return StackDepth();} // deprecated +private: + TLoop* iStack; + TPriQue iActiveQ; + TAny* iSpare; + }; + + + +class TCleanupItem; +class CleanupStack + { +public: + IMPORT_C static void PushL(TAny* aPtr); + IMPORT_C static void PushL(CBase* aPtr); + IMPORT_C static void PushL(TCleanupItem anItem); + IMPORT_C static void Pop(); + IMPORT_C static void Pop(TInt aCount); + IMPORT_C static void PopAndDestroy(); + IMPORT_C static void PopAndDestroy(TInt aCount); + IMPORT_C static void Check(TAny* aExpectedItem); + inline static void Pop(TAny* aExpectedItem); + inline static void Pop(TInt aCount, TAny* aLastExpectedItem); + inline static void PopAndDestroy(TAny* aExpectedItem); + inline static void PopAndDestroy(TInt aCount, TAny* aLastExpectedItem); + }; + + +/* + * This will declare CPrivatePolledActiveScheduler as a friend + * of all classes that define a friend. CPrivatePolledActiveScheduler needs to + * be a friend of CActive + */ +//#define friend friend class CPrivatePolledActiveScheduler; friend + + +/* + * This will change the: + * void DoStart(); + * method in CActiveScheduler to: + * void DoStart(); friend class CPrivatePolledActiveScheduler; + * We need this to access the private datamembers in CActiveScheduler. + */ +//#define DoStart() DoStart(); friend class CPrivatePolledActiveScheduler; +//#include +#include "PolledAS.h" + + +class CPrivatePolledActiveScheduler : public CActiveScheduler +{ +public: + void Schedule(); +}; + + +void CPrivatePolledActiveScheduler::Schedule() +{ + TDblQueIter q(iActiveQ); + q.SetToFirst(); + FOREVER + { + CActive *pR=q++; + if (pR) + { + //TRequestStatus::EActive = 1, //bit0 + //TRequestStatus::ERequestPending = 2, //bit1 + if (pR->IsActive() && pR->iStatus!=KRequestPending) + { +// pR->iActive=EFalse; // won't this cause trouble? + pR->iStatus.iFlags&=~TRequestStatusFaked::EActive; + //debugPrintFile(_L("as: %08x"), pR); + TRAPD(r,pR->RunL()); + //pR->iStatus=TRequestStatus::ERequestPending; + break; + } + } + else + break; + } +} + + +static CPolledActiveScheduler* sPolledActiveScheduler = NULL; + +CPolledActiveScheduler::~CPolledActiveScheduler() +{ + sPolledActiveScheduler = NULL; + delete iPrivatePolledActiveScheduler; +} + +CPolledActiveScheduler* CPolledActiveScheduler::NewL() +{ + // if (sPolledActiveScheduler == NULL) + { + sPolledActiveScheduler = new(ELeave)CPolledActiveScheduler; + CleanupStack::PushL(sPolledActiveScheduler); + sPolledActiveScheduler->ConstructL(); + CleanupStack::Pop(); + } + return sPolledActiveScheduler; +} + +void CPolledActiveScheduler::ConstructL() +{ + iPrivatePolledActiveScheduler = new(ELeave) CPrivatePolledActiveScheduler; + iPrivatePolledActiveScheduler->Install(iPrivatePolledActiveScheduler); +} + + +void CPolledActiveScheduler::Schedule() +{ + iPrivatePolledActiveScheduler->Schedule(); +} + +CPolledActiveScheduler* CPolledActiveScheduler::Instance() +{ +// return (CPolledActiveScheduler*) CActiveScheduler::Current(); + return sPolledActiveScheduler; +} diff --git a/platform/uiq3/engine/vid.cpp b/platform/uiq3/engine/vid.cpp new file mode 100644 index 00000000..308b10b0 --- /dev/null +++ b/platform/uiq3/engine/vid.cpp @@ -0,0 +1,645 @@ +// EmuScan routines for Pico, also simple text and shape drawing routines. + +// (c) Copyright 2006, notaz +// All Rights Reserved + +#include "vid.h" +#include "../Engine.h" +#include "../../../pico/picoInt.h" +#include "blit.h" +#include "debug.h" + + +// global stuff +extern TPicoConfig *currentConfig; +extern TPicoAreaConfigEntry areaConfig[]; +extern const char *actionNames[]; + +// main framebuffer +static void *screenbuff = 0; // pointer to real device video memory +//static +extern "C" { unsigned char *framebuff = 0; } // temporary buffer +const int framebuffsize = (8+320)*(8+240+8)*2+8*2; // actual framebuffer size (in bytes+to support new rendering mode) + +// drawer function pointers +static void (*drawTextFps)(const char *text) = 0; +static void (*drawTextNotice)(const char *text) = 0; + +// blitter +static void (*vidBlit)(int full) = 0; + +// colors +const unsigned short color_red = 0x022F; +const unsigned short color_red_dim = 0x0004; +const unsigned short color_green = 0x01F1; +const unsigned short color_blue = 0x0F11; +const unsigned short color_grey = 0x0222; + +// other +int txtheight_fit = 138; + +// bitmasks +static const unsigned long mask_numbers[] = { + 0x12244800, // 47 2F / + 0x69999600, // 48 30 0 + 0x26222200, // 49 31 1 + 0x69168F00, // 50 32 2 + 0x69219600, // 51 33 3 + 0x266AF200, // 52 34 4 + 0xF8E11E00, // 53 35 5 + 0x68E99600, // 54 36 6 + 0x71222200, // 55 37 7 + 0x69699600, // 56 38 8 + 0x69719600, // 57 39 9 + 0x04004000, // 58 3A : + 0x04004400, // 59 3B ; + 0x01242100, // 60 3C < + 0x00707000, // 61 3D = + 0x04212400, // 62 3E > + 0x69240400, // 63 3F ? + 0x00000000, // 64 40 @ [used instead of space for now] + 0x22579900, // 65 41 A + 0xE9E99E00, // 66 42 B + 0x69889600, // 67 43 C + 0xE9999E00, // 68 44 D + 0xF8E88F00, // 69 45 E + 0xF8E88800, // 70 46 F + 0x698B9700, // 71 47 G + 0x99F99900, // 72 48 H + 0x44444400, // 73 49 I + 0x11119600, // 74 4A J + 0x9ACCA900, // 75 4B K + 0x88888F00, // 76 4C L + 0x9F999900, // 77 4D M + 0x9DDBB900, // 78 4E N + 0x69999600, // 79 4F O + 0xE99E8800, // 80 50 P + 0x6999A500, // 81 51 Q + 0xE99E9900, // 82 52 R + 0x69429600, // 83 53 S + 0x72222200, // 84 54 T + 0x99999600, // 85 55 U + 0x55552200, // 86 56 V + 0x9999F900, // 87 57 W + 0x55225500, // 88 58 X + 0x55222200, // 89 59 Y + 0xF1248F00, // 90 5A Z +}; + + +//////////////////////////////// +// Cram functions + +static int EmuCramNull(int cram) +{ + User::Panic(_L("Cram called!!"), 0); + return cram; +} + + +//////////////////////////////// +// PicoScan functions + +static int EmuScan8(unsigned int num, void *sdata) +{ + DrawLineDest = framebuff + 328*(num+1) + 328*8 + 8; + + return 0; +} + + +static int EmuScanFit0(unsigned int num, void *sdata) +{ + // 0.75, 168 lines + + static int u = 0, num2 = 0; + if(!num) u = num2 = 0; + + DrawLineDest = framebuff + 328*(++num2) + 328*8 + 8; + + u += 6666; + + if(u < 10000) { +// u += 7500; + return 1; + } + + u -= 10000; + + return 0; +} + + +//////////////////////////////// +// text drawers +// warning: text must be at least 1px away from screen borders + +static void drawTextM2(int x, int y, const char *text) +{ + unsigned char *vidmem = framebuff + 328*8 + 8; + int charmask, i, cx = x, cy; + unsigned char *l, *le; + + // darken the background (left border) + for(l=vidmem+(cx-1)+(y-1)*328, le=l+8*328; l < le; l+=328) *l = 0xE0; + + for(const char *p=text; *p; p++) { + cy = y; + charmask = *(mask_numbers + (*p - 0x2F)); + + for(l = vidmem+cx+(y-1)*328, le = l+8*328; l < le; l+=328-4) { + *l = 0xE0; l++; *l = 0xE0; l++; + *l = 0xE0; l++; *l = 0xE0; l++; + *l = 0xE0; + } + + for(i=0; i < 24; i++) { + if(charmask&0x80000000) *( vidmem + (cx+(i&3)) + (cy+(i>>2))*328 ) = 0xf0; + charmask <<= 1; + } + cx += 5; + } +} + + +static void drawTextM2Fat(int x, int y, const char *text) +{ + unsigned char *vidmem = framebuff + 328*8 + 8; + int charmask, i, cx = x&~1, cy; + unsigned short *l, *le; + + // darken the background (left border) + for(l=(unsigned short *)(vidmem+(cx-2)+(y-1)*328), le=l+8*328/2; l < le; l+=328/2) *l = 0xE0; + + for(const char *p=text; *p; p++) { + cy = y; + for(l = (unsigned short *)(vidmem+cx+(y-1)*328), le = l+8*328/2; l < le; l+=328/2) { + l += 4; + *l-- = 0xe0e0; *l-- = 0xe0e0; *l-- = 0xe0e0; *l-- = 0xe0e0; *l = 0xe0e0; + } + + charmask = *(mask_numbers + (*p - 0x2F)); + + for(i=0; i < 24; i++) { + if(charmask&0x80000000) *(unsigned short *)( vidmem + cx+(i&3)*2 + (cy+(i>>2))*328 ) = 0xf0f0; + charmask <<= 1; + } + cx += 5*2; + } +} + + +static void drawTextFpsCenter0(const char *text) +{ + if(!text) return; + drawTextM2(214, 216, text); +} + +static void drawTextFpsFit0(const char *text) +{ + if(!text) return; + drawTextM2Fat((Pico.video.reg[12]&1) ? 256-32 : 224-32, 160, text); +} + +static void drawTextFpsFit2_0(const char *text) +{ + if(!text) return; + drawTextM2Fat((Pico.video.reg[12]&1) ? 256-32 : 224-32, 216, text); +} + +static void drawTextFps0(const char *text) +{ + if(!text) return; + drawTextM2((Pico.video.reg[12]&1) ? 256 : 224, 216, text); +} + +static void drawTextNoticeCenter0(const char *text) +{ + if(!text) return; + drawTextM2(2, 216, text); +} + +static void drawTextNoticeFit0(const char *text) +{ + if(!text) return; + drawTextM2Fat(2, 160, text); +} + +static void drawTextNoticeFit2_0(const char *text) +{ + if(!text) return; + drawTextM2Fat(2, 216, text); +} + +static void drawTextNotice0(const char *text) +{ + if(!text) return; + drawTextM2(2, 216, text); +} + + +// ----------------------------------------------------------------- + +static int localPal[0x100]; + +static void fillLocalPal(void) +{ + Pico.m.dirtyPal = 0; + + if (PicoOpt&0x10) { + // 8bit fast renderer + vidConvCpyRGB32(localPal, Pico.cram, 0x40); + return; + } + + // 8bit accurate renderer + if(Pico.video.reg[0xC]&8) { // shadow/hilight mode + vidConvCpyRGB32(localPal, Pico.cram, 0x40); + vidConvCpyRGB32sh(localPal+0x40, Pico.cram, 0x40); + vidConvCpyRGB32hi(localPal+0x80, Pico.cram, 0x40); + blockcpy(localPal+0xc0, localPal+0x40, 0x40*4); + localPal[0xe0] = 0x00000000; // reserved pixels for OSD + localPal[0xf0] = 0x00ee0000; + } else if (rendstatus & 0x20) { // mid-frame palette changes + vidConvCpyRGB32(localPal, Pico.cram, 0x40); + vidConvCpyRGB32(localPal+0x40, HighPal, 0x40); + vidConvCpyRGB32(localPal+0x80, HighPal+0x40, 0x40); + } else { + vidConvCpyRGB32(localPal, Pico.cram, 0x40); + } +} + + +// note: the internal 8 pixel border is taken care by asm code +static void vidBlit_90(int full) +{ + unsigned char *ps = framebuff+328*8; + unsigned long *pd = (unsigned long *) screenbuff; + + if (Pico.m.dirtyPal) fillLocalPal(); + + if(Pico.video.reg[12]&1) + vidConvCpy_90(pd, ps, localPal, 320/8); + else { + if(full) vidClear(pd, 32); + pd += 256*32; + vidConvCpy_90(pd, ps, localPal, 256/8); + if(full) vidClear(pd + 256*256, 32); + } +} + + +static void vidBlit_270(int full) +{ + unsigned char *ps = framebuff+328*8; + unsigned long *pd = (unsigned long *) screenbuff; + + if (Pico.m.dirtyPal) fillLocalPal(); + + if(Pico.video.reg[12]&1) + vidConvCpy_270(pd, ps, localPal, 320/8); + else { + if(full) vidClear(pd, 32); + pd += 256*32; + ps -= 64; // the blitter starts copying from the right border, so we need to adjust + vidConvCpy_270(pd, ps, localPal, 256/8); + if(full) vidClear(pd + 256*256, 32); + } +} + + +static void vidBlitCenter_0(int full) +{ + unsigned char *ps = framebuff+328*8+8; + unsigned long *pd = (unsigned long *) screenbuff; + + if (Pico.m.dirtyPal) fillLocalPal(); + + if(Pico.video.reg[12]&1) ps += 32; + vidConvCpy_center_0(pd, ps, localPal); + if(full) vidClear(pd + 224*256, 96); +} + + +static void vidBlitCenter_180(int full) +{ + unsigned char *ps = framebuff+328*8+8; + unsigned long *pd = (unsigned long *) screenbuff; + + if (Pico.m.dirtyPal) fillLocalPal(); + + if(Pico.video.reg[12]&1) ps += 32; + vidConvCpy_center_180(pd, ps, localPal); + if(full) vidClear(pd + 224*256, 96); +} + + +static void vidBlitFit_0(int full) +{ + if (Pico.m.dirtyPal) fillLocalPal(); + + if(Pico.video.reg[12]&1) + vidConvCpy_center2_40c_0(screenbuff, framebuff+328*8, localPal, 168); + else vidConvCpy_center2_32c_0(screenbuff, framebuff+328*8, localPal, 168); + if(full) vidClear((unsigned long *)screenbuff + 168*256, 320-168); +} + + +static void vidBlitFit_180(int full) +{ + if (Pico.m.dirtyPal) fillLocalPal(); + + if(Pico.video.reg[12]&1) + vidConvCpy_center2_40c_180(screenbuff, framebuff+328*8, localPal, 168); + else vidConvCpy_center2_32c_180(screenbuff, framebuff+328*8-64, localPal, 168); + if(full) vidClear((unsigned long *)screenbuff + 168*256, 320-168); +} + + +static void vidBlitFit2_0(int full) +{ + if (Pico.m.dirtyPal) fillLocalPal(); + + if(Pico.video.reg[12]&1) + vidConvCpy_center2_40c_0(screenbuff, framebuff+328*8, localPal, 224); + else vidConvCpy_center2_32c_0(screenbuff, framebuff+328*8, localPal, 224); + if(full) vidClear((unsigned long *)screenbuff + 224*256, 96); +} + + +static void vidBlitFit2_180(int full) +{ + if (Pico.m.dirtyPal) fillLocalPal(); + + if(Pico.video.reg[12]&1) + vidConvCpy_center2_40c_180(screenbuff, framebuff+328*8, localPal, 224); + else vidConvCpy_center2_32c_180(screenbuff, framebuff+328*8-64, localPal, 224); + if(full) vidClear((unsigned long *)screenbuff + 224*256, 96); +} + + +static void vidBlitCfg(void) +{ + unsigned short *ps = (unsigned short *) framebuff; + unsigned long *pd = (unsigned long *) screenbuff; + int i; + + // hangs randomly (due to repeated ldms/stms?) + //for (int i = 1; i < 320; i++, ps += 240, pd += 256) + // vidConvCpyRGB32(pd, ps, 240); + + for (i = 0; i < 320; i++, pd += 16) + for (int u = 0; u < 240; u++, ps++, pd++) + *pd = ((*ps & 0xf) << 20) | ((*ps & 0xf0) << 8) | ((*ps & 0xf00) >> 4); +} + + +//////////////////////////////// +// main functions + +int vidInit(void *vidmem, int reinit) +{ + if(!reinit) { + // prepare framebuffer + screenbuff = vidmem; + framebuff = (unsigned char *) malloc(framebuffsize); + + if(!screenbuff) return KErrNotSupported; + if(!framebuff) return KErrNoMemory; + + memset(framebuff, 0, framebuffsize); + + // Cram function: go and hack Pico so it never gets called + PicoCram = EmuCramNull; + } + + // select suitable blitters + vidBlit = vidBlit_270; + PicoScan = EmuScan8; + drawTextFps = drawTextFps0; + drawTextNotice = drawTextNotice0; + + memset(localPal, 0, 0x100*4); + localPal[0xe0] = 0x00000000; // reserved pixels for OSD + localPal[0xf0] = 0x00ee0000; + + // setup all orientation related stuff + if(currentConfig->iScreenRotation == TPicoConfig::PRot0) { + if(currentConfig->iScreenMode == TPicoConfig::PMCenter) { + vidBlit = vidBlitCenter_0; + drawTextFps = drawTextFpsCenter0; + drawTextNotice = drawTextNoticeCenter0; + } else if(currentConfig->iScreenMode == TPicoConfig::PMFit2) { + vidBlit = vidBlitFit2_0; + drawTextFps = drawTextFpsFit2_0; + drawTextNotice = drawTextNoticeFit2_0; + } else { + vidBlit = vidBlitFit_0; + drawTextFps = drawTextFpsFit0; + drawTextNotice = drawTextNoticeFit0; + PicoScan = EmuScanFit0; + } + } else if(currentConfig->iScreenRotation == TPicoConfig::PRot90) { + vidBlit = vidBlit_90; + } else if(currentConfig->iScreenRotation == TPicoConfig::PRot180) { + if(currentConfig->iScreenMode == TPicoConfig::PMCenter) { + vidBlit = vidBlitCenter_180; + drawTextFps = drawTextFpsCenter0; + drawTextNotice = drawTextNoticeCenter0; + } else if(currentConfig->iScreenMode == TPicoConfig::PMFit2) { + vidBlit = vidBlitFit2_180; + drawTextFps = drawTextFpsFit2_0; + drawTextNotice = drawTextNoticeFit2_0; + } else { + vidBlit = vidBlitFit_180; + drawTextFps = drawTextFpsFit0; + drawTextNotice = drawTextNoticeFit0; + PicoScan = EmuScanFit0; + } + } else if(currentConfig->iScreenRotation == TPicoConfig::PRot270) { + vidBlit = vidBlit_270; + } + + vidBlit(1); + PicoOpt |= 0x100; + Pico.m.dirtyPal = 1; + + return 0; +} + +void vidFree() +{ + free(framebuff); + framebuff = 0; +} + +void vidDrawFrame(char *noticeStr, char *fpsStr, int num) +{ + DrawLineDest = framebuff + 328*8 + 8; + +// PicoFrame(); // moved to main loop + if(currentConfig->iFlags & 2) + drawTextFps(fpsStr); + drawTextNotice(noticeStr); + + vidBlit(!num); // copy full frame once a second +} + +// ----------------------------------------------------------------- + +static void drawText0(int x, int y, const char *text, long color) +{ + unsigned short *vidmem=(unsigned short *)framebuff; + int charmask, i, cx = x, cy; + unsigned short *l, *le, dmask=0x0333; + + // darken the background (left border) + for(l=vidmem+(cx-1)+(y-1)*240, le=vidmem+(cx-1)+(y+7)*240; l < le; l+=240) + *l = (*l >> 2) & dmask; + + for(const char *p=text; *p; p++) { + cy = y; + charmask = *(mask_numbers + (*p - 0x2F)); + + for(l = vidmem+cx+(y-1)*240, le = vidmem+cx+(y+7)*240; l < le; l+=240-4) { + *l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++; + *l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++; + *l = (*l >> 2) & dmask; + } + + for(i=0; i < 24; i++) { + // draw dot. Is this fast? + if(charmask&0x80000000) *( vidmem + (cx+(i&3)) + (cy+(i>>2))*240 ) = color; + charmask <<= 1; + } + cx += 5; + } +} + +// draws rect with width - 1 and height - 1 +static void drawRect(const TRect &rc, unsigned short color) +{ + unsigned short *vidmem=(unsigned short *)framebuff; + + if(rc.iTl.iX - rc.iBr.iX && rc.iTl.iY - rc.iBr.iY) { + int stepX = rc.iTl.iX < rc.iBr.iX ? 1 : -1; + int stepY = rc.iTl.iY < rc.iBr.iY ? 1 : -1; + + for(int x = rc.iTl.iX;; x += stepX) { + *(vidmem + rc.iTl.iY*240 + x) = *(vidmem + (rc.iBr.iY - stepY)*240 + x) = color; + if(x == rc.iBr.iX - stepX) break; + } + + for(int y = rc.iTl.iY;; y += stepY) { + *(vidmem + y*240 + rc.iTl.iX) = *(vidmem + y*240 + rc.iBr.iX - stepX) = color; + if(y == rc.iBr.iY - stepY) break; + } + } +} + +// draws fullsize filled rect +static void drawRectFilled(const TRect rc, unsigned short color) +{ + unsigned short *vidmem=(unsigned short *)framebuff; + + if(rc.iTl.iX - rc.iBr.iX && rc.iTl.iY - rc.iBr.iY) { + int stepX = rc.iTl.iX < rc.iBr.iX ? 1 : -1; + int stepY = rc.iTl.iY < rc.iBr.iY ? 1 : -1; + + for(int y = rc.iTl.iY;; y += stepY) { + for(int x = rc.iTl.iX;; x += stepX) { + *(vidmem + y*240 + x) = *(vidmem + y*240 + x) = color; + if(x == rc.iBr.iX) break; + } + if(y == rc.iBr.iY) break; + } + } +} + +// direction: -1 left, 1 right +static void drawArrow0(TPoint p, int direction, unsigned short color) +{ + unsigned short *vidmem=(unsigned short *)framebuff; + int width = 15; + int x = p.iX; + int y = p.iY; + + for(; width > 0; x+=direction, y++, width -=2) + for(int i=0; i < width; i++) + *(vidmem + x + y*240 + i*240) = color; +} + +static char *vidGetScanName(int scan) +{ + static char buff[32]; + + if((scan >= '0' && scan <= '9') || (scan >= 'A' && scan <= 'Z')) { + buff[0] = (char) scan; buff[1] = 0; + } else { + switch(scan) { + case 0x01: strcpy(buff, "BSPACE"); break; + case 0x03: strcpy(buff, "OK"); break; + case 0x05: strcpy(buff, "SPACE"); break; + case 0x0e: strcpy(buff, "AST"); break; + case 0x0f: strcpy(buff, "HASH"); break; + case 0x12: strcpy(buff, "SHIFT"); break; + case 0x19: strcpy(buff, "ALT"); break; + case 0x79: strcpy(buff, "PLUS"); break; + case 0x7a: strcpy(buff, "DOT"); break; + case 0xa5: strcpy(buff, "JOG@UP"); break; + case 0xa6: strcpy(buff, "JOG@DOWN"); break; + case 0xb5: strcpy(buff, "INET"); break; + case 0xd4: strcpy(buff, "JOG@PUSH"); break; + case 0xd5: strcpy(buff, "BACK"); break; + default: sprintf(buff, "KEY@%02X", scan); break; + } + } + + return buff; +} + +void vidKeyConfigFrame(const TUint whichAction) +{ + int i; + char buttonNames[128]; + buttonNames[0] = 0; + memset(framebuff, 0, framebuffsize); + + unsigned long currentActCode = 1 << whichAction; + + // draw all "buttons" in reverse order + const TPicoAreaConfigEntry *e = areaConfig + 1; i = 0; + while(e->rect != TRect(0,0,0,0)) { e++; i++; } + for(e--, i--; e->rect != TRect(0,0,0,0); e--, i--) + drawRect(e->rect, (currentConfig->iAreaBinds[i] & currentActCode) ? color_red : color_red_dim); + + // action name control + drawRectFilled(TRect(72, 2, 168, 20), color_grey); // 96x14 + drawArrow0(TPoint(80, 3), -1, color_green); + drawArrow0(TPoint(160, 3), 1, color_green); + + drawText0(86, 9, actionNames[whichAction], color_red); + + // draw active button names if there are any + for(i = 0; i < 256; i++) { + if(currentConfig->iKeyBinds[i] & currentActCode) { + if(buttonNames[0]) strcat(buttonNames, ";@"); + strcat(buttonNames, vidGetScanName(i)); + } + } + + if(buttonNames[0]) { + buttonNames[61] = 0; // only 60 chars fit + drawText0(6, 48, buttonNames, color_blue); + } + + vidBlitCfg(); +} + +void vidDrawNotice(const char *txt) +{ + if(framebuff) { + drawTextNotice(txt); + vidBlit(1); + } +} diff --git a/platform/uiq3/engine/vid.h b/platform/uiq3/engine/vid.h new file mode 100644 index 00000000..d6b89959 --- /dev/null +++ b/platform/uiq3/engine/vid.h @@ -0,0 +1,9 @@ +#include + +// let's do it in more c-like way +int vidInit(void *vidmem, int reinit); +void vidFree(); +void vidDrawFrame(char *noticeStr, char *fpsStr, int num); +void vidKeyConfigFrame(const TUint whichAction); +void vidDrawFCconfigDone(); +void vidDrawNotice(const char *txt); // safe to call anytime, draws text for 1 frame diff --git a/platform/uiq3/makezip.cmd b/platform/uiq3/makezip.cmd new file mode 100644 index 00000000..2aea7722 --- /dev/null +++ b/platform/uiq3/makezip.cmd @@ -0,0 +1,3 @@ +@cd _out +@"C:\Program Files\arch\WinRAR\WinRAR.exe" a PicoDrive.zip PicoDrive.SIS config.txt ..\..\readme.txt +@cd.. diff --git a/platform/uiq3/port_config.h b/platform/uiq3/port_config.h new file mode 100644 index 00000000..0478ce4b --- /dev/null +++ b/platform/uiq3/port_config.h @@ -0,0 +1,25 @@ +// port specific settings + +#ifndef PORT_CONFIG_H +#define PORT_CONFIG_H + +#define CPU_CALL + +// draw2.c +#define START_ROW 0 // which row of tiles to start rendering at? +#define END_ROW 28 // ..end + +// pico.c +#define CAN_HANDLE_240_LINES 0 // fow now + +//#define dprintf(f,...) printf(f"\n",##__VA_ARGS__) +#ifdef __DEBUG_PRINT +#ifdef __cplusplus +extern "C" +#endif +void dprintf(char *format, ...); +#else +#define dprintf(x...) +#endif + +#endif //PORT_CONFIG_H diff --git a/platform/uiq3/port_config.s b/platform/uiq3/port_config.s new file mode 100644 index 00000000..bc0f97fe --- /dev/null +++ b/platform/uiq3/port_config.s @@ -0,0 +1,8 @@ +@ .equiv START_ROW, 1 +@ .equiv END_ROW, 27 +@ one row means 8 pixels. If above example was used, (27-1)*8=208 lines would be rendered. +.equiv START_ROW, 0 +.equiv END_ROW, 28 + +@ this should be set to one only for GP2X port +.equiv EXTERNAL_YM2612, 0 diff --git a/platform/uiq3/qconn.cmd b/platform/uiq3/qconn.cmd new file mode 100644 index 00000000..429b196e --- /dev/null +++ b/platform/uiq3/qconn.cmd @@ -0,0 +1 @@ +@..\..\..\qconsole-1.60\qtty-1.60\release\qtty --qc-addr M600i --qc-channel 5 --user qconsole --pass server \ No newline at end of file diff --git a/platform/uiq3/qlog.cmd b/platform/uiq3/qlog.cmd new file mode 100644 index 00000000..c9e15423 --- /dev/null +++ b/platform/uiq3/qlog.cmd @@ -0,0 +1 @@ +@..\..\..\qconsole-1.60\qtty-1.60\release\qtty --qc-addr M600i --qc-channel 5 --user qconsole --pass server --cmds "cat c:\logs\pico.log" exit diff --git a/platform/uiq3/qup.cmd b/platform/uiq3/qup.cmd new file mode 100644 index 00000000..de5594ad --- /dev/null +++ b/platform/uiq3/qup.cmd @@ -0,0 +1 @@ +@..\..\..\qconsole-1.60\qtty-1.60\release\qtty --qc-addr M600i --qc-channel 5 --user qconsole --pass server --cmds "put c:\Shared\PicoDrive.SIS _out\PicoDrive.SIS" "rundoc c:\Shared\PicoDrive.SIS" exit diff --git a/platform/uiq3/rsc/Pico18x18.bmp b/platform/uiq3/rsc/Pico18x18.bmp new file mode 100644 index 00000000..840c55a3 Binary files /dev/null and b/platform/uiq3/rsc/Pico18x18.bmp differ diff --git a/platform/uiq3/rsc/Pico18x18m.bmp b/platform/uiq3/rsc/Pico18x18m.bmp new file mode 100644 index 00000000..734d6408 Binary files /dev/null and b/platform/uiq3/rsc/Pico18x18m.bmp differ diff --git a/platform/uiq3/rsc/Pico40x40.bmp b/platform/uiq3/rsc/Pico40x40.bmp new file mode 100644 index 00000000..81ad7e71 Binary files /dev/null and b/platform/uiq3/rsc/Pico40x40.bmp differ diff --git a/platform/uiq3/rsc/Pico40x40m.bmp b/platform/uiq3/rsc/Pico40x40m.bmp new file mode 100644 index 00000000..32a75ef5 Binary files /dev/null and b/platform/uiq3/rsc/Pico40x40m.bmp differ diff --git a/platform/uiq3/rsc/Pico64x64.bmp b/platform/uiq3/rsc/Pico64x64.bmp new file mode 100644 index 00000000..3e357161 Binary files /dev/null and b/platform/uiq3/rsc/Pico64x64.bmp differ diff --git a/platform/uiq3/rsc/Pico64x64m.bmp b/platform/uiq3/rsc/Pico64x64m.bmp new file mode 100644 index 00000000..83a1857f Binary files /dev/null and b/platform/uiq3/rsc/Pico64x64m.bmp differ diff --git a/platform/uiq3/rsc/PicoDrive.rss b/platform/uiq3/rsc/PicoDrive.rss new file mode 100644 index 00000000..6bbef7cc --- /dev/null +++ b/platform/uiq3/rsc/PicoDrive.rss @@ -0,0 +1,601 @@ +NAME PCDR + +#include +#include +#include +#include +#include "picodrive.hrh" + + +RESOURCE RSS_SIGNATURE { } + +// Defines the name of the default file the application framework creates. +// This resource must always be the second resource in the resource file. +RESOURCE TBUF { buf = "PicoDrive"; } + +RESOURCE EIK_APP_INFO { } + + +// A view shall use the QIK_VIEW_CONFIGURATIONS resource struct to define which +// UI configurations it supports. Can also use QIK_VIEW_CONFIGURATIONS to setup +// the view to switch layout and command list automatically when changes of UI +// configuration occur. This is done with the view and command_list members of +// the QIK_VIEW_CONFIGURATIONS. +// The application supports the reference UI Configurations that are supported +// in the UIQ 3 SDK. Use the UiqEnv tool, to change the UI Configuration in the +// emulator in order to develop and test the application with varying phone styles. +RESOURCE QIK_VIEW_CONFIGURATIONS r_app_ui_configurations +{ + configurations = + { + QIK_VIEW_CONFIGURATION + { + ui_config_mode = KQikPenStyleTouchPortrait; + command_list = r_app_commands; + view = r_app_layout; + }, + QIK_VIEW_CONFIGURATION + { + ui_config_mode = KQikPenStyleTouchLandscape; + command_list = r_app_commands; + view = r_app_layout; + }, + QIK_VIEW_CONFIGURATION + { + ui_config_mode = KQikSoftkeyStyleTouchPortrait; + command_list = r_app_commands; + view = r_app_layout; + }, + QIK_VIEW_CONFIGURATION + { + ui_config_mode = KQikSoftkeyStylePortrait; + command_list = r_app_commands; + view = r_app_layout; + }, + QIK_VIEW_CONFIGURATION + { + ui_config_mode = KQikSoftkeyStyleSmallPortrait; + command_list = r_app_commands; + view = r_app_layout; + } + }; +} + +// Commands are defined with the QIK_COMMAND_LIST struct, +// commands can also be created in code by instantiating CQikCommand. +// The control command id for debug command is a reserved id from uikon.hrh. +// The id for each command is defined in the .hrh file. +RESOURCE QIK_COMMAND_LIST r_app_commands +{ + items = + { +// QIK_COMMAND { id=EEikCmdPicoMain; text="Main"; type=EQikCommandTypeDone; namedGroupLinkId=EEikCmdPicoMain; }, +// QIK_COMMAND { id=EEikCmdPicoDebugInfo; text="Debug info"; type=EQikCommandTypeScreen; stateFlags=EQikCmdFlagDebugOnly; }, + QIK_COMMAND { id=EEikCmdPicoFrameskip; text="Frameskip"; type=EQikCommandTypeScreen; namedGroupLinkId=EEikCmdPicoFrameskip; }, + QIK_COMMAND { id=EEikCmdPicoFrameskipAuto; text="Auto"; type=EQikCommandTypeScreen; namedGroupId=EEikCmdPicoFrameskip; + groupId=EEikCmdPicoFrameskip; stateFlags=EQikCmdFlagRadioStart; }, + QIK_COMMAND { id=EEikCmdPicoFrameskip0; text="0"; type=EQikCommandTypeScreen; namedGroupId=EEikCmdPicoFrameskip; + groupId=EEikCmdPicoFrameskip0; stateFlags=EQikCmdFlagRadioMiddle; }, + QIK_COMMAND { id=EEikCmdPicoFrameskip1; text="1"; type=EQikCommandTypeScreen; namedGroupId=EEikCmdPicoFrameskip; + groupId=EEikCmdPicoFrameskip0; stateFlags=EQikCmdFlagRadioMiddle; }, + QIK_COMMAND { id=EEikCmdPicoFrameskip2; text="2"; type=EQikCommandTypeScreen; namedGroupId=EEikCmdPicoFrameskip; + groupId=EEikCmdPicoFrameskip0; stateFlags=EQikCmdFlagRadioMiddle; }, + QIK_COMMAND { id=EEikCmdPicoFrameskip4; text="4"; type=EQikCommandTypeScreen; namedGroupId=EEikCmdPicoFrameskip; + groupId=EEikCmdPicoFrameskip0; stateFlags=EQikCmdFlagRadioMiddle; }, + QIK_COMMAND { id=EEikCmdPicoFrameskip8; text="8"; type=EQikCommandTypeScreen; namedGroupId=EEikCmdPicoFrameskip; + groupId=EEikCmdPicoFrameskip0; stateFlags=EQikCmdFlagRadioEnd; }, + QIK_COMMAND { id=EEikCmdPicoConfig; text="Configure"; type=EQikCommandTypeScreen; namedGroupLinkId=EEikCmdPicoConfig; }, + QIK_COMMAND { id=EEikCmdPicoKeys; text="Keys"; type=EQikCommandTypeScreen; namedGroupId=EEikCmdPicoConfig; }, + QIK_COMMAND { id=EEikCmdPicoSettings; text="Settings"; type=EQikCommandTypeScreen; namedGroupId=EEikCmdPicoConfig; }, + QIK_COMMAND { id=EEikCmdHelpAbout; text="About"; type=EQikCommandTypeScreen; namedGroupId=EEikCmdPicoConfig; }, + + QIK_COMMAND { id=EEikCmdPicoLoadROM; text="Load new ROM"; type=EQikCommandTypeScreen; groupId=EEikCmdPicoResume; }, + QIK_COMMAND { id=EEikCmdPicoReset; text="Reset game"; type=EQikCommandTypeScreen; groupId=EEikCmdPicoResume; }, + QIK_COMMAND { id=EEikCmdPicoLoadState; text="Load state"; type=EQikCommandTypeScreen; groupId=EEikCmdPicoResume; }, + QIK_COMMAND { id=EEikCmdPicoSaveState; text="Save state"; type=EQikCommandTypeScreen; groupId=EEikCmdPicoResume; }, + QIK_COMMAND { id=EEikCmdPicoResume; text="Resume game"; type=EQikCommandTypeScreen; groupId=EEikCmdPicoResume; cpfFlags=EQikCpfFlagIsDefault; }, + + QIK_COMMAND { id=EEikCmdExit; text="Exit"; type=EQikCommandTypeScreen; groupId=EEikCmdExit; } + }; +} + + +// Defines the view by linking to the pages. +RESOURCE QIK_VIEW r_app_layout +{ + pages = {}; +} + + +/************************************** + * + * config dialog + * + **************************************/ + +RESOURCE DIALOG r_pico_config +{ + title = "Settings"; + buttons = R_EIK_BUTTONS_CANCEL_OK; + flags = EEikDialogFlagWait; + pages = r_pico_config_pages; +} + +RESOURCE ARRAY r_pico_config_pages +{ + items = { + PAGE + { + id = ECtlOptPageMain; + text = "Main"; + lines = r_pico_config_page_main; + }, + PAGE + { + id = ECtlOptPageSound; + text = "Sound"; + lines = r_pico_config_page_sound; + }, + PAGE + { + id = ECtlOptPageMisc; + text = "Misc"; + lines = r_pico_config_page_misc; + } + }; +} + + +RESOURCE ARRAY r_pico_config_page_main +{ + items = { + DLG_LINE + { + id = ECtlOptRotationLabel; + type = EEikCtLabel; + prompt = "Screen Rotation"; + control = LABEL { horiz_align = EEikLabelAlignHLeft; }; + }, + DLG_LINE + { + id = ECtlOptRotation; + type = EEikCtHorOptionButList; + control = HOROPBUT + { + array_id = r_pico_config_rotation_buttons; + }; + }, + DLG_LINE + { + id = ECtlOptScreenModeLabel; + type = EEikCtLabel; + prompt = "Screen Mode"; + control = LABEL { horiz_align = EEikLabelAlignHLeft; }; + }, + DLG_LINE + { + id = ECtlOptScreenMode; + type = EEikCtHorOptionButList; + control = HOROPBUT + { + array_id = r_pico_config_screenmode_buttons; + }; + }, + DLG_LINE + { + id = ECtlOptUseAltRend; + type = EEikCtCheckBox; + prompt = "Fast renderer (inaccurate)"; + }, + DLG_LINE + { + id = ECtlOptUseAccTiming; + type = EEikCtCheckBox; + prompt = "Accurate timing (slower)"; + }, + DLG_LINE + { + id = ECtlOptUseAccSprites; + type = EEikCtCheckBox; + prompt = "Accurate sprites (slower)"; + }, + DLG_LINE + { + id = ECtlOptShowFPS; + type = EEikCtCheckBox; + prompt = "Show FPS"; + } + }; +} + + +RESOURCE ARRAY r_pico_config_page_sound +{ + items = { + DLG_LINE + { + id = ECtlOptEnableSound; + type = EEikCtCheckBox; + prompt = "Enable sound"; + }, + DLG_LINE + { + id = ECtlOptChipSelLabel; + type = EEikCtLabel; + prompt = "Emulate these sound chips:"; + control = LABEL { horiz_align = EEikLabelAlignHLeft; }; + }, + DLG_LINE + { + id = ECtlOptEmulateZ80; + type = EEikCtCheckBox; + prompt = "Z80"; + }, + DLG_LINE + { + id = ECtlOptEmulateYM2612; + type = EEikCtCheckBox; + prompt = "YM2612"; + }, + DLG_LINE + { + id = ECtlOptEmulateSN76496; + type = EEikCtCheckBox; + prompt = "SN76496 (PSG)"; + }, + DLG_LINE + { + id = ECtlOptSndQLabel; + type = EEikCtLabel; + prompt = "Quality (lowest is fastest)"; + control = LABEL { horiz_align = EEikLabelAlignHLeft; }; + }, + DLG_LINE + { + id = ECtlOptSndQuality; + type = EEikCtChoiceList; + prompt = ""; + control = CHOICELIST { array_id = r_pico_config_snd_quality; }; + itemflags = EEikDlgItemNonFocusing; + } + }; +} + + +RESOURCE ARRAY r_pico_config_page_misc +{ + items = { + DLG_LINE + { + id = ECtlOpt6ButtonPad; + type = EEikCtCheckBox; + prompt = "6 button pad"; + }, + DLG_LINE + { + id = ECtlOptGzipStates; + type = EEikCtCheckBox; + prompt = "gzip save states"; + }, + DLG_LINE + { + id = ECtlOptUseSRAM; + type = EEikCtCheckBox; + prompt = "Use SRAM saves (.srm)"; + }, + DLG_LINE + { + id = ECtlOptRegion; + type = EEikCtChoiceList; + prompt = "Region:"; + control = CHOICELIST { array_id = r_pico_config_region; }; + itemflags = EEikDlgItemNonFocusing; + } + }; +} + + +RESOURCE ARRAY r_pico_config_rotation_buttons +{ + items = { + OPBUT { id = ECtlOptRotation0; text = "0º"; }, + OPBUT { id = ECtlOptRotation90; text = "90º"; }, + OPBUT { id = ECtlOptRotation180; text = "180º"; }, + OPBUT { id = ECtlOptRotation270; text = "270º"; } + }; +} + + +RESOURCE ARRAY r_pico_config_screenmode_buttons +{ + items = { + OPBUT { id = ECtlOptScreenModeCenter; text = "Center"; }, + OPBUT { id = ECtlOptScreenModeFit; text = "Fit"; }, + OPBUT { id = ECtlOptScreenModeFit2; text = "Fit2"; } + }; +} + + +RESOURCE ARRAY r_pico_config_snd_quality +{ + items = { + LBUF { txt = "8000Hz mono"; }, + LBUF { txt = "11025Hz mono"; }, + LBUF { txt = "16000Hz mono"; }, + LBUF { txt = "22050Hz mono"; }, + LBUF { txt = "44100Hz mono"; }, + LBUF { txt = "8000Hz stereo"; }, + LBUF { txt = "11025Hz stereo"; }, + LBUF { txt = "16000Hz stereo"; }, + LBUF { txt = "22050Hz stereo"; }, + LBUF { txt = "44100Hz stereo"; } + }; +} + + +RESOURCE ARRAY r_pico_config_region +{ + items = { + LBUF { txt = "Auto"; }, + LBUF { txt = "Europe"; }, + LBUF { txt = "USA"; }, + LBUF { txt = "Japan PAL"; }, + LBUF { txt = "Japan NTSC"; } + }; +} + + +/************************************** + * + * about dialog + * + **************************************/ + +// A simple dialog shall use the QIK_DIALOG resource struct to +// define which UI configurations it supports. +RESOURCE QIK_DIALOG r_pico_about +{ + title = "About"; + configurations = + { + QIK_DIALOG_CONFIGURATION + { + ui_config_mode = 0; + container = r_pico_about_container; + command_list = r_pico_about_commands; + } + }; + controls = r_pico_about_controls; +} + +RESOURCE QIK_COMMAND_LIST r_pico_about_commands +{ + items= + { + QIK_COMMAND + { + id = EEikCmdPicoAboutDoneCmd; + type = EQikCommandTypeDone; + text = "Done"; + }, + QIK_COMMAND + { + id = EEikCmdPicoAboutCreditsCmd; + type = EQikCommandTypeItem; + text = "Credits"; + } + }; +} + +// A collection of controls that can be used throughout the various +// view/container/building block structs by using the unique handle in +// QIK_CONTROL. So you can specify how the control should be created here and +// just reference to it from other places. +RESOURCE QIK_CONTROL_COLLECTION r_pico_about_controls +{ + items = + { + QIK_CONTROL + { + unique_handle = ECtlPicoAboutText; + type = EEikCtRichTextEditor; + control = r_pico_about_rtxted; + itemflags = EQikCtrlFlagIsEditInPlace; + } + }; +} + +// the controls themselves +RESOURCE RTXTED r_pico_about_rtxted +{ + flags = EEikEdwinDisplayOnly|EEikEdwinReadOnly|EEikEdwinNoHorizScrolling; + numlines = 13; + displayMode = 1; // EDisplayModeView; +} + +// Defines the content of the simple dialog and how they are laid out. +// Default layout manager is used for laying out the controls, which is a row +// layout. +RESOURCE QIK_CONTAINER_SETTINGS r_pico_about_container +{ + controls = + { + QIK_CONTAINER_ITEM_CI_LI + { + type = EQikCtOnelineBuildingBlock; + control = r_pico_about_bb1; + } + }; +} + +// Building block that contains the label. +RESOURCE QIK_SYSTEM_BUILDING_BLOCK r_pico_about_bb1 +{ + content = + { + QIK_SLOT_CONTENT + { + slot_id = EQikItemSlot1; + unique_handle = ECtlPicoAboutText; + } + }; +} + +RESOURCE TBUF r_pico_text_about +{ + buf= + "PicoDrive"\ + "

for UIQ3"\ + "

Version %S, by notaz."\ + "

Port based on UIQ2 version, which is based on PicoDrive 0.030 for Pocket PC by Dave"\ + "

Email: notasas@gmail.com"\ + "

Web: http://notaz.atspace.com"\ + "

Dave's Web: http://www.finalburn.com"; +} + +/************************************** + * + * credits dialog + * + **************************************/ + +// A simple dialog shall use the QIK_DIALOG resource struct to +// define which UI configurations it supports. +RESOURCE QIK_DIALOG r_pico_credits +{ + title = "Credits and thanks"; + configurations = + { + QIK_DIALOG_CONFIGURATION + { + ui_config_mode = 0; + container = r_pico_credits_container; + command_list = r_pico_credits_commands; + } + }; + controls = r_pico_credits_controls; +} + +RESOURCE QIK_COMMAND_LIST r_pico_credits_commands +{ + items= + { + QIK_COMMAND + { + id = EEikCmdPicoAboutDoneCmd; + type = EQikCommandTypeDone; + text = "Done"; + } + }; +} + +// A collection of controls that can be used throughout the various +// view/container/building block structs by using the unique handle in +// QIK_CONTROL. So you can specify how the control should be created here and +// just reference to it from other places. +RESOURCE QIK_CONTROL_COLLECTION r_pico_credits_controls +{ + items = + { + QIK_CONTROL + { + unique_handle = ECtlPicoCreditsText; + type = EEikCtEdwin; + control = r_pico_credits_edwin; + itemflags = EQikCtrlFlagIsEditInPlace; + } + }; +} + +// the controls themselves +RESOURCE EDWIN r_pico_credits_edwin +{ + flags = EEikEdwinDisplayOnly|EEikEdwinReadOnly|EEikEdwinNoHorizScrolling|EEikEdwinDisableAutoCurEnd; + lines = 11; +} + +// Defines the content of the simple dialog and how they are laid out. +// Default layout manager is used for laying out the controls, which is a row +// layout. +RESOURCE QIK_CONTAINER_SETTINGS r_pico_credits_container +{ + controls = + { + QIK_CONTAINER_ITEM_CI_LI + { + type = EQikCtOnelineBuildingBlock; + control = r_pico_credits_bb1; + } + }; +} + +// Building block that contains the label. +RESOURCE QIK_SYSTEM_BUILDING_BLOCK r_pico_credits_bb1 +{ + content = + { + QIK_SLOT_CONTENT + { + slot_id = EQikItemSlot1; + unique_handle = ECtlPicoCreditsText; + } + }; +} + + +RESOURCE ARRAY r_pico_tbuf_credits +{ + items= + { + LBUF{txt="This emulator uses code from these people / projects:";}, + LBUF{txt="";}, + LBUF{txt="Dave";}, + LBUF{txt="- Cyclone 68000 core, Pico emulation library";}, + LBUF{txt="Homepage: http://www.finalburn.com/";}, + LBUF{txt="";}, + LBUF{txt="Reesy & FluBBa";}, + LBUF{txt="- DrZ80, the Z80 emulator written in ARM assembly.";}, + LBUF{txt="Homepage: http://reesy.gp32x.de/";}, + LBUF{txt="";}, + LBUF{txt="Tatsuyuki Satoh, Jarek Burczynski, MultiArcadeMachineEmulator (MAME) development";}, + LBUF{txt="- software implementation of Yamaha FM sound generator and";}, + LBUF{txt="Texas Instruments SN76489 / SN76496 programmable tone / noise generator";}, + LBUF{txt="Homepage: http://www.mame.net/";}, + LBUF{txt="";}, + LBUF{txt="Additional thanks:";}, + LBUF{txt="- Charles MacDonald (http://cgfm2.emuviews.com/) for old but still very useful info about genesis hardware.";}, + LBUF{txt="- Stéphane Dallongeville for creating Gens and making it open-source.";}, + LBUF{txt="- Steve Snake for all that he has done for Genesis emulation scene.";}, + LBUF{txt="- Bart Trzynadlowski for his SSFII and 68000 docs.";}, + LBUF{txt="- Maze for his research (http://haze.mameworld.info).";}, + LBUF{txt="- Mark and Jean-loup for zlib library.";}, + LBUF{txt="- Peter van Sebille for his various open-source Symbian projects to learn from.";}, + LBUF{txt="- Steve Fischer for his open-source Motorola projects.";}, + LBUF{txt="- AnotherGuest for all his Symbian stuff and support.";}, + LBUF{txt="- Inder for the icons.";}, + LBUF{txt="- Anyone else I forgot. You know who you are.";} + }; +} + + +/************************************** + * + * debug dialog + * + **************************************/ + +RESOURCE QIK_DIALOG r_pico_debug +{ + title = "debug"; + configurations = + { + QIK_DIALOG_CONFIGURATION + { + ui_config_mode = 0; + container = r_pico_credits_container; // stuff from credits should fit + command_list = r_pico_credits_commands; + } + }; + controls = r_pico_credits_controls; +} + diff --git a/platform/uiq3/rsc/PicoDrive_loc.rss b/platform/uiq3/rsc/PicoDrive_loc.rss new file mode 100644 index 00000000..2495e0bb --- /dev/null +++ b/platform/uiq3/rsc/PicoDrive_loc.rss @@ -0,0 +1,20 @@ +#include + +// This file localise the applications icons and caption +RESOURCE LOCALISABLE_APP_INFO + { + caption_and_icon = + { + CAPTION_AND_ICON_INFO + { + caption = "PicoDrive"; + // Icons are used to represent applications in the + // application launcher and application title bar. + // The number_of_icons value identifies how many icons + // that exist in the icon_file. + number_of_icons = 3; + // Using the application icons. + icon_file = "\\Resource\\Apps\\PicoDrive.mbm"; + } + }; + } diff --git a/platform/uiq3/rsc/PicoDrive_reg.rss b/platform/uiq3/rsc/PicoDrive_reg.rss new file mode 100644 index 00000000..2b2e4d85 --- /dev/null +++ b/platform/uiq3/rsc/PicoDrive_reg.rss @@ -0,0 +1,17 @@ +// All registration files need to #include appinfo.rh. +#include + +// All registration files must define UID2, which is always +// KUidAppRegistrationResourceFile, and UID3, which is the application's UID. +UID2 KUidAppRegistrationResourceFile +UID3 0xA00010F3 // application UID + +// Registration file need to containo an APP_REGISTRATION_INFO resource that +// minimally needs to provide the name of the application binary (using the +// app_file statement). +RESOURCE APP_REGISTRATION_INFO + { + app_file = "PicoDrive"; // filename of application binary (minus extension) + // Specify the location of the localisable icon/caption definition file + localisable_resource_file = "\\Resource\\Apps\\PicoDrive_loc"; + } diff --git a/platform/uiq3/version.h b/platform/uiq3/version.h new file mode 100644 index 00000000..007068a7 --- /dev/null +++ b/platform/uiq3/version.h @@ -0,0 +1,10 @@ +// version number + +#ifndef __VERSION_H +#define __VERSION_H + +#define KPicoMajorVersionNumber 0 +#define KPicoMinorVersionNumber 96 +#define KPicoBuildNumber 0 + +#endif /* __VERSION_H */ diff --git a/platform/win32/GenaDrive/DSound.cpp b/platform/win32/GenaDrive/DSound.cpp new file mode 100644 index 00000000..9884972a --- /dev/null +++ b/platform/win32/GenaDrive/DSound.cpp @@ -0,0 +1,130 @@ + +#include "app.h" + +#ifndef _XBOX +#pragma warning (disable:4201) +#include +#include +#endif + +static IDirectSound *DSound=NULL; +static IDirectSoundBuffer *LoopBuffer=NULL; +static int LoopLen=0,LoopWrite=0; // Next position in loop to write + +short *DSoundNext=NULL; // Buffer for next sound data to put in loop +//int DSoundSeg=0; // Seg length in samples + +static int LoopBlank() +{ + void *mema=NULL,*memb=NULL; + DWORD sizea=0,sizeb=0; + + LoopBuffer->Lock(0,LoopLen<<2, &mema,&sizea, &memb,&sizeb, 0); + + if (mema) memset(mema,0,sizea); + + LoopBuffer->Unlock(mema,sizea, memb,sizeb); + + return 0; +} + +int DSoundInit() +{ + DSBUFFERDESC dsbd; + WAVEFORMATEX wfx; + + memset(&dsbd,0,sizeof(dsbd)); + memset(&wfx,0,sizeof(wfx)); + + // Make wave format: + wfx.wFormatTag=WAVE_FORMAT_PCM; + wfx.nChannels=(unsigned short)((PicoOpt&8) ? 2 : 1); // Stereo/mono + wfx.nSamplesPerSec=PsndRate; + wfx.wBitsPerSample=16; + + wfx.nBlockAlign=(WORD)((wfx.nChannels*wfx.wBitsPerSample)>>3); + wfx.nAvgBytesPerSec=wfx.nBlockAlign*wfx.nSamplesPerSec; + + // Make buffer for the next seg to put into the loop: + DSoundNext=(short *)malloc(PsndLen<<2); if (DSoundNext==NULL) return 1; + memset(DSoundNext,0,PsndLen<<2); + + // Create the DirectSound interface: + DirectSoundCreate(NULL,&DSound,NULL); + if (DSound==NULL) return 1; + + LoopLen=PsndLen<<1; // 2 segs + +#ifndef _XBOX + LoopLen<<=1; // 4 segs + DSound->SetCooperativeLevel(FrameWnd,DSSCL_PRIORITY); + dsbd.dwFlags=DSBCAPS_GLOBALFOCUS; // Play in background +#endif + + // Create the looping buffer: + dsbd.dwSize=sizeof(dsbd); + dsbd.dwBufferBytes=LoopLen<CreateSoundBuffer(&dsbd,&LoopBuffer,NULL); + if (LoopBuffer==NULL) return 1; + + LoopBlank(); + LoopBuffer->Play(0,0,DSBPLAY_LOOPING); + return 0; +} + +void DSoundExit() +{ + if (LoopBuffer) LoopBuffer->Stop(); + RELEASE(LoopBuffer) + RELEASE(DSound) + free(DSoundNext); DSoundNext=NULL; +} + +static int WriteSeg() +{ + void *mema=NULL,*memb=NULL; + DWORD sizea=0,sizeb=0; + + // Lock the segment at 'LoopWrite' and copy the next segment in + LoopBuffer->Lock(LoopWrite<<((PicoOpt&8) ? 2 : 1),PsndLen<<((PicoOpt&8) ? 2 : 1), &mema,&sizea, &memb,&sizeb, 0); + + if (mema) memcpy(mema,DSoundNext,sizea); + + LoopBuffer->Unlock(mema,sizea, memb,0); + + return 0; +} + +int DSoundUpdate() +{ + DWORD play=0; + int pos=0; + + if (LoopBuffer==NULL) return 1; + + LoopBuffer->GetCurrentPosition(&play,NULL); + pos=play>>((PicoOpt&8) ? 2 : 1); + + // 'LoopWrite' is the next seg in the loop that we want to write + // First check that the sound 'play' pointer has moved out of it: + if (pos>=LoopWrite && posLoopLen) LoopWrite=0; + + return 0; +} + +void DSoundMute() +{ + LoopBuffer->Stop(); +} + +void DSoundUnMute() +{ + LoopBuffer->Play(0,0,DSBPLAY_LOOPING); +} diff --git a/platform/win32/GenaDrive/Direct.cpp b/platform/win32/GenaDrive/Direct.cpp new file mode 100644 index 00000000..05b84de1 --- /dev/null +++ b/platform/win32/GenaDrive/Direct.cpp @@ -0,0 +1,210 @@ + +#include "app.h" + +static IDirect3D8 *Direct3D=NULL; +IDirect3DDevice8 *Device=NULL; +IDirect3DSurface8 *DirectBack=NULL; // Back Buffer + +static IDirect3DVertexBuffer8 *VertexBuffer=NULL; + +struct CustomVertex +{ + float x,y,z; // Vertex cordinates + unsigned int colour; + float u,v; // Texture coordinates +}; +#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1) + +static CustomVertex VertexList[4]; + +int DirectInit() +{ + D3DPRESENT_PARAMETERS d3dpp; + D3DDISPLAYMODE mode; + int i=0,ret=0; + + memset(&d3dpp,0,sizeof(d3dpp)); + memset(&mode,0,sizeof(mode)); + + Direct3D=Direct3DCreate8(D3D_SDK_VERSION); if (Direct3D==NULL) return 1; + + // Set up the structure used to create the D3D device: + d3dpp.BackBufferWidth =MainWidth; + d3dpp.BackBufferHeight=MainHeight; + d3dpp.BackBufferCount =1; + d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD; + +#ifdef _XBOX + d3dpp.BackBufferFormat=D3DFMT_X8R8G8B8; + d3dpp.FullScreen_RefreshRateInHz=60; +#else + Direct3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&mode); + d3dpp.BackBufferFormat=mode.Format; + d3dpp.Windowed=1; +#endif + + // Try to create a device with hardware vertex processing: + for (i=0;i<4;i++) + { + int behave=D3DCREATE_HARDWARE_VERTEXPROCESSING; + +#ifdef _XBOX + if (i==1) + { + // If 60Hz didn't work, try PAL 50Hz instead: + d3dpp.FullScreen_RefreshRateInHz=0; + d3dpp.BackBufferHeight=MainHeight=576; + } +#endif + + // Try software vertex processing: + if (i==2) behave=D3DCREATE_MIXED_VERTEXPROCESSING; + if (i==3) behave=D3DCREATE_SOFTWARE_VERTEXPROCESSING; + + Direct3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,FrameWnd,behave,&d3dpp,&Device); + if (Device) break; + } + + if (Device==NULL) return 1; + + Device->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&DirectBack); + if (DirectBack==NULL) return 1; + + Device->CreateVertexBuffer(sizeof(VertexList),0,D3DFVF_CUSTOMVERTEX,D3DPOOL_DEFAULT,&VertexBuffer); + if (VertexBuffer==NULL) return 1; + + ret=TexScreenInit(); if (ret) return 1; + + FontInit(); + + Device->SetRenderState(D3DRS_LIGHTING,0); // Turn off lighting + + // Set up texture modes: + Device->SetTextureStageState(0,D3DTSS_ADDRESSU,D3DTADDRESS_CLAMP); + Device->SetTextureStageState(0,D3DTSS_ADDRESSV,D3DTADDRESS_CLAMP); + return 0; +} + +void DirectExit() +{ + FontExit(); + TexScreenExit(); + + RELEASE(VertexBuffer) + RELEASE(DirectBack) + RELEASE(Device) + RELEASE(Direct3D) +} + + +static int MakeVertexList() +{ + struct CustomVertex *vert=NULL,*pv=NULL; + float dist=0.0f; + float scalex=0.0f,scaley=0.0f; + unsigned int colour=0xffffff; + float right=0.0f,bottom=0.0f; + + if (LoopMode!=8) colour=0x102040; + + dist=10.0f; scalex=dist*1.3333f; scaley=dist; + + scalex*=640.0f/(float)MainWidth; + scaley*=448.0f/(float)MainHeight; + + vert=VertexList; + + // Put the vertices for the corners of the screen: + pv=vert; + pv->z=dist; + pv->x=-scalex; pv->y=scaley; + pv->colour=colour; pv++; + + *pv=vert[0]; pv->x= scalex; pv->y= scaley; pv++; + *pv=vert[0]; pv->x=-scalex; pv->y=-scaley; pv++; + *pv=vert[0]; pv->x= scalex; pv->y=-scaley; pv++; + + // Find where the screen images ends on the texture + right =(float)EmuWidth /(float)TexWidth; + bottom=(float)EmuHeight/(float)TexHeight; + + // Write texture coordinates: + pv=vert; + pv->u=0.0f; pv->v=0.00f; pv++; + pv->u=right; pv->v=0.00f; pv++; + pv->u=0.0f; pv->v=bottom; pv++; + pv->u=right; pv->v=bottom; pv++; + + return 0; +} + +int DirectClear(unsigned int colour) +{ + Device->Clear(0,NULL,D3DCLEAR_TARGET,colour,1.0f,0); + return 0; +} + +int DirectPresent() +{ + Device->Present(NULL,NULL,NULL,NULL); + return 0; +} + +static int SetupMatrices() +{ + D3DXVECTOR3 eye ( 0.0f, 0.0f, 0.0f ); + D3DXVECTOR3 look( 0.0f, 0.0f, 0.0f ); + D3DXVECTOR3 up ( 0.0f, 1.0f, 0.0f ); + D3DXMATRIX mat; + float nudgex=0.0f,nudgey=0.0f; + + memset(&mat,0,sizeof(mat)); + + mat.m[0][0]=mat.m[1][1]=mat.m[2][2]=mat.m[3][3]=1.0f; + Device->SetTransform(D3DTS_WORLD,&mat); + + look.x=(float)Inp.axis[2]/2457.6f; + look.y=(float)Inp.axis[3]/2457.6f; + look.z=10.0f; + + // Nudge pixels to the centre of each screen pixel: + nudgex=13.3333f/(float)(MainWidth <<1); + nudgey=10.0000f/(float)(MainHeight<<1); + eye.x +=nudgex; eye.y +=nudgey; + look.x+=nudgex; look.y+=nudgey; + + D3DXMatrixLookAtLH(&mat,&eye,&look,&up); + Device->SetTransform(D3DTS_VIEW,&mat); + + D3DXMatrixPerspectiveFovLH(&mat, 0.5f*PI, 1.3333f, 0.2f, 1000.0f); + Device->SetTransform(D3DTS_PROJECTION,&mat); + return 0; +} + +int DirectScreen() +{ + unsigned char *lock=NULL; + + // Copy the screen to the screen texture: +#ifdef _XBOX + TexScreenSwizzle(); +#else + TexScreenLinear(); +#endif + + SetupMatrices(); + + MakeVertexList(); + + // Copy vertices in: + VertexBuffer->Lock(0,sizeof(VertexList),&lock,0); if (lock==NULL) return 1; + memcpy(lock,VertexList,sizeof(VertexList)); + VertexBuffer->Unlock(); + + Device->SetTexture(0,TexScreen); + Device->SetStreamSource(0,VertexBuffer,sizeof(CustomVertex)); + Device->SetVertexShader(D3DFVF_CUSTOMVERTEX); + Device->DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2); + + return 0; +} diff --git a/platform/win32/GenaDrive/Emu.cpp b/platform/win32/GenaDrive/Emu.cpp new file mode 100644 index 00000000..5294d7af --- /dev/null +++ b/platform/win32/GenaDrive/Emu.cpp @@ -0,0 +1,112 @@ + +#include "app.h" + +extern "C" { +struct Pico +{ + unsigned char ram[0x10000]; // 0x00000 scratch ram + unsigned short vram[0x8000]; // 0x10000 + unsigned char zram[0x2000]; // 0x20000 Z80 ram + unsigned char ioports[0x10]; + unsigned int pad[0x3c]; // unused + unsigned short cram[0x40]; // 0x22100 + unsigned short vsram[0x40]; // 0x22180 + + unsigned char *rom; // 0x22200 + unsigned int romsize; // 0x22204 + +// struct PicoMisc m; +// struct PicoVideo video; +}; + extern struct Pico Pico; +} + +unsigned short *EmuScreen=NULL; +extern "C" unsigned short *framebuff=NULL; +int EmuWidth=0,EmuHeight=0; +static int frame=0; +static int EmuScan(unsigned int num, void *sdata); + +int EmuInit() +{ + int len=0; + +// PicoOpt=-1; +// PsndRate=44100; PsndLen=DSoundSeg; + + PicoInit(); + + // Allocate screen: + EmuWidth=320; EmuHeight=224; + len=EmuWidth*EmuHeight; len<<=1; + EmuScreen=(unsigned short *)malloc(len); if (EmuScreen==NULL) return 1; + framebuff=(unsigned short *)malloc((8+320)*(8+224+8)*2); + memset(EmuScreen,0,len); + + PicoScan=EmuScan; + + return 0; +} + +void EmuExit() +{ + //RomFree(); + free(EmuScreen); EmuScreen=NULL; // Deallocate screen + free(framebuff); + EmuWidth=EmuHeight=0; + + PicoExit(); +} + +// Megadrive scanline callback: +static int EmuScan(unsigned int num, void *sdata) +{ + unsigned short *pd=NULL,*end=NULL; + unsigned short *ps=NULL; + + if (num>=(unsigned int)EmuHeight) return 0; + + // Copy scanline to screen buffer: + pd=EmuScreen+(num<<8)+(num<<6); end=pd+320; + ps=(unsigned short *)sdata; + + do { *pd++=(unsigned short)PicoCram(*ps++); } while (pd=0) if (Inp.button[m]>30) input|=1<>8; + + while (pos-height && y>8)) colour=0x00ff40; + + FontSetColour(colour); + FontText(text,x,y); + } + + y+=height; + pos+=strlen(name)+1; // Skip to next string + index++; + } + + return 0; +} + +int FileMenu::scroll(int amount) +{ + int max=0; + + choiceFocus+=amount; + + max=nameCount<<8; + if (choiceFocus<0) choiceFocus=0; + if (choiceFocus>=max) choiceFocus=max-1; + + return 0; +} + +// Get the currently highlighted filename +int FileMenu::getFilePath(char *path) +{ + int focus=0; + int pos=0; + char *name=NULL; + + // Find where the user is focused + focus=choiceFocus>>8; + pos=nameOffset(focus); if (pos<0) return 1; + + name=nameList+pos; + + // Return path and name: + sprintf(path,"%.128s\\%.128s",currentPath,name); + return 0; +} + +// ---------------------------------------------------------------------- +int FileMenu::nameReset() +{ + free(nameList); nameList=NULL; + nameSize=nameMax=nameCount=0; + + return 0; +} + +int FileMenu::nameFind(char *path) +{ + HANDLE find=NULL; + WIN32_FIND_DATA wfd; + + memset(&wfd,0,sizeof(wfd)); + + find=FindFirstFile(path,&wfd); + if (find==INVALID_HANDLE_VALUE) return 1; + + for (;;) + { + nameAdd(wfd.cFileName); // Add the name to the list + + if (FindNextFile(find,&wfd)==0) break; + } + + FindClose(find); + return 0; +} + +int FileMenu::nameAdd(char *entry) +{ + int len=0; + + len=strlen(entry); + // Check we have room for this entry: + if (nameSize+len+1>nameMax) nameSizeUp(); + if (nameSize+len+1>nameMax) return 1; + + // Add entry with zero at the end: + memcpy(nameList+nameSize,entry,len); + nameSize+=len+1; + nameCount++; + + return 0; +} + +int FileMenu::nameSizeUp() +{ + + void *mem=NULL; + int add=256; + + // Allocate more memory for the list: + mem=realloc(nameList,nameMax+add); if (mem==NULL) return 1; + + nameList=(char *)mem; + memset(nameList+nameMax,0,add); // Blank new memory + nameMax+=add; + return 0; +} + +int FileMenu::nameOffset(int index) +{ + int pos=0,i=0; + + while (pos +static XFONT *Font=NULL; + +int FontInit() +{ + XFONT_OpenDefaultFont(&Font); if (Font==NULL) return 1; + + return 0; +} + +void FontExit() +{ +} + +int FontSetColour(unsigned int colour) +{ + Font->SetTextColor(colour); + return 0; +} + +int FontText(WCHAR *text,int dx,int dy) +{ + if (Font==NULL || DirectBack==NULL) return 1; + + Font->TextOut(DirectBack,text,~0U,dx,dy); + return 0; +} + +#endif + + +// ---------------------------------------------------------------------------------- +#ifndef _XBOX + +static ID3DXFont *Font=NULL; +static unsigned int FontColour=0; + +int FontInit() +{ + LOGFONT lf; + + memset(&lf,0,sizeof(lf)); + strcpy(lf.lfFaceName,"Arial"); + lf.lfHeight=24; + D3DXCreateFontIndirect(Device,&lf,&Font); + + return 0; +} + +void FontExit() +{ + RELEASE(Font); +} + +int FontSetColour(unsigned int colour) +{ + FontColour=0xff000000|colour; + return 0; +} + +int FontText(WCHAR *text,int dx,int dy) +{ + RECT rect={0,0,0,0}; + + if (Font==NULL || DirectBack==NULL) return 1; + + Font->Begin(); + rect.left=dx; + rect.top=dy; + rect.right=MainWidth; + rect.bottom=MainHeight; + + Font->DrawTextW(text,-1,&rect,DT_LEFT,FontColour); + Font->End(); + + return 0; +} + +#endif diff --git a/platform/win32/GenaDrive/GenaDrive.dsp b/platform/win32/GenaDrive/GenaDrive.dsp new file mode 100644 index 00000000..85db328c --- /dev/null +++ b/platform/win32/GenaDrive/GenaDrive.dsp @@ -0,0 +1,308 @@ +# Microsoft Developer Studio Project File - Name="GenaDrive" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=GenaDrive - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "GenaDrive.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "GenaDrive.mak" CFG="GenaDrive - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GenaDrive - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "GenaDrive - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GenaDrive - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\..\..\Pico" /I ".\\" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "EMU_M68K" /D "_USE_MZ80" /FR /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 gdi32.lib user32.lib advapi32.lib d3d8.lib d3dx8.lib dsound.lib comdlg32.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "GenaDrive - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\..\..\Pico" /I ".\\" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "DEBUG" /D "EMU_M68K" /D "_USE_MZ80" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 user32.lib gdi32.lib advapi32.lib d3d8.lib d3dx8.lib dsound.lib comdlg32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "GenaDrive - Win32 Release" +# Name "GenaDrive - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\Emu.cpp +# End Source File +# Begin Source File + +SOURCE=.\GenaDrive.txt +# End Source File +# Begin Source File + +SOURCE=.\Input.cpp +# End Source File +# Begin Source File + +SOURCE=.\LightCal.cpp +# End Source File +# Begin Source File + +SOURCE=.\Loop.cpp +# End Source File +# Begin Source File + +SOURCE=.\Main.cpp +# End Source File +# Begin Source File + +SOURCE=.\Makefile +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\app.h +# End Source File +# End Group +# Begin Group "DirectX" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Direct.cpp +# End Source File +# Begin Source File + +SOURCE=.\DSound.cpp +# End Source File +# Begin Source File + +SOURCE=.\FileMenu.cpp +# End Source File +# Begin Source File + +SOURCE=.\FileMenu.h +# End Source File +# Begin Source File + +SOURCE=.\Font.cpp +# End Source File +# Begin Source File + +SOURCE=.\TexScreen.cpp +# End Source File +# End Group +# Begin Group "Pico" + +# PROP Default_Filter "" +# Begin Group "sound" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Pico\sound\driver.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Pico\sound\sn76496.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\Pico\sound\sn76496.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Pico\sound\sound.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\Pico\sound\sound.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Pico\sound\ym2612.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\Pico\sound\ym2612.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\Pico\Area.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\Pico\Cart.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\Pico\Draw.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\Pico\Draw2.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\Pico\Memory.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\Pico\Misc.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\Pico\Pico.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\Pico\Pico.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Pico\PicoInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Pico\Sek.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\Pico\Utils.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\Pico\VideoPort.c +# End Source File +# End Group +# Begin Group "cores" + +# PROP Default_Filter "" +# Begin Group "musashi" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\cpu\musashi\m68k.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\cpu\musashi\m68kconf.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\cpu\musashi\m68kcpu.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\cpu\musashi\m68kcpu.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\cpu\musashi\m68kdasm.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\cpu\musashi\m68kopac.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\cpu\musashi\m68kopdm.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\cpu\musashi\m68kopnz.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\cpu\musashi\m68kops.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\cpu\musashi\m68kops.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\cpu\mz80\mz80.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\cpu\a68k\a68k.obj + +!IF "$(CFG)" == "GenaDrive - Win32 Release" + +!ELSEIF "$(CFG)" == "GenaDrive - Win32 Debug" + +# PROP Exclude_From_Build 1 + +!ENDIF + +# End Source File +# End Group +# End Target +# End Project diff --git a/platform/win32/GenaDrive/GenaDrive.txt b/platform/win32/GenaDrive/GenaDrive.txt new file mode 100644 index 00000000..ad0d8fc4 --- /dev/null +++ b/platform/win32/GenaDrive/GenaDrive.txt @@ -0,0 +1,118 @@ + +__________________________________________________________________________________________ + + ______ _______ __ _ _______ ______ ______ _____ _ _ _______ + | ____ |______ | \ | |_____| | \ |_____/ | \ / |______ + |_____| |______ | \_| | | |_____/ | \_ __|__ \/ |______ + + G E N A D R I V E + + + GenaDrive is a Genesis / MegaDrive emulator for the XBox. + + + #include + I do not accept responsibility for any effects, adverse or otherwise, that + this code may have on you, your computer, your sanity, your dog... etc. + You can use this software freely as long as you don't use it commercially. +__________________________________________________________________________________________ + + Weird Name? + +GenaDrive is a porn-star emulator, based on legendary porn star Jenna Ja... no not really. +GenaDrive (one word, capital G, capital D), is pronounced "Jen-A-Drive". + +(Think 'MegaDrive' but with 'Gen' instead of 'Meg'.) + +__________________________________________________________________________________________ + +What's New + + v0.004 + * Merged the PicoDrive and GenaDrive 'Pico' directories, with ifdefs for + EMU_C68K (Cyclone) and EMU_A68K. + + v0.003 - Added .SMD support + + v0.002 - First release + +__________________________________________________________________________________________ + + Okay but what is it? + + GenaDrive is a partially-complete MegaDrive emulator for the XBox. It emulates the + hardware of the MegaDrive console on the XBox. Basically, it makes your XBox act like + a MegaDrive. + + It actually uses the same code-base as my Pocket PC 'PicoDrive' emulator, but instead + of an ARM-optimized 68000 emulator it uses (naturally) an Intel-optimized one - A68K + from the MAME project. + +__________________________________________________________________________________________ + + How to use + + Put the emulator (default.xbe) in a directory such as e:\Emulators\GenaDrive\ + Make sure there is a directory e:\Emulators\GenaDrive\Roms + Put your rom images there. + + Run GenaDrive. + If it doesn't work, try running 'xbepatch' on the XBE first to convert it to a retail XBE. + + This is minimal zip support, though there must be no other files in each zip. + + Run the emulator and you will see a list of rom images. Push up/down and press A + to select a rom image. + Click the Right thumbstick in to pause and return to the menu. + + To exit the emulator hold L and R and press Black, or press Back+Start. + + This is just an early version so there's quite a few things missing or not up to scratch, + e.g. sound, z80, joypad 2 + +__________________________________________________________________________________________ + +What's currently emulated: + + 68000 : Yes + + VDP + Scroll A/B : Yes + Line Scroll : Yes + Sprites : Sort of + Window : Not yet + H-Ints/HV Counter : Not yet + + Sound: + Z80 : Not yet (faked) + YM2151 : Not yet + PSG : Not yet + + Compatibility: ~50% ? + +__________________________________________________________________________________________ + +Web page and contact info: + + I (Dave) can be reached at the usual spot, my web-page is: + + http://www.finalburn.com/ + + And my e-mail address is as follows, just change the (atsymbol) to @ + + dev(atsymbol)finalburn.com + + NB - I had to shut down the 'dave' mailbox so it's now 'dev', because the 'dave' + e-mail address was printed everywhere and spambots logged it and spammed it to death! :P + So if you must quote it, please quote it as above... or better yet just link to my webpage. + +Thanks to: + Mike Coates and Darren Olafson once again for A68K + Sam for getting me set up on my XBox! + Charles Macdonald, for researching just about every console ever + MameDev+FBA, for keeping on going and going and going + XPort for loads of great XBox emulators + + ...and anyone else I forgot! + +__________________________________________________________________________________________ diff --git a/platform/win32/GenaDrive/Input.cpp b/platform/win32/GenaDrive/Input.cpp new file mode 100644 index 00000000..01069ca7 --- /dev/null +++ b/platform/win32/GenaDrive/Input.cpp @@ -0,0 +1,247 @@ + +#include "app.h" +#include + +extern char *romname; +extern unsigned char *rom_data; +extern unsigned int rom_size; +extern int fastForward; +extern int frameStep; +extern int emu_frame; + +struct Input Inp; + +// --------------------- XBox Input ----------------------------- +#ifdef _XBOX +static HANDLE GamePad=NULL; +static XINPUT_STATE Pad; + +static int DeadZone(short *paxis) +{ + int zone=0x2000; + int a=*paxis; + + if (a<-zone) a+=zone; + else if (a> zone) a-=zone; else a=0; + + *paxis=(short)a; + return 0; +} + +static int DeviceRead() +{ + int but=0,a=0; + + memset(Inp.axis, 0,sizeof(Inp.axis)); + memset(Inp.button,0,sizeof(Inp.button)); + + if (GamePad==NULL) GamePad=XInputOpen(XDEVICE_TYPE_GAMEPAD,0,XDEVICE_NO_SLOT,NULL); + if (GamePad==NULL) return 1; + + // Read XBox joypad: + XInputGetState(GamePad,&Pad); + + // Get analog axes: + Inp.axis[0]=Pad.Gamepad.sThumbLX; + Inp.axis[1]=Pad.Gamepad.sThumbLY; + Inp.axis[2]=Pad.Gamepad.sThumbRX; + Inp.axis[3]=Pad.Gamepad.sThumbRY; + + for (a=0;a<4;a++) DeadZone(Inp.axis+a); + + // Get digital buttons: + but=Pad.Gamepad.wButtons; + for (a=0;a<8;a++) + { + if (but&(1<= push) Inp.button[0]|=0xff; // Up + if (Inp.axis[1]<=-push) Inp.button[1]|=0xff; // Down + if (Inp.axis[0]<=-push) Inp.button[2]|=0xff; // Left + if (Inp.axis[0]>= push) Inp.button[3]|=0xff; // Right + + // Update debounce/time held information: + for (i=0;i30) Inp.held[i]=1; // Just pressed + } + else + { + // Is the button still being held down? + Inp.held[i]++; + if (Inp.held[i]>=0x80) Inp.held[i]&=0xbf; // (Keep looping around) + + if (Inp.button[i]<25) Inp.held[i]=0; // No + } + } + + // Work out some key repeat values: + for (i=0;i=0x20 && (held&1)) rep=1; + + Inp.repeat[i]=rep; + } + + return 0; +} + +// Set Lightgun calibration values: +int InputLightCal(int cx,int cy,int ux,int uy) +{ +#ifdef _XBOX + XINPUT_LIGHTGUN_CALIBRATION_OFFSETS cal; + + memset(&cal,0,sizeof(cal)); + + cal.wCenterX =(WORD)cx; + cal.wCenterY =(WORD)cy; + cal.wUpperLeftX=(WORD)ux; + cal.wUpperLeftY=(WORD)uy; + XInputSetLightgunCalibration(GamePad,&cal); + +#endif + + (void)(cx+cy+ux+uy); + + return 0; +} diff --git a/platform/win32/GenaDrive/LightCal.cpp b/platform/win32/GenaDrive/LightCal.cpp new file mode 100644 index 00000000..0d697d94 --- /dev/null +++ b/platform/win32/GenaDrive/LightCal.cpp @@ -0,0 +1,102 @@ + +#include "app.h" + +struct Target +{ + int sx,sy; // Onscreen coordinates + int dx,dy; // Device values +}; + +struct Target Targ[2]= +{ + {0,0, 0,0}, + {0,0, 0,0} +}; +static int LightState=0; + +struct Calib +{ + float ax,bx; + float ay,by; +}; +static struct Calib Cal={0.0f,0.0f,0.0f,0.0f}; + +int LightCalReset() +{ + LightState=0; + + memset(Targ,0,sizeof(Targ)); + Targ[0].sx=MainWidth >>1; + Targ[0].sy=MainHeight>>1; + Targ[1].sy=Targ[0].sy-MainHeight*61/160; + Targ[1].sx=Targ[0].sx-MainWidth *61/160; + return 0; +} + +int LightCalUpdate() +{ + int i=0; + struct Target *pt=NULL; + + if (Inp.held[4]==1) LoopMode=3; + + if (Inp.held[8]==1) + { + i=LightState&1; + pt=Targ+i; + + pt->dx=Inp.axis[0]; + pt->dy=Inp.axis[1]; + + if (i==1) + { + int num=0,den=0; + + // rx= a + b*x - work out a and b: + num=Targ[0].sx-Targ[1].sx; + den=Targ[0].dx-Targ[1].dx; + if (den) Cal.bx=(float)num/(float)den; + Cal.ax=(float)Targ[0].sx-Cal.bx*(float)Targ[0].dx; + + num=Targ[0].sy-Targ[1].sy; + den=Targ[0].dy-Targ[1].dy; + if (den) Cal.by=(float)num/(float)den; + Cal.ay=(float)Targ[0].sy-Cal.by*(float)Targ[0].dy; + } + + LightState++; + } + + return 0; +} + +int LightCalRender() +{ + int i=0; + struct Target *pt=NULL; + float fx=0.0f,fy=0.0f; + + DirectClear(0xffffff); + + WCHAR text[80]={0}; + wsprintfW(text,L"LightGun Calibration"); + FontSetColour(0x0000ff); + FontText(text,240,48); + + wsprintfW(text,L"Start to quit, B to call InputLightCal"); + FontSetColour(0x004000); + FontText(text,64,120); + + i=LightState&1; + pt=Targ+i; + FontSetColour(0); + FontText(L"X", pt->sx-8, pt->sy-12); + + fx=Cal.ax+Cal.bx*(float)Inp.axis[0]; + fy=Cal.ay+Cal.by*(float)Inp.axis[1]; + + FontSetColour(0xff0000); + FontText(L"+", (int)fx-8,(int)fy-12); + + return 0; +} diff --git a/platform/win32/GenaDrive/Loop.cpp b/platform/win32/GenaDrive/Loop.cpp new file mode 100644 index 00000000..54d35197 --- /dev/null +++ b/platform/win32/GenaDrive/Loop.cpp @@ -0,0 +1,244 @@ +#include "app.h" +#include "FileMenu.h" + +// sram +struct PicoSRAM +{ + unsigned char *data; // actual data + unsigned int start; // start address in 68k address space + unsigned int end; + unsigned char resize; // 1=SRAM size changed and needs to be reallocated on PicoReset + unsigned char reg_back; // copy of Pico.m.sram_reg to set after reset + unsigned char changed; + unsigned char pad; +}; + +extern "C" PicoSRAM SRam; +extern char *romname; +int fastForward=0; +int frameStep=0; + +char LoopQuit=0; +static FILE *DebugFile=NULL; +int LoopMode=0; +static void UpdateSound(); + +int LoopInit() +{ + int ret=0; + + // bits LSb->MSb: + // enable_ym2612&dac, enable_sn76496, enable_z80, stereo_sound; + // alt_renderer, 6button_gamepad, accurate_timing, accurate_sprites + PicoOpt=0x1f; + PsndRate=44100; + //PsndLen=PsndRate/60; // calculated later by pico itself + + // Init Direct3D: + ret=DirectInit(); if (ret) return 1; + InputInit(); + + // Init DirectSound: + //DSoundInit(); + + ret=EmuInit(); if (ret) return 1; + FileMenu.init(); + + LoopMode=8; + PicoWriteSound = UpdateSound; + + return 0; +} + +void preLoopInit() +{ + romname[strlen(romname)-3] = 0; + strcat(romname, "srm"); + int sram_size = SRam.end-SRam.start+1; + if(SRam.reg_back & 4) sram_size=0x2000; + FILE *f = fopen(romname, "rb"); + if(f && SRam.data) + fread(SRam.data, 1, sram_size, f); + if(f) fclose(f); +} + +extern "C" char *debugString(); + +void LoopExit() +{ + dprintf(debugString()); + + romname[strlen(romname)-3] = 0; + strcat(romname, "srm"); + int sram_size = SRam.end-SRam.start+1; + if(SRam.reg_back & 4) sram_size=0x2000; + for(; sram_size > 0; sram_size--) + if(SRam.data[sram_size-1]) break; + if(sram_size) { + FILE *f = fopen(romname, "wb"); + if(f) { + fwrite(SRam.data, 1, sram_size, f); + fclose(f); + } + } + + FileMenu.exit(); + EmuExit(); + DSoundExit(); PsndLen=0; + InputExit(); + DirectExit(); + + if (DebugFile) fclose(DebugFile); + DebugFile=NULL; +} + +// ---------------------------------------------------------------- + +int emu_frame = 0; + +static int DoGame() +{ + if(fastForward) { PicoSkipFrame+=1; PicoSkipFrame&=7; } + else PicoSkipFrame=0; + + if(frameStep==1) return 0; + else if(frameStep==3) frameStep=1; + + EmuFrame(); + emu_frame++; + + if (Inp.held[7]==1) LoopMode=2; // Right thumb = Toggle Menu + + return 0; +} +// ---------------------------------------------------------------- + +static int MenuUpdate() +{ + int delta=0; + + if (Inp.repeat[0]) delta-=0x100; + if (Inp.repeat[1]) delta+=0x100; + + if (Inp.button[14]>30) delta-=Inp.button[14]-30; + if (Inp.button[15]>30) delta+=Inp.button[15]-30; + + if (delta) FileMenu.scroll(delta); + + if (Inp.held[8]==1 || Inp.held[10]==1 || Inp.held[4]==1) // A, X or Start + { + //RomFree(); + //FileMenu.getFilePath(RomName); + //RomLoad(); + //LoopMode=8; // Go to game + } + + if (Inp.held[7]==1) LoopMode=8; // Right thumb = Toggle Menu + + return 0; +} + +static int MenuRender() +{ + WCHAR text[80]={0}; + wsprintfW(text,L"%.40S v%x.%.3x",AppName,PicoVer>>12,PicoVer&0xfff); + FontSetColour(0x60c0ff); + FontText(text,64,48); + + FileMenu.render(); + + return 0; +} + +// ---------------------------------------------------------------- + +static int ModeUpdate() +{ + if (Inp.held[14] && Inp.held[15] && Inp.held[12]==1) LoopQuit=1; // L+R+black to quit: + if (Inp.button[4]>30 && Inp.button[5]>30) LoopQuit=1; // Start and back to quit + + if (LoopMode==8) { DoGame(); return 0; } + + if (DSoundNext) memset(DSoundNext,0,PsndLen<<2); + + if (LoopMode==2) { FileMenu.scan(); LoopMode++; return 0; } + if (LoopMode==3) { MenuUpdate(); return 0; } + if (LoopMode==4) { LightCalUpdate(); return 0; } + + LoopMode=2; // Unknown mode, go to rom menu + return 0; +} + + +static int ModeRender() +{ + DirectScreen(); + if (LoopMode==3) MenuRender(); + if (LoopMode==4) LightCalRender(); + + return 0; +} + +static void UpdateSound() +{ + if(fastForward) return; + while (DSoundUpdate()) { Sleep(1); } + while (DSoundUpdate()==0) { } +} + +int LoopCode() +{ + + // Main loop: + while (!LoopQuit) + { + InputUpdate(); + + DirectClear(0); + ModeUpdate(); + ModeRender(); + DirectPresent(); +// UpdateSound(); + } + + return 0; +} + +// ------------------------------------------------------------------------------------- + +extern "C" int dprintf(char *format, ...) +{ + char *name=NULL; + va_list val=NULL; + +#ifdef _XBOX + name="d:\\zout.txt"; +#else + name="zout.txt"; +#endif + + if (DebugFile==NULL) DebugFile=fopen(name,"wt"); + if (DebugFile==NULL) return 1; + + fprintf(DebugFile, "%05i: ", emu_frame); + va_start(val,format); + vfprintf(DebugFile,format,val); + fprintf(DebugFile, "\n"); + fflush(DebugFile); + + va_end(val); + return 0; +} + +extern "C" int dprintf2(char *format, ...) +{ + char str[512]; + va_list val=NULL; + + va_start(val,format); + vsprintf(str,format,val); + va_end(val); + OutputDebugString(str); + + return 0; +} diff --git a/platform/win32/GenaDrive/Main.cpp b/platform/win32/GenaDrive/Main.cpp new file mode 100644 index 00000000..edab4305 --- /dev/null +++ b/platform/win32/GenaDrive/Main.cpp @@ -0,0 +1,178 @@ + +#include "app.h" +#include +#include + +char *romname; +HWND FrameWnd=NULL; + +int MainWidth=720,MainHeight=480; + +char AppName[]="GenaDrive"; + +#ifdef STARSCREAM + extern "C" int SekReset(); +#endif + +// ------------------------------------ XBox Main ------------------------------------------ +#ifdef _XBOX + +static int MainCode() +{ + int ret=0; + + ret=LoopInit(); if (ret) { LoopExit(); return 1; } + + LoopQuit=0; LoopCode(); + LoopExit(); + + return 0; +} + +int __cdecl main() +{ + LD_LAUNCH_DASHBOARD launch; + + MainCode(); + + // Go back to dashboard: + memset(&launch,0,sizeof(launch)); + launch.dwReason=XLD_LAUNCH_DASHBOARD_MAIN_MENU; + XLaunchNewImage(NULL,(LAUNCH_DATA *)&launch); +} +#endif + +// ----------------------------------- Windows Main ---------------------------------------- +#ifndef _XBOX +// Window proc for the frame window: +static LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam) +{ + if (msg==WM_CLOSE) { PostQuitMessage(0); return 0; } + if (msg==WM_DESTROY) FrameWnd=NULL; // Blank handle + + return DefWindowProc(hwnd,msg,wparam,lparam); +} + +static int FrameInit() +{ + WNDCLASS wc; + RECT rect={0,0,0,0}; + int style=0; + int left=0,top=0,width=0,height=0; + + memset(&wc,0,sizeof(wc)); + + // Register the window class: + wc.lpfnWndProc=WndProc; + wc.hInstance=GetModuleHandle(NULL); + wc.hCursor=LoadCursor(NULL,IDC_ARROW); + wc.hbrBackground=CreateSolidBrush(0); + wc.lpszClassName="MainFrame"; + RegisterClass(&wc); + + rect.right =320;//MainWidth; + rect.bottom=224;//MainHeight; + + // Adjust size of windows based on borders: + style=WS_OVERLAPPEDWINDOW; + AdjustWindowRect(&rect,style,0); + width =rect.right-rect.left; + height=rect.bottom-rect.top; + + // Place window in the centre of the screen: + SystemParametersInfo(SPI_GETWORKAREA,0,&rect,0); + left=rect.left+rect.right; + top=rect.top+rect.bottom; + + left-=width; left>>=1; + top-=height; top>>=1; + + // Create the window: + FrameWnd=CreateWindow(wc.lpszClassName,AppName,style|WS_VISIBLE, + left,top,width,height,NULL,NULL,NULL,NULL); + + return 0; +} + +// -------------------- + +static DWORD WINAPI ThreadCode(void *) +{ + LoopCode(); + return 0; +} + +// starscream needs this +unsigned char *rom_data = 0; +unsigned int rom_size = 0; + +int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR cmdline,int) +{ + MSG msg; + int ret=0; + DWORD tid=0; + HANDLE thread=NULL; + + // notaz: load rom + static char rompath[MAX_PATH]; rompath[0] = 0; + strcpy(rompath, cmdline + (cmdline[0] == '\"' ? 1 : 0)); + if(rompath[strlen(rompath)-1] == '\"') rompath[strlen(rompath)-1] = 0; + + FILE *rom = 0; + if(strlen(rompath) > 4) rom = fopen(rompath, "rb"); + if(!rom) { + OPENFILENAME of; ZeroMemory(&of, sizeof(OPENFILENAME)); + of.lStructSize = sizeof(OPENFILENAME); + of.lpstrFilter = "ROMs\0*.smd;*.bin;*.gen\0"; + of.lpstrFile = rompath; rompath[0] = 0; + of.nMaxFile = MAX_PATH; + of.Flags = OFN_FILEMUSTEXIST|OFN_HIDEREADONLY; + if(!GetOpenFileName(&of)) return 1; + rom = fopen(rompath, "rb"); + if(!rom) return 1; + } + romname = rompath; + + if(PicoCartLoad(rom, &rom_data, &rom_size)) { + //RDebug::Print(_L("PicoCartLoad() failed.")); + //goto cleanup; + } + + FrameInit(); + ret=LoopInit(); if (ret) { LoopExit(); return 1; } + + PicoCartInsert(rom_data, rom_size); + + // only now we got the mode (pal/ntsc), so init sound now + DSoundInit(); + + preLoopInit(); + + // Make another thread to run LoopCode(): + LoopQuit=0; + thread=CreateThread(NULL,0,ThreadCode,NULL,0,&tid); + + // Main window loop: + for (;;) + { + GetMessage(&msg,NULL,0,0); + if (msg.message==WM_QUIT) break; + + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + // Signal thread to quit and wait for it to exit: + LoopQuit=1; WaitForSingleObject(thread,5000); + CloseHandle(thread); thread=NULL; + + LoopExit(); + DestroyWindow(FrameWnd); + + free(rom_data); + + _CrtDumpMemoryLeaks(); + return 0; +} +#endif + diff --git a/platform/win32/GenaDrive/Rom.cpp b/platform/win32/GenaDrive/Rom.cpp new file mode 100644 index 00000000..9192dcf9 --- /dev/null +++ b/platform/win32/GenaDrive/Rom.cpp @@ -0,0 +1,143 @@ + +#include "app.h" +#include "Unzip.h" + +unsigned char *RomData=NULL; +int RomLen=0; +char RomName[260]=""; + + +static int Byteswap(unsigned char *data,int len) +{ + int i=0; + + if (len<2) return 1; // Too short + + do + { + unsigned short *pd=(unsigned short *)(data+i); + int word=*pd; // Get word + + word=(word<<8)|(word>>8); // Byteswap it + *pd=(unsigned short)word; // Put word + i+=2; + } + while (i+2<=len); + + return 0; +} + +// Interleve a 16k block and byteswap +static int InterleveBlock(unsigned char *dest,unsigned char *src) +{ + int i=0; + for (i=0;i<0x2000;i++) dest[(i<<1) ]=src[ i]; // Odd + for (i=0;i<0x2000;i++) dest[(i<<1)+1]=src[0x2000+i]; // Even + return 0; +} + +// Decode a SMD file +static int DecodeSmd(unsigned char *data,int len) +{ + unsigned char *temp=NULL; + int i=0; + + temp=(unsigned char *)malloc(0x4000); + if (temp==NULL) return 1; + memset(temp,0,0x4000); + + // Interleve each 16k block and shift down by 0x200: + for (i=0; i+0x4200<=len; i+=0x4000) + { + InterleveBlock(temp,data+0x200+i); // Interleve 16k to temporary buffer + memcpy(data+i,temp,0x4000); // Copy back in + } + + free(temp); + return 0; +} + +int RomLoad() +{ + FILE *file=NULL; + char *name=NULL; + int nameLen=0; + int fileLen=0,space=0; + Unzip unzip; + + name=RomName; + + file=fopen(name,"rb"); if (file==NULL) return 1; + + nameLen=strlen(name); + if (stricmp(name+nameLen-4,".zip")==0) unzip.file=file; // Open as zip file + + if (unzip.file) + { + int ret=0; + + ret=unzip.fileOpen(); // Get first entry + if (ret==0) + { + fileLen=unzip.dataLen; // Length of file + // Switch to using the name in the zip file: + name=unzip.name; nameLen=strlen(name); + } + else + { + unzip.file=NULL; + } + + } + else + { + // Find out the length of the file: + fseek(file,0,SEEK_END); fileLen=ftell(file); + fseek(file,0,SEEK_SET); + } + + // Allocate space for it: + space=(fileLen+0x3fff)&~0x3fff; + + RomData=(unsigned char *)malloc(space); + if (RomData==NULL) { fclose(file); return 1; } + memset(RomData,0,space); + + // Read in file: + if (unzip.file) unzip.fileDecode(RomData); + else fread(RomData,1,fileLen,file); + + unzip.fileClose(); + + fclose(file); + unzip.file=file=NULL; + + RomLen=fileLen; + + // Check for SMD: + if ((fileLen&0x3fff)==0x200) + { + // Decode and byteswap: + DecodeSmd(RomData,RomLen); + RomLen-=0x200; + } + else + { + // Just byteswap: + Byteswap(RomData,RomLen); + } + + PicoCartInsert(RomData,RomLen); + + return 0; +} + +void RomFree() +{ +// PicoCartInsert(NULL,0); // Unplug rom + + if (RomData) free(RomData); + RomData=NULL; RomLen=0; + memset(RomName,0,sizeof(RomName)); +} + diff --git a/platform/win32/GenaDrive/TexScreen.cpp b/platform/win32/GenaDrive/TexScreen.cpp new file mode 100644 index 00000000..45eeab73 --- /dev/null +++ b/platform/win32/GenaDrive/TexScreen.cpp @@ -0,0 +1,107 @@ + +#include "app.h" + +IDirect3DTexture8 *TexScreen=NULL; +int TexWidth=0,TexHeight=0; + +// Blank the texture: +static int TexBlank() +{ + D3DLOCKED_RECT lock={0,NULL}; + unsigned char *dest=NULL; + int y=0,line=0; + + TexScreen->LockRect(0,&lock,NULL,0); if (lock.pBits==NULL) return 1; + + dest=(unsigned char *)lock.pBits; + for (y=0; yUnlockRect(0); + return 0; +} + +int TexScreenInit() +{ + TexWidth =512; + TexHeight=512; + + Device->CreateTexture(TexWidth,TexHeight,1,0,D3DFMT_R5G6B5,D3DPOOL_MANAGED,&TexScreen); + if (TexScreen==NULL) return 1; + + TexBlank(); + return 0; +} + +void TexScreenExit() +{ + RELEASE(TexScreen) + TexWidth=TexHeight=0; +} + +// Copy screen to a swizzled texture +int TexScreenSwizzle() +{ + D3DLOCKED_RECT lock={0,NULL}; + unsigned char *dest=NULL; + int y=0,sy=0,mask=0; + unsigned short *ps=NULL; + + mask=TexWidth*TexHeight-1; + + TexScreen->LockRect(0,&lock,NULL,0); if (lock.pBits==NULL) return 1; + + dest=(unsigned char *)lock.pBits; + ps=EmuScreen; + + // Write to swizzled locations: + for (y=0,sy=0; yUnlockRect(0); + + return 0; +} + +// Copy screen to a linear texture: +int TexScreenLinear() +{ + D3DLOCKED_RECT lock={0,NULL}; + unsigned char *dest=NULL; + int y=0,line=0; + unsigned short *ps=NULL; + + TexScreen->LockRect(0,&lock,NULL,0); if (lock.pBits==NULL) return 1; + + dest=(unsigned char *)lock.pBits; + ps=EmuScreen; + + for (y=0; yUnlockRect(0); + return 0; +} diff --git a/platform/win32/GenaDrive/Unzip.cpp b/platform/win32/GenaDrive/Unzip.cpp new file mode 100644 index 00000000..d152de99 --- /dev/null +++ b/platform/win32/GenaDrive/Unzip.cpp @@ -0,0 +1,109 @@ + + +#include "app.h" +#include "Unzip.h" +#include "zlib.h" + +// Decompress a 'deflate' compressed buffer +static int Inflate(unsigned char *dest,int destLen, unsigned char *src,int srcLen) +{ + z_stream stream; + + memset(&stream,0,sizeof(stream)); + + stream.next_in =src; + stream.avail_in =srcLen; + stream.next_out =dest; + stream.avail_out=destLen; + inflateInit2(&stream,-15); + inflate(&stream,Z_FINISH); + inflateEnd(&stream); + + return 0; +} + +static int Get32(unsigned char *src) +{ + return src[0] | (src[1]<<8) | (src[2]<<16) | (src[3]<<24); +} + +// -------------------------------------------------------------- +Unzip::Unzip() +{ + memset(this,0,sizeof(*this)); +} + +int Unzip::gotoFirstFile() +{ + headerPos=0; + return 0; +} + +int Unzip::fileOpen() +{ + int ret=0,okay=0; + + fseek(file,headerPos,SEEK_SET); + + // Read in file entry header: + ret=fread(head,1,sizeof(head),file); + if (ret!=sizeof(head)) return 1; + + // Check header: + if (head[0]=='P' && head[1]=='K' && head[2]==3 && head[3]==4) okay=1; + if (okay==0) return 1; + + // Get compressed and uncompressed sizes: + srcLen =Get32(head+0x12); + dataLen=Get32(head+0x16); + + // Get size of name and extra fields: + nameLen=Get32(head+0x1a); + extraLen=nameLen>>16; nameLen&=0xffff; + + // Read in name: + name=(char *)malloc(nameLen+1); if (name==NULL) return 1; + memset(name,0,nameLen+1); + fread(name,1,nameLen,file); + + // Find position of compressed data in the file + compPos=headerPos+sizeof(head); + compPos+=nameLen+extraLen; + + return 0; +} + +int Unzip::fileClose() +{ + free(name); name=NULL; + + // Go to next header: + headerPos=compPos+srcLen; + + srcLen=dataLen=0; + nameLen=extraLen=0; + + return 0; +} + +int Unzip::fileDecode(unsigned char *data) +{ + unsigned char *src=NULL; + + // Go to compressed data: + fseek(file,compPos,SEEK_SET); + + // Allocate memory: + src=(unsigned char *)malloc(srcLen); + if (src==NULL) { fclose(file); return 1; } + memset(src,0,srcLen); + + // Read in compressed version and decompress + fread(src,1,srcLen,file); + + Inflate(data,dataLen, src,srcLen); + + free(src); src=NULL; srcLen=0; + + return 0; +} diff --git a/platform/win32/GenaDrive/Unzip.h b/platform/win32/GenaDrive/Unzip.h new file mode 100644 index 00000000..8086b4b4 --- /dev/null +++ b/platform/win32/GenaDrive/Unzip.h @@ -0,0 +1,23 @@ + + +class Unzip +{ +public: + Unzip(); + FILE *file; // Zip file current open + unsigned char head[0x1e]; // Zip entry header + int dataLen; // Zip entry dest (uncompressed) size + + char *name; // Name of entry + + int gotoFirstFile(); + int fileOpen(); + int fileClose(); + int fileDecode(unsigned char *data); + +private: + int srcLen; // Zip entry source (compressed) size + int nameLen,extraLen; // Length of name field and extra fields + int headerPos; // Position of file entry header (PK... etc) + int compPos; // Position of compressed data +}; diff --git a/platform/win32/GenaDrive/app.h b/platform/win32/GenaDrive/app.h new file mode 100644 index 00000000..43f756e4 --- /dev/null +++ b/platform/win32/GenaDrive/app.h @@ -0,0 +1,108 @@ + +#include + +#ifdef _XBOX +#include +#endif + +#ifndef _XBOX +#define WIN32_LEAN_AND_MEAN +#include +#include +#endif + +#include + +#include "Pico.h" + +#define PI 3.14159265f + +#define RELEASE(x) if (x) x->Release(); x=NULL; + +#ifdef _XBOX +#define HOME "d:\\" +#else +#define HOME ".\\" +#endif + +// Emu.cpp +extern unsigned short *EmuScreen; +extern int EmuWidth,EmuHeight; +int EmuInit(); +void EmuExit(); +int EmuRomLoad(char *name); +int EmuFrame(); + +// Input.cpp +struct Input +{ + short axis[4]; + unsigned char button[16]; + unsigned char held[16]; // How long has the button been held + char repeat[16]; // Auto-repeat +}; +extern struct Input Inp; +int InputInit(); +void InputExit(); +int InputUpdate(); +int InputLightCal(int cx,int cy,int ux,int uy); + +// LightCal.cpp +int LightCalReset(); +int LightCalUpdate(); +int LightCalRender(); + +// Loop.cpp +void preLoopInit(); +extern char LoopQuit; +extern int LoopMode; + +int LoopInit(); +void LoopExit(); +int LoopCode(); + +// Main.cpp +extern HWND FrameWnd; +extern int MainWidth,MainHeight; +extern char AppName[]; +extern "C" int dprintf(char *format, ...); + +// Rom.cpp +extern unsigned char *RomData; +extern int RomLen; +extern char RomName[260]; +int RomLoad(); +void RomFree(); + +// -------------------------------------------- +// Direct.cpp +extern IDirect3DDevice8 *Device; +extern IDirect3DSurface8 *DirectBack; // Back Buffer +int DirectInit(); +int DirectClear(unsigned int colour); +int DirectScreen(); +int DirectPresent(); +void DirectExit(); + +// DSound.cpp: +int DSoundInit(); +void DSoundExit(); +int DSoundUpdate(); +extern short *DSoundNext; // Buffer for next sound data to put in loop +//extern int DSoundSeg; // Seg length in samples +void DSoundMute(); +void DSoundUnMute(); + +// Font.cpp +int FontInit(); +void FontExit(); +int FontSetColour(unsigned int colour); +int FontText(WCHAR *,int,int); + +// TexScreen.cpp +extern IDirect3DTexture8 *TexScreen; +extern int TexWidth,TexHeight; +int TexScreenInit(); +void TexScreenExit(); +int TexScreenSwizzle(); +int TexScreenLinear(); diff --git a/platform/win32/GenaDrive/port_config.h b/platform/win32/GenaDrive/port_config.h new file mode 100644 index 00000000..9acc7cd1 --- /dev/null +++ b/platform/win32/GenaDrive/port_config.h @@ -0,0 +1,27 @@ +// port specific settings + +#ifndef PORT_CONFIG_H +#define PORT_CONFIG_H + +#define CPU_CALL __fastcall + +// draw2.c +#define START_ROW 0 // which row of tiles to start rendering at? +#define END_ROW 28 // ..end + +// pico.c +#define CAN_HANDLE_240_LINES 0 + +#ifdef __cplusplus +extern "C" { +#endif + +// common debug +int dprintf (char *format, ...); +int dprintf2(char *format, ...); + +#ifdef __cplusplus +} // End of extern "C" +#endif + +#endif //PORT_CONFIG_H diff --git a/platform/win32/GenaDrive/zconf.h b/platform/win32/GenaDrive/zconf.h new file mode 100644 index 00000000..456de063 --- /dev/null +++ b/platform/win32/GenaDrive/zconf.h @@ -0,0 +1,323 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflatePrime z_deflatePrime +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table + +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +# define WIN32 +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tried only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +#define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/platform/win32/GenaDrive/zlib.h b/platform/win32/GenaDrive/zlib.h new file mode 100644 index 00000000..d24cc435 --- /dev/null +++ b/platform/win32/GenaDrive/zlib.h @@ -0,0 +1,1200 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.1, November 17th, 2003 + + Copyright (C) 1995-2003 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.1" +#define ZLIB_VERNUM 0x1210 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by the in-memory functions is the zlib + format, which is a zlib wrapper documented in RFC 1950, wrapped around a + deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + This library does not provide any functions to write gzip files in memory. + However such functions could be easily written using zlib's deflate function, + the documentation in the gzip RFC, and the examples in gzio.c. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + the compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it get to the next deflate block boundary. When decoding the zlib + or gzip format, this will cause inflate() to return immediately after the + header and before the first block. When doing a raw inflate, inflate() will + go ahead and process the first block, and will return when it gets to the end + of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm-adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative + memLevel). msg is set to null if there is no error message. inflateInit2 + does not perform any decompression apart from reading the zlib header if + present: this will be done by inflate(). (So next_in and avail_in may be + modified, but next_out and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate + if this call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by this call of + inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary). + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_stream FAR *strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_stream FAR *strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_stream FAR *strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: QUICKEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); + +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + for the crc. Pre- and post-conditioning (one's complement) is performed + within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_stream FAR *strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int err)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/unzip/unzip.c b/unzip/unzip.c new file mode 100644 index 00000000..4f1786c0 --- /dev/null +++ b/unzip/unzip.c @@ -0,0 +1,623 @@ +#include "unzip.h" + +#include +#include +#include +#include + +#ifdef __SYMBIAN32__ +#include +#else +#include "zlib/zlib.h" +#endif + +/* public globals */ +//int gUnzipQuiet = 0; /* flag controls error messages */ + +#define ERROR_CORRUPT "The zipfile seems to be corrupt, please check it" +#define ERROR_FILESYSTEM "Your filesystem seems to be corrupt, please check it" +#define ERROR_UNSUPPORTED "The format of this zipfile is not supported, please recompress it" + +#define INFLATE_INPUT_BUFFER_MAX 16384 +#ifndef MIN +#define MIN(x,y) ((x)<(y)?(x):(y)) +#endif + + +// notaz +#ifdef __DEBUG_PRINT +void dprintf(char *format, ...); +#define logerror dprintf +void errormsg(const char* extmsg, const char* usermsg, const char* zipname) +{ + dprintf("Error in zipfile %s: %s", zipname, extmsg); +} +#else +#define logerror(x...) +#define errormsg(x...) +#endif + +/* Print a error message */ +//void errormsg(const char* extmsg, const char* usermsg, const char* zipname) { + /* Output to the user with no internal detail */ +// if (!gUnzipQuiet) +// printf("Error in zipfile %s\n%s\n", zipname, usermsg); + /* Output to log file with all informations */ +// logerror("Error in zipfile %s: %s\n", zipname, extmsg); +// printf("Error in zipfile %s: %s\n", zipname, extmsg); +//} + +/* ------------------------------------------------------------------------- + Unzip support + ------------------------------------------------------------------------- */ + +/* Use these to avoid structure padding and byte-ordering problems */ +static UINT16 read_word (char *buf) { + unsigned char *ubuf = (unsigned char *) buf; + + return ((UINT16)ubuf[1] << 8) | (UINT16)ubuf[0]; +} + +/* Use these to avoid structure padding and byte-ordering problems */ +static UINT32 read_dword (char *buf) { + unsigned char *ubuf = (unsigned char *) buf; + + return ((UINT32)ubuf[3] << 24) | ((UINT32)ubuf[2] << 16) | ((UINT32)ubuf[1] << 8) | (UINT32)ubuf[0]; +} + +/* Locate end-of-central-dir sig in buffer and return offset + out: + *offset offset of cent dir start in buffer + return: + ==0 not found + !=0 found, *offset valid +*/ +static int ecd_find_sig (char *buffer, int buflen, int *offset) +{ + static char ecdsig[] = { 'P', 'K', 0x05, 0x06 }; + int i; + for (i=buflen-22; i>=0; i--) { + if (memcmp(buffer+i, ecdsig, 4) == 0) { + *offset = i; + return 1; + } + } + return 0; +} + +/* Read ecd data in zip structure + in: + zip->fp, zip->length zip file + out: + zip->ecd, zip->ecd_length ecd data +*/ +static int ecd_read(ZIP* zip) { + char* buf; + int buf_length = 1024; /* initial buffer length */ + + while (1) { + int offset; + + if (buf_length > zip->length) + buf_length = zip->length; + + if (fseek(zip->fp, zip->length - buf_length, SEEK_SET) != 0) { + return -1; + } + + /* allocate buffer */ + buf = (char*)malloc( buf_length ); + if (!buf) { + return -1; + } + + if (fread( buf, buf_length, 1, zip->fp ) != 1) { + free(buf); + return -1; + } + + if (ecd_find_sig(buf, buf_length, &offset)) { + zip->ecd_length = buf_length - offset; + + zip->ecd = (char*)malloc( zip->ecd_length ); + if (!zip->ecd) { + free(buf); + return -1; + } + + memcpy(zip->ecd, buf + offset, zip->ecd_length); + + free(buf); + return 0; + } + + free(buf); + + if (buf_length < zip->length) { + /* double buffer */ + buf_length = 2*buf_length; + + logerror("Retry reading of zip ecd for %d bytes\n",buf_length); + + } else { + return -1; + } + } +} + +/* offsets in end of central directory structure */ +#define ZIPESIG 0x00 +#define ZIPEDSK 0x04 +#define ZIPECEN 0x06 +#define ZIPENUM 0x08 +#define ZIPECENN 0x0a +#define ZIPECSZ 0x0c +#define ZIPEOFST 0x10 +#define ZIPECOML 0x14 +#define ZIPECOM 0x16 + +/* offsets in central directory entry structure */ +#define ZIPCENSIG 0x0 +#define ZIPCVER 0x4 +#define ZIPCOS 0x5 +#define ZIPCVXT 0x6 +#define ZIPCEXOS 0x7 +#define ZIPCFLG 0x8 +#define ZIPCMTHD 0xa +#define ZIPCTIM 0xc +#define ZIPCDAT 0xe +#define ZIPCCRC 0x10 +#define ZIPCSIZ 0x14 +#define ZIPCUNC 0x18 +#define ZIPCFNL 0x1c +#define ZIPCXTL 0x1e +#define ZIPCCML 0x20 +#define ZIPDSK 0x22 +#define ZIPINT 0x24 +#define ZIPEXT 0x26 +#define ZIPOFST 0x2a +#define ZIPCFN 0x2e + +/* offsets in local file header structure */ +#define ZIPLOCSIG 0x00 +#define ZIPVER 0x04 +#define ZIPGENFLG 0x06 +#define ZIPMTHD 0x08 +#define ZIPTIME 0x0a +#define ZIPDATE 0x0c +#define ZIPCRC 0x0e +#define ZIPSIZE 0x12 +#define ZIPUNCMP 0x16 +#define ZIPFNLN 0x1a +#define ZIPXTRALN 0x1c +#define ZIPNAME 0x1e + +/* Opens a zip stream for reading + return: + !=0 success, zip stream + ==0 error +*/ +ZIP* openzip(const char* zipfile) { + /* allocate */ + ZIP* zip = (ZIP*)malloc( sizeof(ZIP) ); + if (!zip) { + return 0; + } + + /* open */ + zip->fp = fopen(zipfile, "rb"); + if (!zip->fp) { + errormsg ("Opening for reading", ERROR_FILESYSTEM, zipfile); + free(zip); + return 0; + } + + /* go to end */ + if (fseek(zip->fp, 0L, SEEK_END) != 0) { + errormsg ("Seeking to end", ERROR_FILESYSTEM, zipfile); + fclose(zip->fp); + free(zip); + return 0; + } + + /* get length */ + zip->length = ftell(zip->fp); + if (zip->length < 0) { + errormsg ("Get file size", ERROR_FILESYSTEM, zipfile); + fclose(zip->fp); + free(zip); + return 0; + } + if (zip->length == 0) { + errormsg ("Empty file", ERROR_CORRUPT, zipfile); + fclose(zip->fp); + free(zip); + return 0; + } + + /* read ecd data */ + if (ecd_read(zip)!=0) { + errormsg ("Reading ECD (end of central directory)", ERROR_CORRUPT, zipfile); + fclose(zip->fp); + free(zip); + return 0; + } + + /* compile ecd info */ + zip->end_of_cent_dir_sig = read_dword (zip->ecd+ZIPESIG); + zip->number_of_this_disk = read_word (zip->ecd+ZIPEDSK); + zip->number_of_disk_start_cent_dir = read_word (zip->ecd+ZIPECEN); + zip->total_entries_cent_dir_this_disk = read_word (zip->ecd+ZIPENUM); + zip->total_entries_cent_dir = read_word (zip->ecd+ZIPECENN); + zip->size_of_cent_dir = read_dword (zip->ecd+ZIPECSZ); + zip->offset_to_start_of_cent_dir = read_dword (zip->ecd+ZIPEOFST); + zip->zipfile_comment_length = read_word (zip->ecd+ZIPECOML); + zip->zipfile_comment = zip->ecd+ZIPECOM; + + /* verify that we can work with this zipfile (no disk spanning allowed) */ + if ((zip->number_of_this_disk != zip->number_of_disk_start_cent_dir) || + (zip->total_entries_cent_dir_this_disk != zip->total_entries_cent_dir) || + (zip->total_entries_cent_dir < 1)) { + errormsg("Cannot span disks", ERROR_UNSUPPORTED, zipfile); + free(zip->ecd); + fclose(zip->fp); + free(zip); + return 0; + } + + if (fseek(zip->fp, zip->offset_to_start_of_cent_dir, SEEK_SET)!=0) { + errormsg ("Seeking to central directory", ERROR_CORRUPT, zipfile); + free(zip->ecd); + fclose(zip->fp); + free(zip); + return 0; + } + + /* read from start of central directory */ + zip->cd = (char*)malloc( zip->size_of_cent_dir ); + if (!zip->cd) { + free(zip->ecd); + fclose(zip->fp); + free(zip); + return 0; + } + + if (fread(zip->cd, zip->size_of_cent_dir, 1, zip->fp)!=1) { + errormsg ("Reading central directory", ERROR_CORRUPT, zipfile); + free(zip->cd); + free(zip->ecd); + fclose(zip->fp); + free(zip); + return 0; + } + + /* reset ent */ + zip->ent.name = 0; + + /* rewind */ + zip->cd_pos = 0; + + /* file name */ + zip->zip = (char*)malloc(strlen(zipfile)+1); + if (!zip->zip) { + free(zip->cd); + free(zip->ecd); + fclose(zip->fp); + free(zip); + return 0; + } + strcpy(zip->zip, zipfile); + + return zip; +} + +/* Reads the current entry from a zip stream + in: + zip opened zip + return: + !=0 success + ==0 error +*/ +struct zipent* readzip(ZIP* zip) { + + /* end of directory */ + if (zip->cd_pos >= zip->size_of_cent_dir) + return 0; + + /* compile zipent info */ + zip->ent.cent_file_header_sig = read_dword (zip->cd+zip->cd_pos+ZIPCENSIG); + zip->ent.version_made_by = *(zip->cd+zip->cd_pos+ZIPCVER); + zip->ent.host_os = *(zip->cd+zip->cd_pos+ZIPCOS); + zip->ent.version_needed_to_extract = *(zip->cd+zip->cd_pos+ZIPCVXT); + zip->ent.os_needed_to_extract = *(zip->cd+zip->cd_pos+ZIPCEXOS); + zip->ent.general_purpose_bit_flag = read_word (zip->cd+zip->cd_pos+ZIPCFLG); + zip->ent.compression_method = read_word (zip->cd+zip->cd_pos+ZIPCMTHD); + zip->ent.last_mod_file_time = read_word (zip->cd+zip->cd_pos+ZIPCTIM); + zip->ent.last_mod_file_date = read_word (zip->cd+zip->cd_pos+ZIPCDAT); + zip->ent.crc32 = read_dword (zip->cd+zip->cd_pos+ZIPCCRC); + zip->ent.compressed_size = read_dword (zip->cd+zip->cd_pos+ZIPCSIZ); + zip->ent.uncompressed_size = read_dword (zip->cd+zip->cd_pos+ZIPCUNC); + zip->ent.filename_length = read_word (zip->cd+zip->cd_pos+ZIPCFNL); + zip->ent.extra_field_length = read_word (zip->cd+zip->cd_pos+ZIPCXTL); + zip->ent.file_comment_length = read_word (zip->cd+zip->cd_pos+ZIPCCML); + zip->ent.disk_number_start = read_word (zip->cd+zip->cd_pos+ZIPDSK); + zip->ent.internal_file_attrib = read_word (zip->cd+zip->cd_pos+ZIPINT); + zip->ent.external_file_attrib = read_dword (zip->cd+zip->cd_pos+ZIPEXT); + zip->ent.offset_lcl_hdr_frm_frst_disk = read_dword (zip->cd+zip->cd_pos+ZIPOFST); + + /* check to see if filename length is illegally long (past the size of this directory + entry) */ + if (zip->cd_pos + ZIPCFN + zip->ent.filename_length > zip->size_of_cent_dir) + { + errormsg("Invalid filename length in directory", ERROR_CORRUPT,zip->zip); + return 0; + } + + /* copy filename */ + free(zip->ent.name); + zip->ent.name = (char*)malloc(zip->ent.filename_length + 1); + memcpy(zip->ent.name, zip->cd+zip->cd_pos+ZIPCFN, zip->ent.filename_length); + zip->ent.name[zip->ent.filename_length] = 0; + + /* skip to next entry in central dir */ + zip->cd_pos += ZIPCFN + zip->ent.filename_length + zip->ent.extra_field_length + zip->ent.file_comment_length; + + return &zip->ent; +} + +/* Closes a zip stream */ +void closezip(ZIP* zip) { + /* release all */ + free(zip->ent.name); + free(zip->cd); + free(zip->ecd); + /* only if not suspended */ + if (zip->fp) + fclose(zip->fp); + free(zip->zip); + free(zip); +} + +/* Suspend access to a zip file (release file handler) + in: + zip opened zip + note: + A suspended zip is automatically reopened at first call of + readuncompressd() or readcompressed() functions +*/ +void suspendzip(ZIP* zip) { + if (zip->fp) { + fclose(zip->fp); + zip->fp = 0; + } +} + +/* Revive a suspended zip file (reopen file handler) + in: + zip suspended zip + return: + zip success + ==0 error (zip must be closed with closezip) +*/ +static ZIP* revivezip(ZIP* zip) { + if (!zip->fp) { + zip->fp = fopen(zip->zip, "rb"); + if (!zip->fp) { + return 0; + } + } + return zip; + +} + +/* Reset a zip stream to the first entry + in: + zip opened zip + note: + ZIP file must be opened and not suspended +*/ +void rewindzip(ZIP* zip) { + zip->cd_pos = 0; +} + +/* Seek zip->fp to compressed data + return: + ==0 success + <0 error +*/ +int seekcompresszip(ZIP* zip, struct zipent* ent) { + char buf[ZIPNAME]; + long offset; + + if (!zip->fp) { + if (!revivezip(zip)) + return -1; + } + + if (fseek(zip->fp, ent->offset_lcl_hdr_frm_frst_disk, SEEK_SET)!=0) { + errormsg ("Seeking to header", ERROR_CORRUPT, zip->zip); + return -1; + } + + if (fread(buf, ZIPNAME, 1, zip->fp)!=1) { + errormsg ("Reading header", ERROR_CORRUPT, zip->zip); + return -1; + } + + { + UINT16 filename_length = read_word (buf+ZIPFNLN); + UINT16 extra_field_length = read_word (buf+ZIPXTRALN); + + /* calculate offset to data and fseek() there */ + offset = ent->offset_lcl_hdr_frm_frst_disk + ZIPNAME + filename_length + extra_field_length; + + if (fseek(zip->fp, offset, SEEK_SET) != 0) { + errormsg ("Seeking to compressed data", ERROR_CORRUPT, zip->zip); + return -1; + } + + } + + return 0; +} + +/* Inflate a file + in: + in_file stream to inflate + in_size size of the compressed data to read + out_size size of decompressed data + out: + out_data buffer for decompressed data + return: + ==0 ok + + 990525 rewritten for use with zlib MLR +*/ +static int inflate_file(FILE* in_file, unsigned in_size, unsigned char* out_data, unsigned out_size) +{ + int err; + unsigned char* in_buffer; + z_stream d_stream; /* decompression stream */ + + d_stream.zalloc = 0; + d_stream.zfree = 0; + d_stream.opaque = 0; + + d_stream.next_in = 0; + d_stream.avail_in = 0; + d_stream.next_out = out_data; + d_stream.avail_out = out_size; + + err = inflateInit2(&d_stream, -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + */ + if (err != Z_OK) + { + logerror("inflateInit error: %d\n", err); + return -1; + } + + in_buffer = (unsigned char*)malloc(INFLATE_INPUT_BUFFER_MAX+1); + if (!in_buffer) + return -1; + + for (;;) + { + if (in_size <= 0) + { + logerror("inflate error: compressed size too small\n"); + free (in_buffer); + return -1; + } + d_stream.next_in = in_buffer; + d_stream.avail_in = fread (in_buffer, 1, MIN(in_size, INFLATE_INPUT_BUFFER_MAX), in_file); + in_size -= d_stream.avail_in; + if (in_size == 0) + d_stream.avail_in++; /* add dummy byte at end of compressed data */ + + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) + break; + if (err != Z_OK) + { + logerror("inflate error: %d\n", err); + free (in_buffer); + return -1; + } + } + + err = inflateEnd(&d_stream); + if (err != Z_OK) + { + logerror("inflateEnd error: %d\n", err); + free (in_buffer); + return -1; + } + + free (in_buffer); + + if ((d_stream.avail_out > 0) || (in_size > 0)) + { + logerror("zip size mismatch. %i\n", in_size); + return -1; + } + + return 0; +} + +/* Read compressed data + out: + data compressed data read + return: + ==0 success + <0 error +*/ +int readcompresszip(ZIP* zip, struct zipent* ent, char* data) { + int err = seekcompresszip(zip,ent); + if (err!=0) + return err; + + if (fread(data, ent->compressed_size, 1, zip->fp)!=1) { + errormsg ("Reading compressed data", ERROR_CORRUPT, zip->zip); + return -1; + } + + return 0; +} + +/* Read UNcompressed data + out: + data UNcompressed data + return: + ==0 success + <0 error +*/ +int readuncompresszip(ZIP* zip, struct zipent* ent, char* data) { + if (ent->compression_method == 0x0000) { + /* file is not compressed, simply stored */ + + /* check if size are equal */ + if (ent->compressed_size != ent->uncompressed_size) { + errormsg("Wrong uncompressed size in store compression", ERROR_CORRUPT,zip->zip); + return -3; + } + + return readcompresszip(zip,ent,data); + } else if (ent->compression_method == 0x0008) { + /* file is compressed using "Deflate" method */ + if (ent->version_needed_to_extract > 0x14) { + errormsg("Version too new", ERROR_UNSUPPORTED,zip->zip); + return -2; + } + + if (ent->os_needed_to_extract != 0x00) { + errormsg("OS not supported", ERROR_UNSUPPORTED,zip->zip); + return -2; + } + + if (ent->disk_number_start != zip->number_of_this_disk) { + errormsg("Cannot span disks", ERROR_UNSUPPORTED,zip->zip); + return -2; + } + + /* read compressed data */ + if (seekcompresszip(zip,ent)!=0) { + return -1; + } + + /* configure inflate */ + if (inflate_file( zip->fp, ent->compressed_size, (unsigned char*)data, ent->uncompressed_size)) + { + errormsg("Inflating compressed data", ERROR_CORRUPT, zip->zip); + return -3; + } + + return 0; + } else { + errormsg("Compression method unsupported", ERROR_UNSUPPORTED, zip->zip); + return -2; + } +} diff --git a/unzip/unzip.h b/unzip/unzip.h new file mode 100644 index 00000000..d44f9632 --- /dev/null +++ b/unzip/unzip.h @@ -0,0 +1,144 @@ +#ifndef __UNZIP_H +#define __UNZIP_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// notaz: something's missing this +#ifndef UINT16 +#define UINT32 unsigned int +#define UINT16 unsigned short +#define UINT8 unsigned char +#endif + +/*************************************************************************** + * Support for retrieving files from zipfiles + ***************************************************************************/ + +struct zipent { + UINT32 cent_file_header_sig; + UINT8 version_made_by; + UINT8 host_os; + UINT8 version_needed_to_extract; + UINT8 os_needed_to_extract; + UINT16 general_purpose_bit_flag; + UINT16 compression_method; + UINT16 last_mod_file_time; + UINT16 last_mod_file_date; + UINT32 crc32; + UINT32 compressed_size; + UINT32 uncompressed_size; + UINT16 filename_length; + UINT16 extra_field_length; + UINT16 file_comment_length; + UINT16 disk_number_start; + UINT16 internal_file_attrib; + UINT32 external_file_attrib; + UINT32 offset_lcl_hdr_frm_frst_disk; + char* name; /* 0 terminated */ +}; + +typedef struct _ZIP { + char* zip; /* zip name */ + FILE* fp; /* zip handler */ + long length; /* length of zip file */ + + char* ecd; /* end_of_cent_dir data */ + unsigned ecd_length; /* end_of_cent_dir length */ + + char* cd; /* cent_dir data */ + + unsigned cd_pos; /* position in cent_dir */ + + struct zipent ent; /* buffer for readzip */ + + /* end_of_cent_dir */ + UINT32 end_of_cent_dir_sig; + UINT16 number_of_this_disk; + UINT16 number_of_disk_start_cent_dir; + UINT16 total_entries_cent_dir_this_disk; + UINT16 total_entries_cent_dir; + UINT32 size_of_cent_dir; + UINT32 offset_to_start_of_cent_dir; + UINT16 zipfile_comment_length; + char* zipfile_comment; /* pointer in ecd */ +} ZIP; + +/* Opens a zip stream for reading + return: + !=0 success, zip stream + ==0 error +*/ +ZIP* openzip(const char* path); + +/* Closes a zip stream */ +void closezip(ZIP* zip); + +/* Reads the current entry from a zip stream + in: + zip opened zip + return: + !=0 success + ==0 error +*/ +struct zipent* readzip(ZIP* zip); + +/* Suspend access to a zip file (release file handler) + in: + zip opened zip + note: + A suspended zip is automatically reopened at first call of + readuncompressd() or readcompressed() functions +*/ +void suspendzip(ZIP* zip); + +/* Resets a zip stream to the first entry + in: + zip opened zip + note: + ZIP file must be opened and not suspended +*/ +void rewindzip(ZIP* zip); + +/* Read compressed data from a zip entry + in: + zip opened zip + ent entry to read + out: + data buffer for data, ent.compressed_size UINT8s allocated by the caller + return: + ==0 success + <0 error +*/ +int readcompresszip(ZIP* zip, struct zipent* ent, char* data); + +/* Read decompressed data from a zip entry + in: + zip zip stream open + ent entry to read + out: + data buffer for data, ent.uncompressed_size UINT8s allocated by the caller + return: + ==0 success + <0 error +*/ +int readuncompresszip(ZIP* zip, struct zipent* ent, char* data); + +/* public functions */ +int /* error */ load_zipped_file (const char *zipfile, const char *filename, + unsigned char **buf, unsigned int *length); +int /* error */ checksum_zipped_file (const char *zipfile, const char *filename, unsigned int *length, unsigned int *sum); + +void unzip_cache_clear(void); + +/* public globals */ +extern int gUnzipQuiet; /* flag controls error messages */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/zlib/ChangeLog b/zlib/ChangeLog new file mode 100644 index 00000000..7f6869d3 --- /dev/null +++ b/zlib/ChangeLog @@ -0,0 +1,855 @@ + + ChangeLog file for zlib + +Changes in 1.2.3 (18 July 2005) +- Apply security vulnerability fixes to contrib/infback9 as well +- Clean up some text files (carriage returns, trailing space) +- Update testzlib, vstudio, masmx64, and masmx86 in contrib [Vollant] + +Changes in 1.2.2.4 (11 July 2005) +- Add inflatePrime() function for starting inflation at bit boundary +- Avoid some Visual C warnings in deflate.c +- Avoid more silly Visual C warnings in inflate.c and inftrees.c for 64-bit + compile +- Fix some spelling errors in comments [Betts] +- Correct inflateInit2() error return documentation in zlib.h +- Added zran.c example of compressed data random access to examples + directory, shows use of inflatePrime() +- Fix cast for assignments to strm->state in inflate.c and infback.c +- Fix zlibCompileFlags() in zutil.c to use 1L for long shifts [Oberhumer] +- Move declarations of gf2 functions to right place in crc32.c [Oberhumer] +- Add cast in trees.c t avoid a warning [Oberhumer] +- Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer] +- Update make_vms.com [Zinser] +- Initialize state->write in inflateReset() since copied in inflate_fast() +- Be more strict on incomplete code sets in inflate_table() and increase + ENOUGH and MAXD -- this repairs a possible security vulnerability for + invalid inflate input. Thanks to Tavis Ormandy and Markus Oberhumer for + discovering the vulnerability and providing test cases. +- Add ia64 support to configure for HP-UX [Smith] +- Add error return to gzread() for format or i/o error [Levin] +- Use malloc.h for OS/2 [Necasek] + +Changes in 1.2.2.3 (27 May 2005) +- Replace 1U constants in inflate.c and inftrees.c for 64-bit compile +- Typecast fread() return values in gzio.c [Vollant] +- Remove trailing space in minigzip.c outmode (VC++ can't deal with it) +- Fix crc check bug in gzread() after gzungetc() [Heiner] +- Add the deflateTune() function to adjust internal compression parameters +- Add a fast gzip decompressor, gun.c, to examples (use of inflateBack) +- Remove an incorrect assertion in examples/zpipe.c +- Add C++ wrapper in infback9.h [Donais] +- Fix bug in inflateCopy() when decoding fixed codes +- Note in zlib.h how much deflateSetDictionary() actually uses +- Remove USE_DICT_HEAD in deflate.c (would mess up inflate if used) +- Add _WIN32_WCE to define WIN32 in zconf.in.h [Spencer] +- Don't include stderr.h or errno.h for _WIN32_WCE in zutil.h [Spencer] +- Add gzdirect() function to indicate transparent reads +- Update contrib/minizip [Vollant] +- Fix compilation of deflate.c when both ASMV and FASTEST [Oberhumer] +- Add casts in crc32.c to avoid warnings [Oberhumer] +- Add contrib/masmx64 [Vollant] +- Update contrib/asm586, asm686, masmx86, testzlib, vstudio [Vollant] + +Changes in 1.2.2.2 (30 December 2004) +- Replace structure assignments in deflate.c and inflate.c with zmemcpy to + avoid implicit memcpy calls (portability for no-library compilation) +- Increase sprintf() buffer size in gzdopen() to allow for large numbers +- Add INFLATE_STRICT to check distances against zlib header +- Improve WinCE errno handling and comments [Chang] +- Remove comment about no gzip header processing in FAQ +- Add Z_FIXED strategy option to deflateInit2() to force fixed trees +- Add updated make_vms.com [Coghlan], update README +- Create a new "examples" directory, move gzappend.c there, add zpipe.c, + fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html. +- Add FAQ entry and comments in deflate.c on uninitialized memory access +- Add Solaris 9 make options in configure [Gilbert] +- Allow strerror() usage in gzio.c for STDC +- Fix DecompressBuf in contrib/delphi/ZLib.pas [ManChesTer] +- Update contrib/masmx86/inffas32.asm and gvmat32.asm [Vollant] +- Use z_off_t for adler32_combine() and crc32_combine() lengths +- Make adler32() much faster for small len +- Use OS_CODE in deflate() default gzip header + +Changes in 1.2.2.1 (31 October 2004) +- Allow inflateSetDictionary() call for raw inflate +- Fix inflate header crc check bug for file names and comments +- Add deflateSetHeader() and gz_header structure for custom gzip headers +- Add inflateGetheader() to retrieve gzip headers +- Add crc32_combine() and adler32_combine() functions +- Add alloc_func, free_func, in_func, out_func to Z_PREFIX list +- Use zstreamp consistently in zlib.h (inflate_back functions) +- Remove GUNZIP condition from definition of inflate_mode in inflate.h + and in contrib/inflate86/inffast.S [Truta, Anderson] +- Add support for AMD64 in contrib/inflate86/inffas86.c [Anderson] +- Update projects/README.projects and projects/visualc6 [Truta] +- Update win32/DLL_FAQ.txt [Truta] +- Avoid warning under NO_GZCOMPRESS in gzio.c; fix typo [Truta] +- Deprecate Z_ASCII; use Z_TEXT instead [Truta] +- Use a new algorithm for setting strm->data_type in trees.c [Truta] +- Do not define an exit() prototype in zutil.c unless DEBUG defined +- Remove prototype of exit() from zutil.c, example.c, minigzip.c [Truta] +- Add comment in zlib.h for Z_NO_FLUSH parameter to deflate() +- Fix Darwin build version identification [Peterson] + +Changes in 1.2.2 (3 October 2004) +- Update zlib.h comments on gzip in-memory processing +- Set adler to 1 in inflateReset() to support Java test suite [Walles] +- Add contrib/dotzlib [Ravn] +- Update win32/DLL_FAQ.txt [Truta] +- Update contrib/minizip [Vollant] +- Move contrib/visual-basic.txt to old/ [Truta] +- Fix assembler builds in projects/visualc6/ [Truta] + +Changes in 1.2.1.2 (9 September 2004) +- Update INDEX file +- Fix trees.c to update strm->data_type (no one ever noticed!) +- Fix bug in error case in inflate.c, infback.c, and infback9.c [Brown] +- Add "volatile" to crc table flag declaration (for DYNAMIC_CRC_TABLE) +- Add limited multitasking protection to DYNAMIC_CRC_TABLE +- Add NO_vsnprintf for VMS in zutil.h [Mozilla] +- Don't declare strerror() under VMS [Mozilla] +- Add comment to DYNAMIC_CRC_TABLE to use get_crc_table() to initialize +- Update contrib/ada [Anisimkov] +- Update contrib/minizip [Vollant] +- Fix configure to not hardcode directories for Darwin [Peterson] +- Fix gzio.c to not return error on empty files [Brown] +- Fix indentation; update version in contrib/delphi/ZLib.pas and + contrib/pascal/zlibpas.pas [Truta] +- Update mkasm.bat in contrib/masmx86 [Truta] +- Update contrib/untgz [Truta] +- Add projects/README.projects [Truta] +- Add project for MS Visual C++ 6.0 in projects/visualc6 [Cadieux, Truta] +- Update win32/DLL_FAQ.txt [Truta] +- Update list of Z_PREFIX symbols in zconf.h [Randers-Pehrson, Truta] +- Remove an unnecessary assignment to curr in inftrees.c [Truta] +- Add OS/2 to exe builds in configure [Poltorak] +- Remove err dummy parameter in zlib.h [Kientzle] + +Changes in 1.2.1.1 (9 January 2004) +- Update email address in README +- Several FAQ updates +- Fix a big fat bug in inftrees.c that prevented decoding valid + dynamic blocks with only literals and no distance codes -- + Thanks to "Hot Emu" for the bug report and sample file +- Add a note to puff.c on no distance codes case. + +Changes in 1.2.1 (17 November 2003) +- Remove a tab in contrib/gzappend/gzappend.c +- Update some interfaces in contrib for new zlib functions +- Update zlib version number in some contrib entries +- Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta] +- Support shared libraries on Hurd and KFreeBSD [Brown] +- Fix error in NO_DIVIDE option of adler32.c + +Changes in 1.2.0.8 (4 November 2003) +- Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas +- Add experimental NO_DIVIDE #define in adler32.c + - Possibly faster on some processors (let me know if it is) +- Correct Z_BLOCK to not return on first inflate call if no wrap +- Fix strm->data_type on inflate() return to correctly indicate EOB +- Add deflatePrime() function for appending in the middle of a byte +- Add contrib/gzappend for an example of appending to a stream +- Update win32/DLL_FAQ.txt [Truta] +- Delete Turbo C comment in README [Truta] +- Improve some indentation in zconf.h [Truta] +- Fix infinite loop on bad input in configure script [Church] +- Fix gzeof() for concatenated gzip files [Johnson] +- Add example to contrib/visual-basic.txt [Michael B.] +- Add -p to mkdir's in Makefile.in [vda] +- Fix configure to properly detect presence or lack of printf functions +- Add AS400 support [Monnerat] +- Add a little Cygwin support [Wilson] + +Changes in 1.2.0.7 (21 September 2003) +- Correct some debug formats in contrib/infback9 +- Cast a type in a debug statement in trees.c +- Change search and replace delimiter in configure from % to # [Beebe] +- Update contrib/untgz to 0.2 with various fixes [Truta] +- Add build support for Amiga [Nikl] +- Remove some directories in old that have been updated to 1.2 +- Add dylib building for Mac OS X in configure and Makefile.in +- Remove old distribution stuff from Makefile +- Update README to point to DLL_FAQ.txt, and add comment on Mac OS X +- Update links in README + +Changes in 1.2.0.6 (13 September 2003) +- Minor FAQ updates +- Update contrib/minizip to 1.00 [Vollant] +- Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta] +- Update POSTINC comment for 68060 [Nikl] +- Add contrib/infback9 with deflate64 decoding (unsupported) +- For MVS define NO_vsnprintf and undefine FAR [van Burik] +- Add pragma for fdopen on MVS [van Burik] + +Changes in 1.2.0.5 (8 September 2003) +- Add OF to inflateBackEnd() declaration in zlib.h +- Remember start when using gzdopen in the middle of a file +- Use internal off_t counters in gz* functions to properly handle seeks +- Perform more rigorous check for distance-too-far in inffast.c +- Add Z_BLOCK flush option to return from inflate at block boundary +- Set strm->data_type on return from inflate + - Indicate bits unused, if at block boundary, and if in last block +- Replace size_t with ptrdiff_t in crc32.c, and check for correct size +- Add condition so old NO_DEFLATE define still works for compatibility +- FAQ update regarding the Windows DLL [Truta] +- INDEX update: add qnx entry, remove aix entry [Truta] +- Install zlib.3 into mandir [Wilson] +- Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta] +- Adapt the zlib interface to the new DLL convention guidelines [Truta] +- Introduce ZLIB_WINAPI macro to allow the export of functions using + the WINAPI calling convention, for Visual Basic [Vollant, Truta] +- Update msdos and win32 scripts and makefiles [Truta] +- Export symbols by name, not by ordinal, in win32/zlib.def [Truta] +- Add contrib/ada [Anisimkov] +- Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta] +- Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant] +- Add contrib/masm686 [Truta] +- Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm + [Truta, Vollant] +- Update contrib/delphi; rename to contrib/pascal; add example [Truta] +- Remove contrib/delphi2; add a new contrib/delphi [Truta] +- Avoid inclusion of the nonstandard in contrib/iostream, + and fix some method prototypes [Truta] +- Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip + [Truta] +- Avoid the use of backslash (\) in contrib/minizip [Vollant] +- Fix file time handling in contrib/untgz; update makefiles [Truta] +- Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines + [Vollant] +- Remove contrib/vstudio/vc15_16 [Vollant] +- Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta] +- Update README.contrib [Truta] +- Invert the assignment order of match_head and s->prev[...] in + INSERT_STRING [Truta] +- Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings + [Truta] +- Compare function pointers with 0, not with NULL or Z_NULL [Truta] +- Fix prototype of syncsearch in inflate.c [Truta] +- Introduce ASMINF macro to be enabled when using an ASM implementation + of inflate_fast [Truta] +- Change NO_DEFLATE to NO_GZCOMPRESS [Truta] +- Modify test_gzio in example.c to take a single file name as a + parameter [Truta] +- Exit the example.c program if gzopen fails [Truta] +- Add type casts around strlen in example.c [Truta] +- Remove casting to sizeof in minigzip.c; give a proper type + to the variable compared with SUFFIX_LEN [Truta] +- Update definitions of STDC and STDC99 in zconf.h [Truta] +- Synchronize zconf.h with the new Windows DLL interface [Truta] +- Use SYS16BIT instead of __32BIT__ to distinguish between + 16- and 32-bit platforms [Truta] +- Use far memory allocators in small 16-bit memory models for + Turbo C [Truta] +- Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in + zlibCompileFlags [Truta] +- Cygwin has vsnprintf [Wilson] +- In Windows16, OS_CODE is 0, as in MSDOS [Truta] +- In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson] + +Changes in 1.2.0.4 (10 August 2003) +- Minor FAQ updates +- Be more strict when checking inflateInit2's windowBits parameter +- Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well +- Add gzip wrapper option to deflateInit2 using windowBits +- Add updated QNX rule in configure and qnx directory [Bonnefoy] +- Make inflate distance-too-far checks more rigorous +- Clean up FAR usage in inflate +- Add casting to sizeof() in gzio.c and minigzip.c + +Changes in 1.2.0.3 (19 July 2003) +- Fix silly error in gzungetc() implementation [Vollant] +- Update contrib/minizip and contrib/vstudio [Vollant] +- Fix printf format in example.c +- Correct cdecl support in zconf.in.h [Anisimkov] +- Minor FAQ updates + +Changes in 1.2.0.2 (13 July 2003) +- Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons +- Attempt to avoid warnings in crc32.c for pointer-int conversion +- Add AIX to configure, remove aix directory [Bakker] +- Add some casts to minigzip.c +- Improve checking after insecure sprintf() or vsprintf() calls +- Remove #elif's from crc32.c +- Change leave label to inf_leave in inflate.c and infback.c to avoid + library conflicts +- Remove inflate gzip decoding by default--only enable gzip decoding by + special request for stricter backward compatibility +- Add zlibCompileFlags() function to return compilation information +- More typecasting in deflate.c to avoid warnings +- Remove leading underscore from _Capital #defines [Truta] +- Fix configure to link shared library when testing +- Add some Windows CE target adjustments [Mai] +- Remove #define ZLIB_DLL in zconf.h [Vollant] +- Add zlib.3 [Rodgers] +- Update RFC URL in deflate.c and algorithm.txt [Mai] +- Add zlib_dll_FAQ.txt to contrib [Truta] +- Add UL to some constants [Truta] +- Update minizip and vstudio [Vollant] +- Remove vestigial NEED_DUMMY_RETURN from zconf.in.h +- Expand use of NO_DUMMY_DECL to avoid all dummy structures +- Added iostream3 to contrib [Schwardt] +- Replace rewind() with fseek() for WinCE [Truta] +- Improve setting of zlib format compression level flags + - Report 0 for huffman and rle strategies and for level == 0 or 1 + - Report 2 only for level == 6 +- Only deal with 64K limit when necessary at compile time [Truta] +- Allow TOO_FAR check to be turned off at compile time [Truta] +- Add gzclearerr() function [Souza] +- Add gzungetc() function + +Changes in 1.2.0.1 (17 March 2003) +- Add Z_RLE strategy for run-length encoding [Truta] + - When Z_RLE requested, restrict matches to distance one + - Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE +- Correct FASTEST compilation to allow level == 0 +- Clean up what gets compiled for FASTEST +- Incorporate changes to zconf.in.h [Vollant] + - Refine detection of Turbo C need for dummy returns + - Refine ZLIB_DLL compilation + - Include additional header file on VMS for off_t typedef +- Try to use _vsnprintf where it supplants vsprintf [Vollant] +- Add some casts in inffast.c +- Enchance comments in zlib.h on what happens if gzprintf() tries to + write more than 4095 bytes before compression +- Remove unused state from inflateBackEnd() +- Remove exit(0) from minigzip.c, example.c +- Get rid of all those darn tabs +- Add "check" target to Makefile.in that does the same thing as "test" +- Add "mostlyclean" and "maintainer-clean" targets to Makefile.in +- Update contrib/inflate86 [Anderson] +- Update contrib/testzlib, contrib/vstudio, contrib/minizip [Vollant] +- Add msdos and win32 directories with makefiles [Truta] +- More additions and improvements to the FAQ + +Changes in 1.2.0 (9 March 2003) +- New and improved inflate code + - About 20% faster + - Does not allocate 32K window unless and until needed + - Automatically detects and decompresses gzip streams + - Raw inflate no longer needs an extra dummy byte at end + - Added inflateBack functions using a callback interface--even faster + than inflate, useful for file utilities (gzip, zip) + - Added inflateCopy() function to record state for random access on + externally generated deflate streams (e.g. in gzip files) + - More readable code (I hope) +- New and improved crc32() + - About 50% faster, thanks to suggestions from Rodney Brown +- Add deflateBound() and compressBound() functions +- Fix memory leak in deflateInit2() +- Permit setting dictionary for raw deflate (for parallel deflate) +- Fix const declaration for gzwrite() +- Check for some malloc() failures in gzio.c +- Fix bug in gzopen() on single-byte file 0x1f +- Fix bug in gzread() on concatenated file with 0x1f at end of buffer + and next buffer doesn't start with 0x8b +- Fix uncompress() to return Z_DATA_ERROR on truncated input +- Free memory at end of example.c +- Remove MAX #define in trees.c (conflicted with some libraries) +- Fix static const's in deflate.c, gzio.c, and zutil.[ch] +- Declare malloc() and free() in gzio.c if STDC not defined +- Use malloc() instead of calloc() in zutil.c if int big enough +- Define STDC for AIX +- Add aix/ with approach for compiling shared library on AIX +- Add HP-UX support for shared libraries in configure +- Add OpenUNIX support for shared libraries in configure +- Use $cc instead of gcc to build shared library +- Make prefix directory if needed when installing +- Correct Macintosh avoidance of typedef Byte in zconf.h +- Correct Turbo C memory allocation when under Linux +- Use libz.a instead of -lz in Makefile (assure use of compiled library) +- Update configure to check for snprintf or vsnprintf functions and their + return value, warn during make if using an insecure function +- Fix configure problem with compile-time knowledge of HAVE_UNISTD_H that + is lost when library is used--resolution is to build new zconf.h +- Documentation improvements (in zlib.h): + - Document raw deflate and inflate + - Update RFCs URL + - Point out that zlib and gzip formats are different + - Note that Z_BUF_ERROR is not fatal + - Document string limit for gzprintf() and possible buffer overflow + - Note requirement on avail_out when flushing + - Note permitted values of flush parameter of inflate() +- Add some FAQs (and even answers) to the FAQ +- Add contrib/inflate86/ for x86 faster inflate +- Add contrib/blast/ for PKWare Data Compression Library decompression +- Add contrib/puff/ simple inflate for deflate format description + +Changes in 1.1.4 (11 March 2002) +- ZFREE was repeated on same allocation on some error conditions. + This creates a security problem described in + http://www.zlib.org/advisory-2002-03-11.txt +- Returned incorrect error (Z_MEM_ERROR) on some invalid data +- Avoid accesses before window for invalid distances with inflate window + less than 32K. +- force windowBits > 8 to avoid a bug in the encoder for a window size + of 256 bytes. (A complete fix will be available in 1.1.5). + +Changes in 1.1.3 (9 July 1998) +- fix "an inflate input buffer bug that shows up on rare but persistent + occasions" (Mark) +- fix gzread and gztell for concatenated .gz files (Didier Le Botlan) +- fix gzseek(..., SEEK_SET) in write mode +- fix crc check after a gzeek (Frank Faubert) +- fix miniunzip when the last entry in a zip file is itself a zip file + (J Lillge) +- add contrib/asm586 and contrib/asm686 (Brian Raiter) + See http://www.muppetlabs.com/~breadbox/software/assembly.html +- add support for Delphi 3 in contrib/delphi (Bob Dellaca) +- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti) +- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren) +- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks) +- added a FAQ file + +- Support gzdopen on Mac with Metrowerks (Jason Linhart) +- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart) +- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young) +- avoid some warnings with Borland C (Tom Tanner) +- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant) +- emulate utime() for WIN32 in contrib/untgz (Gilles Vollant) +- allow several arguments to configure (Tim Mooney, Frodo Looijaard) +- use libdir and includedir in Makefile.in (Tim Mooney) +- support shared libraries on OSF1 V4 (Tim Mooney) +- remove so_locations in "make clean" (Tim Mooney) +- fix maketree.c compilation error (Glenn, Mark) +- Python interface to zlib now in Python 1.5 (Jeremy Hylton) +- new Makefile.riscos (Rich Walker) +- initialize static descriptors in trees.c for embedded targets (Nick Smith) +- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith) +- add the OS/2 files in Makefile.in too (Andrew Zabolotny) +- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane) +- fix maketree.c to allow clean compilation of inffixed.h (Mark) +- fix parameter check in deflateCopy (Gunther Nikl) +- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler) +- Many portability patches by Christian Spieler: + . zutil.c, zutil.h: added "const" for zmem* + . Make_vms.com: fixed some typos + . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists + . msdos/Makefile.msc: remove "default rtl link library" info from obj files + . msdos/Makefile.*: use model-dependent name for the built zlib library + . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc: + new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT) +- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane) +- replace __far with _far for better portability (Christian Spieler, Tom Lane) +- fix test for errno.h in configure (Tim Newsham) + +Changes in 1.1.2 (19 March 98) +- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant) + See http://www.winimage.com/zLibDll/unzip.html +- preinitialize the inflate tables for fixed codes, to make the code + completely thread safe (Mark) +- some simplifications and slight speed-up to the inflate code (Mark) +- fix gzeof on non-compressed files (Allan Schrum) +- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs) +- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn) +- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny) +- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori) +- do not wrap extern "C" around system includes (Tom Lane) +- mention zlib binding for TCL in README (Andreas Kupries) +- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert) +- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson) +- allow "configure --prefix $HOME" (Tim Mooney) +- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson) +- move Makefile.sas to amiga/Makefile.sas + +Changes in 1.1.1 (27 Feb 98) +- fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson) +- remove block truncation heuristic which had very marginal effect for zlib + (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the + compression ratio on some files. This also allows inlining _tr_tally for + matches in deflate_slow. +- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier) + +Changes in 1.1.0 (24 Feb 98) +- do not return STREAM_END prematurely in inflate (John Bowler) +- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler) +- compile with -DFASTEST to get compression code optimized for speed only +- in minigzip, try mmap'ing the input file first (Miguel Albrecht) +- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain + on Sun but significant on HP) + +- add a pointer to experimental unzip library in README (Gilles Vollant) +- initialize variable gcc in configure (Chris Herborth) + +Changes in 1.0.9 (17 Feb 1998) +- added gzputs and gzgets functions +- do not clear eof flag in gzseek (Mark Diekhans) +- fix gzseek for files in transparent mode (Mark Diekhans) +- do not assume that vsprintf returns the number of bytes written (Jens Krinke) +- replace EXPORT with ZEXPORT to avoid conflict with other programs +- added compress2 in zconf.h, zlib.def, zlib.dnt +- new asm code from Gilles Vollant in contrib/asm386 +- simplify the inflate code (Mark): + . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new() + . ZALLOC the length list in inflate_trees_fixed() instead of using stack + . ZALLOC the value area for huft_build() instead of using stack + . Simplify Z_FINISH check in inflate() + +- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8 +- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi) +- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with + the declaration of FAR (Gilles VOllant) +- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann) +- read_buf buf parameter of type Bytef* instead of charf* +- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout) +- do not redeclare unlink in minigzip.c for WIN32 (John Bowler) +- fix check for presence of directories in "make install" (Ian Willis) + +Changes in 1.0.8 (27 Jan 1998) +- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant) +- fix gzgetc and gzputc for big endian systems (Markus Oberhumer) +- added compress2() to allow setting the compression level +- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong) +- use constant arrays for the static trees in trees.c instead of computing + them at run time (thanks to Ken Raeburn for this suggestion). To create + trees.h, compile with GEN_TREES_H and run "make test". +- check return code of example in "make test" and display result +- pass minigzip command line options to file_compress +- simplifying code of inflateSync to avoid gcc 2.8 bug + +- support CC="gcc -Wall" in configure -s (QingLong) +- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn) +- fix test for shared library support to avoid compiler warnings +- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant) +- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit) +- do not use fdopen for Metrowerks on Mac (Brad Pettit)) +- add checks for gzputc and gzputc in example.c +- avoid warnings in gzio.c and deflate.c (Andreas Kleinert) +- use const for the CRC table (Ken Raeburn) +- fixed "make uninstall" for shared libraries +- use Tracev instead of Trace in infblock.c +- in example.c use correct compressed length for test_sync +- suppress +vnocompatwarnings in configure for HPUX (not always supported) + +Changes in 1.0.7 (20 Jan 1998) +- fix gzseek which was broken in write mode +- return error for gzseek to negative absolute position +- fix configure for Linux (Chun-Chung Chen) +- increase stack space for MSC (Tim Wegner) +- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant) +- define EXPORTVA for gzprintf (Gilles Vollant) +- added man page zlib.3 (Rick Rodgers) +- for contrib/untgz, fix makedir() and improve Makefile + +- check gzseek in write mode in example.c +- allocate extra buffer for seeks only if gzseek is actually called +- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant) +- add inflateSyncPoint in zconf.h +- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def + +Changes in 1.0.6 (19 Jan 1998) +- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and + gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code) +- Fix a deflate bug occurring only with compression level 0 (thanks to + Andy Buckler for finding this one). +- In minigzip, pass transparently also the first byte for .Z files. +- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress() +- check Z_FINISH in inflate (thanks to Marc Schluper) +- Implement deflateCopy (thanks to Adam Costello) +- make static libraries by default in configure, add --shared option. +- move MSDOS or Windows specific files to directory msdos +- suppress the notion of partial flush to simplify the interface + (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4) +- suppress history buffer provided by application to simplify the interface + (this feature was not implemented anyway in 1.0.4) +- next_in and avail_in must be initialized before calling inflateInit or + inflateInit2 +- add EXPORT in all exported functions (for Windows DLL) +- added Makefile.nt (thanks to Stephen Williams) +- added the unsupported "contrib" directory: + contrib/asm386/ by Gilles Vollant + 386 asm code replacing longest_match(). + contrib/iostream/ by Kevin Ruland + A C++ I/O streams interface to the zlib gz* functions + contrib/iostream2/ by Tyge Løvset + Another C++ I/O streams interface + contrib/untgz/ by "Pedro A. Aranda Guti\irrez" + A very simple tar.gz file extractor using zlib + contrib/visual-basic.txt by Carlos Rios + How to use compress(), uncompress() and the gz* functions from VB. +- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression + level) in minigzip (thanks to Tom Lane) + +- use const for rommable constants in deflate +- added test for gzseek and gztell in example.c +- add undocumented function inflateSyncPoint() (hack for Paul Mackerras) +- add undocumented function zError to convert error code to string + (for Tim Smithers) +- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code. +- Use default memcpy for Symantec MSDOS compiler. +- Add EXPORT keyword for check_func (needed for Windows DLL) +- add current directory to LD_LIBRARY_PATH for "make test" +- create also a link for libz.so.1 +- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura) +- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX) +- added -soname for Linux in configure (Chun-Chung Chen, +- assign numbers to the exported functions in zlib.def (for Windows DLL) +- add advice in zlib.h for best usage of deflateSetDictionary +- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn) +- allow compilation with ANSI keywords only enabled for TurboC in large model +- avoid "versionString"[0] (Borland bug) +- add NEED_DUMMY_RETURN for Borland +- use variable z_verbose for tracing in debug mode (L. Peter Deutsch). +- allow compilation with CC +- defined STDC for OS/2 (David Charlap) +- limit external names to 8 chars for MVS (Thomas Lund) +- in minigzip.c, use static buffers only for 16-bit systems +- fix suffix check for "minigzip -d foo.gz" +- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee) +- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau) +- added makelcc.bat for lcc-win32 (Tom St Denis) +- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe) +- Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion. +- check for unistd.h in configure (for off_t) +- remove useless check parameter in inflate_blocks_free +- avoid useless assignment of s->check to itself in inflate_blocks_new +- do not flush twice in gzclose (thanks to Ken Raeburn) +- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h +- use NO_ERRNO_H instead of enumeration of operating systems with errno.h +- work around buggy fclose on pipes for HP/UX +- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson) +- fix configure if CC is already equal to gcc + +Changes in 1.0.5 (3 Jan 98) +- Fix inflate to terminate gracefully when fed corrupted or invalid data +- Use const for rommable constants in inflate +- Eliminate memory leaks on error conditions in inflate +- Removed some vestigial code in inflate +- Update web address in README + +Changes in 1.0.4 (24 Jul 96) +- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF + bit, so the decompressor could decompress all the correct data but went + on to attempt decompressing extra garbage data. This affected minigzip too. +- zlibVersion and gzerror return const char* (needed for DLL) +- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno) +- use z_error only for DEBUG (avoid problem with DLLs) + +Changes in 1.0.3 (2 Jul 96) +- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS + small and medium models; this makes the library incompatible with previous + versions for these models. (No effect in large model or on other systems.) +- return OK instead of BUF_ERROR if previous deflate call returned with + avail_out as zero but there is nothing to do +- added memcmp for non STDC compilers +- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly) +- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO) +- better check for 16-bit mode MSC (avoids problem with Symantec) + +Changes in 1.0.2 (23 May 96) +- added Windows DLL support +- added a function zlibVersion (for the DLL support) +- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model) +- Bytef is define's instead of typedef'd only for Borland C +- avoid reading uninitialized memory in example.c +- mention in README that the zlib format is now RFC1950 +- updated Makefile.dj2 +- added algorithm.doc + +Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion] +- fix array overlay in deflate.c which sometimes caused bad compressed data +- fix inflate bug with empty stored block +- fix MSDOS medium model which was broken in 0.99 +- fix deflateParams() which could generated bad compressed data. +- Bytef is define'd instead of typedef'ed (work around Borland bug) +- added an INDEX file +- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32), + Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas) +- speed up adler32 for modern machines without auto-increment +- added -ansi for IRIX in configure +- static_init_done in trees.c is an int +- define unlink as delete for VMS +- fix configure for QNX +- add configure branch for SCO and HPUX +- avoid many warnings (unused variables, dead assignments, etc...) +- no fdopen for BeOS +- fix the Watcom fix for 32 bit mode (define FAR as empty) +- removed redefinition of Byte for MKWERKS +- work around an MWKERKS bug (incorrect merge of all .h files) + +Changes in 0.99 (27 Jan 96) +- allow preset dictionary shared between compressor and decompressor +- allow compression level 0 (no compression) +- add deflateParams in zlib.h: allow dynamic change of compression level + and compression strategy. +- test large buffers and deflateParams in example.c +- add optional "configure" to build zlib as a shared library +- suppress Makefile.qnx, use configure instead +- fixed deflate for 64-bit systems (detected on Cray) +- fixed inflate_blocks for 64-bit systems (detected on Alpha) +- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2) +- always return Z_BUF_ERROR when deflate() has nothing to do +- deflateInit and inflateInit are now macros to allow version checking +- prefix all global functions and types with z_ with -DZ_PREFIX +- make falloc completely reentrant (inftrees.c) +- fixed very unlikely race condition in ct_static_init +- free in reverse order of allocation to help memory manager +- use zlib-1.0/* instead of zlib/* inside the tar.gz +- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith + -Wconversion -Wstrict-prototypes -Wmissing-prototypes" +- allow gzread on concatenated .gz files +- deflateEnd now returns Z_DATA_ERROR if it was premature +- deflate is finally (?) fully deterministic (no matches beyond end of input) +- Document Z_SYNC_FLUSH +- add uninstall in Makefile +- Check for __cpluplus in zlib.h +- Better test in ct_align for partial flush +- avoid harmless warnings for Borland C++ +- initialize hash_head in deflate.c +- avoid warning on fdopen (gzio.c) for HP cc -Aa +- include stdlib.h for STDC compilers +- include errno.h for Cray +- ignore error if ranlib doesn't exist +- call ranlib twice for NeXTSTEP +- use exec_prefix instead of prefix for libz.a +- renamed ct_* as _tr_* to avoid conflict with applications +- clear z->msg in inflateInit2 before any error return +- initialize opaque in example.c, gzio.c, deflate.c and inflate.c +- fixed typo in zconf.h (_GNUC__ => __GNUC__) +- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode) +- fix typo in Make_vms.com (f$trnlnm -> f$getsyi) +- in fcalloc, normalize pointer if size > 65520 bytes +- don't use special fcalloc for 32 bit Borland C++ +- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc... +- use Z_BINARY instead of BINARY +- document that gzclose after gzdopen will close the file +- allow "a" as mode in gzopen. +- fix error checking in gzread +- allow skipping .gz extra-field on pipes +- added reference to Perl interface in README +- put the crc table in FAR data (I dislike more and more the medium model :) +- added get_crc_table +- added a dimension to all arrays (Borland C can't count). +- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast +- guard against multiple inclusion of *.h (for precompiled header on Mac) +- Watcom C pretends to be Microsoft C small model even in 32 bit mode. +- don't use unsized arrays to avoid silly warnings by Visual C++: + warning C4746: 'inflate_mask' : unsized array treated as '__far' + (what's wrong with far data in far model?). +- define enum out of inflate_blocks_state to allow compilation with C++ + +Changes in 0.95 (16 Aug 95) +- fix MSDOS small and medium model (now easier to adapt to any compiler) +- inlined send_bits +- fix the final (:-) bug for deflate with flush (output was correct but + not completely flushed in rare occasions). +- default window size is same for compression and decompression + (it's now sufficient to set MAX_WBITS in zconf.h). +- voidp -> voidpf and voidnp -> voidp (for consistency with other + typedefs and because voidnp was not near in large model). + +Changes in 0.94 (13 Aug 95) +- support MSDOS medium model +- fix deflate with flush (could sometimes generate bad output) +- fix deflateReset (zlib header was incorrectly suppressed) +- added support for VMS +- allow a compression level in gzopen() +- gzflush now calls fflush +- For deflate with flush, flush even if no more input is provided. +- rename libgz.a as libz.a +- avoid complex expression in infcodes.c triggering Turbo C bug +- work around a problem with gcc on Alpha (in INSERT_STRING) +- don't use inline functions (problem with some gcc versions) +- allow renaming of Byte, uInt, etc... with #define. +- avoid warning about (unused) pointer before start of array in deflate.c +- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c +- avoid reserved word 'new' in trees.c + +Changes in 0.93 (25 June 95) +- temporarily disable inline functions +- make deflate deterministic +- give enough lookahead for PARTIAL_FLUSH +- Set binary mode for stdin/stdout in minigzip.c for OS/2 +- don't even use signed char in inflate (not portable enough) +- fix inflate memory leak for segmented architectures + +Changes in 0.92 (3 May 95) +- don't assume that char is signed (problem on SGI) +- Clear bit buffer when starting a stored block +- no memcpy on Pyramid +- suppressed inftest.c +- optimized fill_window, put longest_match inline for gcc +- optimized inflate on stored blocks. +- untabify all sources to simplify patches + +Changes in 0.91 (2 May 95) +- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h +- Document the memory requirements in zconf.h +- added "make install" +- fix sync search logic in inflateSync +- deflate(Z_FULL_FLUSH) now works even if output buffer too short +- after inflateSync, don't scare people with just "lo world" +- added support for DJGPP + +Changes in 0.9 (1 May 95) +- don't assume that zalloc clears the allocated memory (the TurboC bug + was Mark's bug after all :) +- let again gzread copy uncompressed data unchanged (was working in 0.71) +- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented +- added a test of inflateSync in example.c +- moved MAX_WBITS to zconf.h because users might want to change that. +- document explicitly that zalloc(64K) on MSDOS must return a normalized + pointer (zero offset) +- added Makefiles for Microsoft C, Turbo C, Borland C++ +- faster crc32() + +Changes in 0.8 (29 April 95) +- added fast inflate (inffast.c) +- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this + is incompatible with previous versions of zlib which returned Z_OK. +- work around a TurboC compiler bug (bad code for b << 0, see infutil.h) + (actually that was not a compiler bug, see 0.81 above) +- gzread no longer reads one extra byte in certain cases +- In gzio destroy(), don't reference a freed structure +- avoid many warnings for MSDOS +- avoid the ERROR symbol which is used by MS Windows + +Changes in 0.71 (14 April 95) +- Fixed more MSDOS compilation problems :( There is still a bug with + TurboC large model. + +Changes in 0.7 (14 April 95) +- Added full inflate support. +- Simplified the crc32() interface. The pre- and post-conditioning + (one's complement) is now done inside crc32(). WARNING: this is + incompatible with previous versions; see zlib.h for the new usage. + +Changes in 0.61 (12 April 95) +- workaround for a bug in TurboC. example and minigzip now work on MSDOS. + +Changes in 0.6 (11 April 95) +- added minigzip.c +- added gzdopen to reopen a file descriptor as gzFile +- added transparent reading of non-gziped files in gzread. +- fixed bug in gzread (don't read crc as data) +- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose). +- don't allocate big arrays in the stack (for MSDOS) +- fix some MSDOS compilation problems + +Changes in 0.5: +- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but + not yet Z_FULL_FLUSH. +- support decompression but only in a single step (forced Z_FINISH) +- added opaque object for zalloc and zfree. +- added deflateReset and inflateReset +- added a variable zlib_version for consistency checking. +- renamed the 'filter' parameter of deflateInit2 as 'strategy'. + Added Z_FILTERED and Z_HUFFMAN_ONLY constants. + +Changes in 0.4: +- avoid "zip" everywhere, use zlib instead of ziplib. +- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush + if compression method == 8. +- added adler32 and crc32 +- renamed deflateOptions as deflateInit2, call one or the other but not both +- added the method parameter for deflateInit2. +- added inflateInit2 +- simplied considerably deflateInit and inflateInit by not supporting + user-provided history buffer. This is supported only in deflateInit2 + and inflateInit2. + +Changes in 0.3: +- prefix all macro names with Z_ +- use Z_FINISH instead of deflateEnd to finish compression. +- added Z_HUFFMAN_ONLY +- added gzerror() diff --git a/zlib/Makefile b/zlib/Makefile new file mode 100644 index 00000000..2fd6e45c --- /dev/null +++ b/zlib/Makefile @@ -0,0 +1,154 @@ +# Makefile for zlib +# Copyright (C) 1995-2005 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile and test, type: +# ./configure; make test +# The call of configure is optional if you don't have special requirements +# If you wish to build zlib as a shared library, use: ./configure -s + +# To use the asm code, type: +# cp contrib/asm?86/match.S ./match.S +# make LOC=-DASMV OBJA=match.o + +# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type: +# make install +# To install in $HOME instead of /usr/local, use: +# make install prefix=$HOME + +CC=cc + +CFLAGS=-O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-g -DDEBUG +#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ +# -Wstrict-prototypes -Wmissing-prototypes + +LDFLAGS=libz.a +LDSHARED=$(CC) +CPP=$(CC) -E + +LIBS=libz.a +SHAREDLIB=libz.so +SHAREDLIBV=libz.so.1.2.3 +SHAREDLIBM=libz.so.1 + +AR=ar rc +RANLIB=ranlib +TAR=tar +SHELL=/bin/sh +EXE= + +prefix = /usr/local +exec_prefix = ${prefix} +libdir = ${exec_prefix}/lib +includedir = ${prefix}/include +mandir = ${prefix}/share/man +man3dir = ${mandir}/man3 + +OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \ + zutil.o inflate.o infback.o inftrees.o inffast.o + +OBJA = +# to use the asm code: make OBJA=match.o + +TEST_OBJS = example.o minigzip.o + +all: example$(EXE) minigzip$(EXE) + +check: test +test: all + @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \ + echo hello world | ./minigzip | ./minigzip -d || \ + echo ' *** minigzip test FAILED ***' ; \ + if ./example; then \ + echo ' *** zlib test OK ***'; \ + else \ + echo ' *** zlib test FAILED ***'; \ + fi + +libz.a: $(OBJS) $(OBJA) + $(AR) $@ $(OBJS) $(OBJA) + -@ ($(RANLIB) $@ || true) >/dev/null 2>&1 + +match.o: match.S + $(CPP) match.S > _match.s + $(CC) -c _match.s + mv _match.o match.o + rm -f _match.s + +$(SHAREDLIBV): $(OBJS) + $(LDSHARED) -o $@ $(OBJS) + rm -f $(SHAREDLIB) $(SHAREDLIBM) + ln -s $@ $(SHAREDLIB) + ln -s $@ $(SHAREDLIBM) + +example$(EXE): example.o $(LIBS) + $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS) + +minigzip$(EXE): minigzip.o $(LIBS) + $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS) + +install: $(LIBS) + -@if [ ! -d $(exec_prefix) ]; then mkdir -p $(exec_prefix); fi + -@if [ ! -d $(includedir) ]; then mkdir -p $(includedir); fi + -@if [ ! -d $(libdir) ]; then mkdir -p $(libdir); fi + -@if [ ! -d $(man3dir) ]; then mkdir -p $(man3dir); fi + cp zlib.h zconf.h $(includedir) + chmod 644 $(includedir)/zlib.h $(includedir)/zconf.h + cp $(LIBS) $(libdir) + cd $(libdir); chmod 755 $(LIBS) + -@(cd $(libdir); $(RANLIB) libz.a || true) >/dev/null 2>&1 + cd $(libdir); if test -f $(SHAREDLIBV); then \ + rm -f $(SHAREDLIB) $(SHAREDLIBM); \ + ln -s $(SHAREDLIBV) $(SHAREDLIB); \ + ln -s $(SHAREDLIBV) $(SHAREDLIBM); \ + (ldconfig || true) >/dev/null 2>&1; \ + fi + cp zlib.3 $(man3dir) + chmod 644 $(man3dir)/zlib.3 +# The ranlib in install is needed on NeXTSTEP which checks file times +# ldconfig is for Linux + +uninstall: + cd $(includedir); \ + cd $(libdir); rm -f libz.a; \ + if test -f $(SHAREDLIBV); then \ + rm -f $(SHAREDLIBV) $(SHAREDLIB) $(SHAREDLIBM); \ + fi + cd $(man3dir); rm -f zlib.3 + +mostlyclean: clean +clean: + rm -f *.o *~ example$(EXE) minigzip$(EXE) \ + libz.* foo.gz so_locations \ + _match.s maketree contrib/infback9/*.o + +maintainer-clean: distclean +distclean: clean + cp -p Makefile.in Makefile + cp -p zconf.in.h zconf.h + rm -f .DS_Store + +tags: + etags *.[ch] + +depend: + makedepend -- $(CFLAGS) -- *.[ch] + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +adler32.o: zlib.h zconf.h +compress.o: zlib.h zconf.h +crc32.o: crc32.h zlib.h zconf.h +deflate.o: deflate.h zutil.h zlib.h zconf.h +example.o: zlib.h zconf.h +gzio.o: zutil.h zlib.h zconf.h +inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inftrees.o: zutil.h zlib.h zconf.h inftrees.h +minigzip.o: zlib.h zconf.h +trees.o: deflate.h zutil.h zlib.h zconf.h trees.h +uncompr.o: zlib.h zconf.h +zutil.o: zutil.h zlib.h zconf.h diff --git a/zlib/Makefile.in b/zlib/Makefile.in new file mode 100644 index 00000000..2fd6e45c --- /dev/null +++ b/zlib/Makefile.in @@ -0,0 +1,154 @@ +# Makefile for zlib +# Copyright (C) 1995-2005 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile and test, type: +# ./configure; make test +# The call of configure is optional if you don't have special requirements +# If you wish to build zlib as a shared library, use: ./configure -s + +# To use the asm code, type: +# cp contrib/asm?86/match.S ./match.S +# make LOC=-DASMV OBJA=match.o + +# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type: +# make install +# To install in $HOME instead of /usr/local, use: +# make install prefix=$HOME + +CC=cc + +CFLAGS=-O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-g -DDEBUG +#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ +# -Wstrict-prototypes -Wmissing-prototypes + +LDFLAGS=libz.a +LDSHARED=$(CC) +CPP=$(CC) -E + +LIBS=libz.a +SHAREDLIB=libz.so +SHAREDLIBV=libz.so.1.2.3 +SHAREDLIBM=libz.so.1 + +AR=ar rc +RANLIB=ranlib +TAR=tar +SHELL=/bin/sh +EXE= + +prefix = /usr/local +exec_prefix = ${prefix} +libdir = ${exec_prefix}/lib +includedir = ${prefix}/include +mandir = ${prefix}/share/man +man3dir = ${mandir}/man3 + +OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \ + zutil.o inflate.o infback.o inftrees.o inffast.o + +OBJA = +# to use the asm code: make OBJA=match.o + +TEST_OBJS = example.o minigzip.o + +all: example$(EXE) minigzip$(EXE) + +check: test +test: all + @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \ + echo hello world | ./minigzip | ./minigzip -d || \ + echo ' *** minigzip test FAILED ***' ; \ + if ./example; then \ + echo ' *** zlib test OK ***'; \ + else \ + echo ' *** zlib test FAILED ***'; \ + fi + +libz.a: $(OBJS) $(OBJA) + $(AR) $@ $(OBJS) $(OBJA) + -@ ($(RANLIB) $@ || true) >/dev/null 2>&1 + +match.o: match.S + $(CPP) match.S > _match.s + $(CC) -c _match.s + mv _match.o match.o + rm -f _match.s + +$(SHAREDLIBV): $(OBJS) + $(LDSHARED) -o $@ $(OBJS) + rm -f $(SHAREDLIB) $(SHAREDLIBM) + ln -s $@ $(SHAREDLIB) + ln -s $@ $(SHAREDLIBM) + +example$(EXE): example.o $(LIBS) + $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS) + +minigzip$(EXE): minigzip.o $(LIBS) + $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS) + +install: $(LIBS) + -@if [ ! -d $(exec_prefix) ]; then mkdir -p $(exec_prefix); fi + -@if [ ! -d $(includedir) ]; then mkdir -p $(includedir); fi + -@if [ ! -d $(libdir) ]; then mkdir -p $(libdir); fi + -@if [ ! -d $(man3dir) ]; then mkdir -p $(man3dir); fi + cp zlib.h zconf.h $(includedir) + chmod 644 $(includedir)/zlib.h $(includedir)/zconf.h + cp $(LIBS) $(libdir) + cd $(libdir); chmod 755 $(LIBS) + -@(cd $(libdir); $(RANLIB) libz.a || true) >/dev/null 2>&1 + cd $(libdir); if test -f $(SHAREDLIBV); then \ + rm -f $(SHAREDLIB) $(SHAREDLIBM); \ + ln -s $(SHAREDLIBV) $(SHAREDLIB); \ + ln -s $(SHAREDLIBV) $(SHAREDLIBM); \ + (ldconfig || true) >/dev/null 2>&1; \ + fi + cp zlib.3 $(man3dir) + chmod 644 $(man3dir)/zlib.3 +# The ranlib in install is needed on NeXTSTEP which checks file times +# ldconfig is for Linux + +uninstall: + cd $(includedir); \ + cd $(libdir); rm -f libz.a; \ + if test -f $(SHAREDLIBV); then \ + rm -f $(SHAREDLIBV) $(SHAREDLIB) $(SHAREDLIBM); \ + fi + cd $(man3dir); rm -f zlib.3 + +mostlyclean: clean +clean: + rm -f *.o *~ example$(EXE) minigzip$(EXE) \ + libz.* foo.gz so_locations \ + _match.s maketree contrib/infback9/*.o + +maintainer-clean: distclean +distclean: clean + cp -p Makefile.in Makefile + cp -p zconf.in.h zconf.h + rm -f .DS_Store + +tags: + etags *.[ch] + +depend: + makedepend -- $(CFLAGS) -- *.[ch] + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +adler32.o: zlib.h zconf.h +compress.o: zlib.h zconf.h +crc32.o: crc32.h zlib.h zconf.h +deflate.o: deflate.h zutil.h zlib.h zconf.h +example.o: zlib.h zconf.h +gzio.o: zutil.h zlib.h zconf.h +inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inftrees.o: zutil.h zlib.h zconf.h inftrees.h +minigzip.o: zlib.h zconf.h +trees.o: deflate.h zutil.h zlib.h zconf.h trees.h +uncompr.o: zlib.h zconf.h +zutil.o: zutil.h zlib.h zconf.h diff --git a/zlib/README b/zlib/README new file mode 100644 index 00000000..758cc500 --- /dev/null +++ b/zlib/README @@ -0,0 +1,125 @@ +ZLIB DATA COMPRESSION LIBRARY + +zlib 1.2.3 is a general purpose data compression library. All the code is +thread safe. The data format used by the zlib library is described by RFCs +(Request for Comments) 1950 to 1952 in the files +http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) +and rfc1952.txt (gzip format). These documents are also available in other +formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html + +All functions of the compression library are documented in the file zlib.h +(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example +of the library is given in the file example.c which also tests that the library +is working correctly. Another example is given in the file minigzip.c. The +compression library itself is composed of all source files except example.c and +minigzip.c. + +To compile all files and run the test program, follow the instructions given at +the top of Makefile. In short "make test; make install" should work for most +machines. For Unix: "./configure; make test; make install". For MSDOS, use one +of the special makefiles such as Makefile.msc. For VMS, use make_vms.com. + +Questions about zlib should be sent to , or to Gilles Vollant + for the Windows DLL version. The zlib home page is +http://www.zlib.org or http://www.gzip.org/zlib/ Before reporting a problem, +please check this site to verify that you have the latest version of zlib; +otherwise get the latest version and check whether the problem still exists or +not. + +PLEASE read the zlib FAQ http://www.gzip.org/zlib/zlib_faq.html before asking +for help. + +Mark Nelson wrote an article about zlib for the Jan. 1997 +issue of Dr. Dobb's Journal; a copy of the article is available in +http://dogma.net/markn/articles/zlibtool/zlibtool.htm + +The changes made in version 1.2.3 are documented in the file ChangeLog. + +Unsupported third party contributions are provided in directory "contrib". + +A Java implementation of zlib is available in the Java Development Kit +http://java.sun.com/j2se/1.4.2/docs/api/java/util/zip/package-summary.html +See the zlib home page http://www.zlib.org for details. + +A Perl interface to zlib written by Paul Marquess is in the +CPAN (Comprehensive Perl Archive Network) sites +http://www.cpan.org/modules/by-module/Compress/ + +A Python interface to zlib written by A.M. Kuchling is +available in Python 1.5 and later versions, see +http://www.python.org/doc/lib/module-zlib.html + +A zlib binding for TCL written by Andreas Kupries is +availlable at http://www.oche.de/~akupries/soft/trf/trf_zip.html + +An experimental package to read and write files in .zip format, written on top +of zlib by Gilles Vollant , is available in the +contrib/minizip directory of zlib. + + +Notes for some targets: + +- For Windows DLL versions, please see win32/DLL_FAQ.txt + +- For 64-bit Irix, deflate.c must be compiled without any optimization. With + -O, one libpng test fails. The test works in 32 bit mode (with the -n32 + compiler flag). The compiler bug has been reported to SGI. + +- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works + when compiled with cc. + +- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is + necessary to get gzprintf working correctly. This is done by configure. + +- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with + other compilers. Use "make test" to check your compiler. + +- gzdopen is not supported on RISCOS, BEOS and by some Mac compilers. + +- For PalmOs, see http://palmzlib.sourceforge.net/ + +- When building a shared, i.e. dynamic library on Mac OS X, the library must be + installed before testing (do "make install" before "make test"), since the + library location is specified in the library. + + +Acknowledgments: + + The deflate format used by zlib was defined by Phil Katz. The deflate + and zlib specifications were written by L. Peter Deutsch. Thanks to all the + people who reported problems and suggested various improvements in zlib; + they are too numerous to cite here. + +Copyright notice: + + (C) 1995-2004 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* +receiving lengthy legal documents to sign. The sources are provided +for free but without warranty of any kind. The library has been +entirely written by Jean-loup Gailly and Mark Adler; it does not +include third-party code. + +If you redistribute modified sources, we would appreciate that you include +in the file ChangeLog history information documenting your changes. Please +read the FAQ for more information on the distribution of modified source +versions. diff --git a/zlib/adler32.c b/zlib/adler32.c new file mode 100644 index 00000000..007ba262 --- /dev/null +++ b/zlib/adler32.c @@ -0,0 +1,149 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +#define BASE 65521UL /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware */ +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD4(a) \ + do { \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD4(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD4(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* the derivation of this formula is left as an exercise for the reader */ + rem = (unsigned)(len2 % BASE); + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 > BASE) sum1 -= BASE; + if (sum1 > BASE) sum1 -= BASE; + if (sum2 > (BASE << 1)) sum2 -= (BASE << 1); + if (sum2 > BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} diff --git a/zlib/compress.c b/zlib/compress.c new file mode 100644 index 00000000..df04f014 --- /dev/null +++ b/zlib/compress.c @@ -0,0 +1,79 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; +} diff --git a/zlib/crc32.c b/zlib/crc32.c new file mode 100644 index 00000000..f658a9ef --- /dev/null +++ b/zlib/crc32.c @@ -0,0 +1,423 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id$ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +/* Local functions for crc concatenation */ +local unsigned long gf2_matrix_times OF((unsigned long *mat, + unsigned long vec)); +local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); + +#ifdef DYNAMIC_CRC_TABLE + +local volatile int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long FAR *)); +#endif /* MAKECRCH */ +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + unsigned long c; + int n, k; + unsigned long poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static volatile int first = 1; /* flag to limit concurrent making */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* See if another task is already doing this (not thread-safe, but better + than nothing -- significantly reduces duration of vulnerability in + case the advice about DYNAMIC_CRC_TABLE is ignored) */ + if (first) { + first = 0; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, + and then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = REV(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = REV(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + } + else { /* not first */ + /* wait for the other guy to finish (not efficient, but rare) */ + while (crc_table_empty) + ; + } + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const unsigned long FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const unsigned long FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const unsigned long FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + u4 endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(REV(c)); +} + +#endif /* BYFOUR */ + +#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ + +/* ========================================================================= */ +local unsigned long gf2_matrix_times(mat, vec) + unsigned long *mat; + unsigned long vec; +{ + unsigned long sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* ========================================================================= */ +local void gf2_matrix_square(square, mat) + unsigned long *square; + unsigned long *mat; +{ + int n; + + for (n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_t len2; +{ + int n; + unsigned long row; + unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ + unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case */ + if (len2 == 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320L; /* CRC-32 polynomial */ + row = 1; + for (n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(even, odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(odd, even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + do { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(even, odd); + if (len2 & 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + if (len2 == 0) + break; + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(odd, even); + if (len2 & 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; +} diff --git a/zlib/crc32.h b/zlib/crc32.h new file mode 100644 index 00000000..8053b611 --- /dev/null +++ b/zlib/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/zlib/deflate.c b/zlib/deflate.c new file mode 100644 index 00000000..29ce1f64 --- /dev/null +++ b/zlib/deflate.c @@ -0,0 +1,1736 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://www.ietf.org/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id$ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifndef FASTEST +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif +#endif +local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->gzhead = Z_NULL; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); + dictionary += dictLength - length; /* use the tail of the dictionary */ + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetHeader (strm, head) + z_streamp strm; + gz_headerp head; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (strm->state->wrap != 2) return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= */ +int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) + z_streamp strm; + int good_length; + int max_lazy; + int nice_length; + int max_chain; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = good_length; + s->max_lazy_match = max_lazy; + s->nice_match = nice_length; + s->max_chain_length = max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds + * for every combination of windowBits and memLevel, as well as wrap. + * But even the conservative upper bound of about 14% expansion does not + * seem onerous for output buffer allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong destLen; + + /* conservative upper bound */ + destLen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; + + /* if can't get parameters, return conservative bound */ + if (strm == Z_NULL || strm->state == Z_NULL) + return destLen; + + /* if not default parameters, return conservative bound */ + s = strm->state; + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return destLen; + + /* default settings: return tight bound for that case */ + return compressBound(sourceLen); +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } +#ifdef GZIP + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + + while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) + break; + } + put_byte(s, s->gzhead->extra[s->gzindex]); + s->gzindex++; + } + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (s->gzindex == s->gzhead->extra_len) { + s->gzindex = 0; + s->status = NAME_STATE; + } + } + else + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) { + s->gzindex = 0; + s->status = COMMENT_STATE; + } + } + else + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) + s->status = HCRC_STATE; + } + else + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) + flush_pending(strm); + if (s->pending + 2 <= s->pending_buf_size) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + } + } + else + s->status = BUSY_STATE; + } +#endif + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && + status != EXTRA_STATE && + status != NAME_STATE && + status != COMMENT_STATE && + status != HCRC_STATE && + status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + zmemcpy(dest, source, sizeof(z_stream)); + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + zmemcpy(ds, ss, sizeof(deflate_state)); + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifndef FASTEST +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ +#endif /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 or strategy == Z_RLE only + */ +local uInt longest_match_fast(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + /* %%% avoid this when Z_RLE */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ +#ifdef FASTEST + if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) || + (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { + s->match_length = longest_match_fast (s, hash_head); + } +#else + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } +#endif + /* longest_match() or longest_match_fast() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } + /* longest_match() or longest_match_fast() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ + +#if 0 +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + uInt run; /* length of run */ + uInt max; /* maximum length of run */ + uInt prev; /* byte at distance one to match */ + Bytef *scan; /* scan for end of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest encodable run. + */ + if (s->lookahead < MAX_MATCH) { + fill_window(s); + if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + run = 0; + if (s->strstart > 0) { /* if there is a previous byte, that is */ + max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH; + scan = s->window + s->strstart - 1; + prev = *scan++; + do { + if (*scan++ != prev) + break; + } while (++run < max); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (run >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, run); + _tr_tally_dist(s, 1, run - MIN_MATCH, bflush); + s->lookahead -= run; + s->strstart += run; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif diff --git a/zlib/deflate.h b/zlib/deflate.h new file mode 100644 index 00000000..05a5ab3a --- /dev/null +++ b/zlib/deflate.h @@ -0,0 +1,331 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2004 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + uInt pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/zlib/example.c b/zlib/example.c new file mode 100644 index 00000000..6c8a0ee7 --- /dev/null +++ b/zlib/example.c @@ -0,0 +1,565 @@ +/* example.c -- usage example of the zlib compression library + * Copyright (C) 1995-2004 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include +#include "zlib.h" + +#ifdef STDC +# include +# include +#endif + +#if defined(VMS) || defined(RISCOS) +# define TESTFILE "foo-gz" +#else +# define TESTFILE "foo.gz" +#endif + +#define CHECK_ERR(err, msg) { \ + if (err != Z_OK) { \ + fprintf(stderr, "%s error: %d\n", msg, err); \ + exit(1); \ + } \ +} + +const char hello[] = "hello, hello!"; +/* "hello world" would be more standard, but the repeated "hello" + * stresses the compression code better, sorry... + */ + +const char dictionary[] = "hello"; +uLong dictId; /* Adler32 value of the dictionary */ + +void test_compress OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_gzio OF((const char *fname, + Byte *uncompr, uLong uncomprLen)); +void test_deflate OF((Byte *compr, uLong comprLen)); +void test_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_deflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_flush OF((Byte *compr, uLong *comprLen)); +void test_sync OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_dict_deflate OF((Byte *compr, uLong comprLen)); +void test_dict_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +int main OF((int argc, char *argv[])); + +/* =========================================================================== + * Test compress() and uncompress() + */ +void test_compress(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + uLong len = (uLong)strlen(hello)+1; + + err = compress(compr, &comprLen, (const Bytef*)hello, len); + CHECK_ERR(err, "compress"); + + strcpy((char*)uncompr, "garbage"); + + err = uncompress(uncompr, &uncomprLen, compr, comprLen); + CHECK_ERR(err, "uncompress"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad uncompress\n"); + exit(1); + } else { + printf("uncompress(): %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Test read/write of .gz files + */ +void test_gzio(fname, uncompr, uncomprLen) + const char *fname; /* compressed file name */ + Byte *uncompr; + uLong uncomprLen; +{ +#ifdef NO_GZCOMPRESS + fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n"); +#else + int err; + int len = (int)strlen(hello)+1; + gzFile file; + z_off_t pos; + + file = gzopen(fname, "wb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + exit(1); + } + gzputc(file, 'h'); + if (gzputs(file, "ello") != 4) { + fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err)); + exit(1); + } + if (gzprintf(file, ", %s!", "hello") != 8) { + fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err)); + exit(1); + } + gzseek(file, 1L, SEEK_CUR); /* add one zero byte */ + gzclose(file); + + file = gzopen(fname, "rb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + exit(1); + } + strcpy((char*)uncompr, "garbage"); + + if (gzread(file, uncompr, (unsigned)uncomprLen) != len) { + fprintf(stderr, "gzread err: %s\n", gzerror(file, &err)); + exit(1); + } + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad gzread: %s\n", (char*)uncompr); + exit(1); + } else { + printf("gzread(): %s\n", (char*)uncompr); + } + + pos = gzseek(file, -8L, SEEK_CUR); + if (pos != 6 || gztell(file) != pos) { + fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n", + (long)pos, (long)gztell(file)); + exit(1); + } + + if (gzgetc(file) != ' ') { + fprintf(stderr, "gzgetc error\n"); + exit(1); + } + + if (gzungetc(' ', file) != ' ') { + fprintf(stderr, "gzungetc error\n"); + exit(1); + } + + gzgets(file, (char*)uncompr, (int)uncomprLen); + if (strlen((char*)uncompr) != 7) { /* " hello!" */ + fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err)); + exit(1); + } + if (strcmp((char*)uncompr, hello + 6)) { + fprintf(stderr, "bad gzgets after gzseek\n"); + exit(1); + } else { + printf("gzgets() after gzseek: %s\n", (char*)uncompr); + } + + gzclose(file); +#endif +} + +/* =========================================================================== + * Test deflate() with small buffers + */ +void test_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + uLong len = (uLong)strlen(hello)+1; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (Bytef*)hello; + c_stream.next_out = compr; + + while (c_stream.total_in != len && c_stream.total_out < comprLen) { + c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + } + /* Finish the stream, still forcing small buffers: */ + for (;;) { + c_stream.avail_out = 1; + err = deflate(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "deflate"); + } + + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with small buffers + */ +void test_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = 0; + d_stream.next_out = uncompr; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) { + d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate\n"); + exit(1); + } else { + printf("inflate(): %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Test deflate() with large buffers and dynamic change of compression level + */ +void test_large_deflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_SPEED); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + /* At this point, uncompr is still mostly zeroes, so it should compress + * very well: + */ + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + if (c_stream.avail_in != 0) { + fprintf(stderr, "deflate not greedy\n"); + exit(1); + } + + /* Feed in already compressed data and switch to no compression: */ + deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); + c_stream.next_in = compr; + c_stream.avail_in = (uInt)comprLen/2; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + /* Switch back to compressing mode: */ + deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED); + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + exit(1); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with large buffers + */ +void test_large_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + for (;;) { + d_stream.next_out = uncompr; /* discard the output */ + d_stream.avail_out = (uInt)uncomprLen; + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "large inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (d_stream.total_out != 2*uncomprLen + comprLen/2) { + fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out); + exit(1); + } else { + printf("large_inflate(): OK\n"); + } +} + +/* =========================================================================== + * Test deflate() with full flush + */ +void test_flush(compr, comprLen) + Byte *compr; + uLong *comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + uInt len = (uInt)strlen(hello)+1; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (Bytef*)hello; + c_stream.next_out = compr; + c_stream.avail_in = 3; + c_stream.avail_out = (uInt)*comprLen; + err = deflate(&c_stream, Z_FULL_FLUSH); + CHECK_ERR(err, "deflate"); + + compr[3]++; /* force an error in first compressed block */ + c_stream.avail_in = len - 3; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + CHECK_ERR(err, "deflate"); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); + + *comprLen = c_stream.total_out; +} + +/* =========================================================================== + * Test inflateSync() + */ +void test_sync(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = 2; /* just read the zlib header */ + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + inflate(&d_stream, Z_NO_FLUSH); + CHECK_ERR(err, "inflate"); + + d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */ + err = inflateSync(&d_stream); /* but skip the damaged part */ + CHECK_ERR(err, "inflateSync"); + + err = inflate(&d_stream, Z_FINISH); + if (err != Z_DATA_ERROR) { + fprintf(stderr, "inflate should report DATA_ERROR\n"); + /* Because of incorrect adler32 */ + exit(1); + } + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + printf("after inflateSync(): hel%s\n", (char *)uncompr); +} + +/* =========================================================================== + * Test deflate() with preset dictionary + */ +void test_dict_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + err = deflateSetDictionary(&c_stream, + (const Bytef*)dictionary, sizeof(dictionary)); + CHECK_ERR(err, "deflateSetDictionary"); + + dictId = c_stream.adler; + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + c_stream.next_in = (Bytef*)hello; + c_stream.avail_in = (uInt)strlen(hello)+1; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + exit(1); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with a preset dictionary + */ +void test_dict_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + for (;;) { + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + if (err == Z_NEED_DICT) { + if (d_stream.adler != dictId) { + fprintf(stderr, "unexpected dictionary"); + exit(1); + } + err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary, + sizeof(dictionary)); + } + CHECK_ERR(err, "inflate with dict"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate with dict\n"); + exit(1); + } else { + printf("inflate with dictionary: %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Usage: example [output.gz [input.gz]] + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + Byte *compr, *uncompr; + uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */ + uLong uncomprLen = comprLen; + static const char* myVersion = ZLIB_VERSION; + + if (zlibVersion()[0] != myVersion[0]) { + fprintf(stderr, "incompatible zlib version\n"); + exit(1); + + } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) { + fprintf(stderr, "warning: different zlib version\n"); + } + + printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n", + ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags()); + + compr = (Byte*)calloc((uInt)comprLen, 1); + uncompr = (Byte*)calloc((uInt)uncomprLen, 1); + /* compr and uncompr are cleared to avoid reading uninitialized + * data and to ensure that uncompr compresses well. + */ + if (compr == Z_NULL || uncompr == Z_NULL) { + printf("out of memory\n"); + exit(1); + } + test_compress(compr, comprLen, uncompr, uncomprLen); + + test_gzio((argc > 1 ? argv[1] : TESTFILE), + uncompr, uncomprLen); + + test_deflate(compr, comprLen); + test_inflate(compr, comprLen, uncompr, uncomprLen); + + test_large_deflate(compr, comprLen, uncompr, uncomprLen); + test_large_inflate(compr, comprLen, uncompr, uncomprLen); + + test_flush(compr, &comprLen); + test_sync(compr, comprLen, uncompr, uncomprLen); + comprLen = uncomprLen; + + test_dict_deflate(compr, comprLen); + test_dict_inflate(compr, comprLen, uncompr, uncomprLen); + + free(compr); + free(uncompr); + + return 0; +} diff --git a/zlib/gzio.c b/zlib/gzio.c new file mode 100644 index 00000000..7e90f492 --- /dev/null +++ b/zlib/gzio.c @@ -0,0 +1,1026 @@ +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. + */ + +/* @(#) $Id$ */ + +#include + +#include "zutil.h" + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#ifdef __MVS__ +# pragma map (fdopen , "\174\174FDOPEN") + FILE *fdopen(int, const char *); +#endif + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern void free OF((voidpf ptr)); +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + z_off_t start; /* start of compressed data in file (header skipped) */ + z_off_t in; /* bytes into deflate or inflate */ + z_off_t out; /* bytes out of deflate or inflate */ + int back; /* one character push-back */ + int last; /* true if push-back is last character */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_DEFAULT_COMPRESSION; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->in = 0; + s->out = 0; + s->back = EOF; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else if (*p == 'R') { + strategy = Z_RLE; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->start = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * start anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->start = ftell(s->file) - s->stream.avail_in; + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +gzFile ZEXPORT gzdopen (fd, mode) + int fd; + const char *mode; +{ + char name[46]; /* allow for up to 128-bit integers */ + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Assure two bytes in the buffer so we can peek ahead -- handle case + where first byte of header is at the end of the buffer after the last + gzip segment */ + len = s->stream.avail_in; + if (len < 2) { + if (len) s->inbuf[0] = s->stream.next_in[0]; + errno = 0; + len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; + s->stream.avail_in += len; + s->stream.next_in = s->inbuf; + if (s->stream.avail_in < 2) { + s->transparent = s->stream.avail_in; + return; + } + } + + /* Peek ahead to check the gzip magic header */ + if (s->stream.next_in[0] != gz_magic[0] || + s->stream.next_in[1] != gz_magic[1]) { + s->transparent = 1; + return; + } + s->stream.avail_in -= 2; + s->stream.next_in += 2; + + /* Check the rest of the gzip header */ + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + if (s->stream.avail_out && s->back != EOF) { + *next_out++ = s->back; + s->stream.next_out++; + s->stream.avail_out--; + s->back = EOF; + s->out++; + start++; + if (s->last) { + s->z_err = Z_STREAM_END; + return 1; + } + } + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= + (uInt)fread(next_out, 1, s->stream.avail_out, s->file); + } + len -= s->stream.avail_out; + s->in += len; + s->out += len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may be + * different from s->out in case of concatenated .gz files. + * Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + inflateReset(&(s->stream)); + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + if (len == s->stream.avail_out && + (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)) + return -1; + return (int)(len - s->stream.avail_out); +} + + +/* =========================================================================== + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char c; + + return gzread(file, &c, 1) == 1 ? c : -1; +} + + +/* =========================================================================== + Push one byte back onto the stream. +*/ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; + s->back = c; + s->out--; + s->last = (s->z_err == Z_STREAM_END); + if (s->last) s->z_err = Z_OK; + s->z_eof = 0; + return c; +} + + +/* =========================================================================== + Reads bytes from the compressed file until len-1 characters are + read, or a newline character is read and transferred to buf, or an + end-of-file condition is encountered. The string is then terminated + with a null character. + gzgets returns buf, or Z_NULL in case of error. + + The current implementation is not optimized at all. +*/ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + char *b = buf; + if (buf == Z_NULL || len <= 0) return Z_NULL; + + while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; + *buf = '\0'; + return b == buf && len > 0 ? Z_NULL : b; +} + + +#ifndef NO_GZCOMPRESS +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + + +/* =========================================================================== + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ +#ifdef STDC +#include + +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) +{ + char buf[Z_PRINTF_BUFSIZE]; + va_list va; + int len; + + buf[sizeof(buf) - 1] = 0; + va_start(va, format); +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(buf, format, va); + va_end(va); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = vsprintf(buf, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + len = strlen(buf); +# else + len = vsnprintf(buf, sizeof(buf), format, va); + va_end(va); +# endif +#endif + if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, (unsigned)len); +} +#else /* not ANSI C */ + +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + char buf[Z_PRINTF_BUFSIZE]; + int len; + + buf[sizeof(buf) - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(buf); +# else + len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, len); +} +#endif + +/* =========================================================================== + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char cc = (unsigned char) c; /* required for big endian systems */ + + return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; +} + + +/* =========================================================================== + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + return gzwrite(file, (char*)s, (unsigned)strlen(s)); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), flush); + s->out -= s->stream.avail_out; + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +int ZEXPORT gzflush (file, flush) + gzFile file; + int flush; +{ + gz_stream *s = (gz_stream*)file; + int err = do_flush (file, flush); + + if (err) return err; + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} +#endif /* NO_GZCOMPRESS */ + +/* =========================================================================== + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error. + SEEK_END is not implemented, returns error. + In this version of the library, gzseek can be extremely slow. +*/ +z_off_t ZEXPORT gzseek (file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || whence == SEEK_END || + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; + } + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return -1L; +#else + if (whence == SEEK_SET) { + offset -= s->in; + } + if (offset < 0) return -1L; + + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + if (s->inbuf == Z_NULL) return -1L; + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; + + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; + + offset -= size; + } + return s->in; +#endif + } + /* Rest of function is for reading only */ + + /* compute absolute position */ + if (whence == SEEK_CUR) { + offset += s->out; + } + if (offset < 0) return -1L; + + if (s->transparent) { + /* map to fseek */ + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; + + s->in = s->out = offset; + return offset; + } + + /* For a negative seek, rewind and use positive seek */ + if (offset >= s->out) { + offset -= s->out; + } else if (gzrewind(file) < 0) { + return -1L; + } + /* offset is now the number of bytes to skip. */ + + if (offset != 0 && s->outbuf == Z_NULL) { + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + if (s->outbuf == Z_NULL) return -1L; + } + if (offset && s->back != EOF) { + s->back = EOF; + s->out++; + offset--; + if (s->last) s->z_err = Z_STREAM_END; + } + while (offset > 0) { + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; + + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; + } + return s->out; +} + +/* =========================================================================== + Rewinds input file. +*/ +int ZEXPORT gzrewind (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return -1; + + s->z_err = Z_OK; + s->z_eof = 0; + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + s->crc = crc32(0L, Z_NULL, 0); + if (!s->transparent) (void)inflateReset(&s->stream); + s->in = 0; + s->out = 0; + return fseek(s->file, s->start, SEEK_SET); +} + +/* =========================================================================== + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. +*/ +z_off_t ZEXPORT gztell (file) + gzFile file; +{ + return gzseek(file, 0L, SEEK_CUR); +} + +/* =========================================================================== + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ +int ZEXPORT gzeof (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + /* With concatenated compressed files that can have embedded + * crc trailers, z_eof is no longer the only/best indicator of EOF + * on a gz_stream. Handle end-of-stream error explicitly here. + */ + if (s == NULL || s->mode != 'r') return 0; + if (s->z_eof) return 1; + return s->z_err == Z_STREAM_END; +} + +/* =========================================================================== + Returns 1 if reading and doing so transparently, otherwise zero. +*/ +int ZEXPORT gzdirect (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return 0; + return s->transparent; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return Z_STREAM_ERROR; +#else + if (do_flush (file, Z_FINISH) != Z_OK) + return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, (uLong)(s->in & 0xffffffff)); +#endif + } + return destroy((gz_stream*)file); +} + +#ifdef STDC +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +/* =========================================================================== + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ +const char * ZEXPORT gzerror (file, errnum) + gzFile file; + int *errnum; +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} + +/* =========================================================================== + Clear the error and end-of-file flags, and do the same for the real file. +*/ +void ZEXPORT gzclearerr (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return; + if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; + s->z_eof = 0; + clearerr(s->file); +} diff --git a/zlib/gzio_symb.c b/zlib/gzio_symb.c new file mode 100644 index 00000000..d4f6f4bb --- /dev/null +++ b/zlib/gzio_symb.c @@ -0,0 +1,630 @@ +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. + */ + +/* @(#) $Id$ */ + +#include +#include +#include +#include + +//#include "zutil.h" +#include +#include "gzio_symb.h" + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif + +#ifndef local +# define local static +#endif + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} +#define zmemcpy memcpy + +static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + z_off_t start; /* start of compressed data in file (header skipped) */ + z_off_t in; /* bytes into deflate or inflate */ + z_off_t out; /* bytes out of deflate or inflate */ + int back; /* one character push-back */ + int last; /* true if push-back is last character */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_DEFAULT_COMPRESSION; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->in = 0; + s->out = 0; + s->back = EOF; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else if (*p == 'R') { + strategy = Z_RLE; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->start = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * start anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->start = ftell(s->file) - s->stream.avail_in; + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Assure two bytes in the buffer so we can peek ahead -- handle case + where first byte of header is at the end of the buffer after the last + gzip segment */ + len = s->stream.avail_in; + if (len < 2) { + if (len) s->inbuf[0] = s->stream.next_in[0]; + errno = 0; + len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; + s->stream.avail_in += len; + s->stream.next_in = s->inbuf; + if (s->stream.avail_in < 2) { + s->transparent = s->stream.avail_in; + return; + } + } + + /* Peek ahead to check the gzip magic header */ + if (s->stream.next_in[0] != gz_magic[0] || + s->stream.next_in[1] != gz_magic[1]) { + s->transparent = 1; + return; + } + s->stream.avail_in -= 2; + s->stream.next_in += 2; + + /* Check the rest of the gzip header */ + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + if (s->stream.avail_out && s->back != EOF) { + *next_out++ = s->back; + s->stream.next_out++; + s->stream.avail_out--; + s->back = EOF; + s->out++; + start++; + if (s->last) { + s->z_err = Z_STREAM_END; + return 1; + } + } + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= + (uInt)fread(next_out, 1, s->stream.avail_out, s->file); + } + len -= s->stream.avail_out; + s->in += len; + s->out += len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may be + * different from s->out in case of concatenated .gz files. + * Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + inflateReset(&(s->stream)); + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + if (len == s->stream.avail_out && + (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)) + return -1; + return (int)(len - s->stream.avail_out); +} + + +#ifndef NO_GZCOMPRESS +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), flush); + s->out -= s->stream.avail_out; + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +#endif /* NO_GZCOMPRESS */ + + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return Z_STREAM_ERROR; +#else + if (do_flush (file, Z_FINISH) != Z_OK) + return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, (uLong)(s->in & 0xffffffff)); +#endif + } + return destroy((gz_stream*)file); +} diff --git a/zlib/gzio_symb.h b/zlib/gzio_symb.h new file mode 100644 index 00000000..10153d81 --- /dev/null +++ b/zlib/gzio_symb.h @@ -0,0 +1,240 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.3, July 18th, 2005 + + Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef GZIO_H +#define GZIO_H + + +#ifdef __cplusplus +extern "C" { +#endif + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +#ifdef STDC + typedef void const *voidpc; +#else + typedef Byte const *voidpc; +#endif + + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +//#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* GZIO_H */ diff --git a/zlib/infback.c b/zlib/infback.c new file mode 100644 index 00000000..455dbc9e --- /dev/null +++ b/zlib/infback.c @@ -0,0 +1,623 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_streamp strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->write = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_streamp strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + + /* process literal */ + if (this.op == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/zlib/inffast.c b/zlib/inffast.c new file mode 100644 index 00000000..bbee92ed --- /dev/null +++ b/zlib/inffast.c @@ -0,0 +1,318 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - M68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code this; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + write = state->write; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = lcode[hold & lmask]; + dolen: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op == 0) { /* literal */ + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + PUP(out) = (unsigned char)(this.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = dcode[hold & dmask]; + dodist: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + from = window - OFF; + if (write == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (write < op) { /* wrap around window */ + from += wsize + write - op; + op -= write; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (write < len) { /* some from start of window */ + op = write; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += write - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + this = dcode[this.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + this = lcode[this.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and write == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/zlib/inffast.h b/zlib/inffast.h new file mode 100644 index 00000000..1e88d2d9 --- /dev/null +++ b/zlib/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/zlib/inffixed.h b/zlib/inffixed.h new file mode 100644 index 00000000..75ed4b59 --- /dev/null +++ b/zlib/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/zlib/inflate.c b/zlib/inflate.c new file mode 100644 index 00000000..792fdee8 --- /dev/null +++ b/zlib/inflate.c @@ -0,0 +1,1368 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common write == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + strm->adler = 1; /* to support ill-conceived Java test suite */ + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; + state->wsize = 0; + state->whave = 0; + state->write = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += value << state->bits; + state->bits += bits; + return Z_OK; +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + if (windowBits < 0) { + state->wrap = 0; + windowBits = -windowBits; + } + else { + state->wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) windowBits &= 15; +#endif + } + if (windowBits < 8 || windowBits > 15) { + ZFREE(strm, state); + strm->state = Z_NULL; + return Z_STREAM_ERROR; + } + state->wbits = (unsigned)windowBits; + state->window = Z_NULL; + return inflateReset(strm); +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, out) +z_streamp strm; +unsigned out; +{ + struct inflate_state FAR *state; + unsigned copy, dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->write = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->write = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->write; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->write, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->write = copy; + state->whave = state->wsize; + } + else { + state->write += dist; + if (state->write == state->wsize) state->write = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL) { + len = state->head->extra_len - state->length; + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + break; + } + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + if ((int)(this.op) == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + state->mode = LIT; + break; + } + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(this.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->mode = DIST; + case DIST: + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + state->extra = (unsigned)(this.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + if (state->offset > state->whave + out - left) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->write) { + copy -= state->write; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->write - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + if (state->mode == DICT) { + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + struct inflate_state FAR *state; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy(dest, source, sizeof(z_stream)); + zmemcpy(copy, state, sizeof(struct inflate_state)); + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} diff --git a/zlib/inflate.h b/zlib/inflate.h new file mode 100644 index 00000000..07bd3e78 --- /dev/null +++ b/zlib/inflate.h @@ -0,0 +1,115 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/zlib/inftrees.c b/zlib/inftrees.c new file mode 100644 index 00000000..8a9c13ff --- /dev/null +++ b/zlib/inftrees.c @@ -0,0 +1,329 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.3 Copyright 1995-2005 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)1; + this.val = (unsigned short)0; + *(*table)++ = this; /* make a table to force an error */ + *(*table)++ = this; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked when a LENS table is being made + against the space in *table, ENOUGH, minus the maximum space needed by + the worst case distance code, MAXD. This should never happen, but the + sufficiency of ENOUGH has not been proven exhaustively, hence the check. + This assumes that when type == LENS, bits == 9. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + this.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/zlib/inftrees.h b/zlib/inftrees.h new file mode 100644 index 00000000..b1104c87 --- /dev/null +++ b/zlib/inftrees.h @@ -0,0 +1,55 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1444 code structures (852 for length/literals + and 592 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 2048 +#define MAXD 592 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/zlib/trees.c b/zlib/trees.c new file mode 100644 index 00000000..395e4e16 --- /dev/null +++ b/zlib/trees.c @@ -0,0 +1,1219 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2005 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id$ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if ((unsigned) tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is binary or text */ + if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN) + set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to BINARY or TEXT, using a crude approximation: + * set it to Z_TEXT if all symbols are either printable characters (33 to 255) + * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise. + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local void set_data_type(s) + deflate_state *s; +{ + int n; + + for (n = 0; n < 9; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + if (n == 9) + for (n = 14; n < 32; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY; +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/zlib/trees.h b/zlib/trees.h new file mode 100644 index 00000000..72facf90 --- /dev/null +++ b/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/zlib/uncompr.c b/zlib/uncompr.c new file mode 100644 index 00000000..b59e3d0d --- /dev/null +++ b/zlib/uncompr.c @@ -0,0 +1,61 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/zlib/zconf.h b/zlib/zconf.h new file mode 100644 index 00000000..03a9431c --- /dev/null +++ b/zlib/zconf.h @@ -0,0 +1,332 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define deflatePrime z_deflatePrime +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table +# define zError z_zError + +# define alloc_func z_alloc_func +# define free_func z_free_func +# define in_func z_in_func +# define out_func z_out_func +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/zlib/zlib.h b/zlib/zlib.h new file mode 100644 index 00000000..02281792 --- /dev/null +++ b/zlib/zlib.h @@ -0,0 +1,1357 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.3, July 18th, 2005 + + Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.3" +#define ZLIB_VERNUM 0x1230 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumualte before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it gets to the next deflate block boundary. When decoding the + zlib or gzip format, this will cause inflate() to return immediately after + the header and before the first block. When doing a raw inflate, inflate() + will go ahead and process the first block, and will return when it gets to + the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. Z_FIXED prevents the + use of dynamic Huffman codes, allowing for a simpler decoder for special + applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. In addition, the + current implementation of deflate will use at most the window size minus + 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is + a crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg + is set to null if there is no error message. inflateInit2 does not perform + any decompression apart from reading the zlib header if present: this will + be done by inflate(). (So next_in and avail_in may be modified, but next_out + and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK can be used to + force inflate() to return immediately after header processing is complete + and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When + any of extra, name, or comment are not Z_NULL and the respective field is + not present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns 1 if file is being read directly without decompression, otherwise + zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); +/* + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is NULL, this function returns the required initial + value for the for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + +/* + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/zlib/zutil.c b/zlib/zutil.c new file mode 100644 index 00000000..d55f5948 --- /dev/null +++ b/zlib/zutil.c @@ -0,0 +1,318 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch (sizeof(uInt)) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch (sizeof(uLong)) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch (sizeof(voidpf)) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch (sizeof(z_off_t)) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#ifdef STDC +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/zlib/zutil.h b/zlib/zutil.h new file mode 100644 index 00000000..b7d5eff8 --- /dev/null +++ b/zlib/zutil.h @@ -0,0 +1,269 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# ifndef _WIN32_WCE +# include +# endif +# include +# include +#endif +#ifdef NO_ERRNO_H +# ifdef _WIN32_WCE + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. We rename it to + * avoid conflict with other libraries that use the same workaround. + */ +# define errno z_errno +# endif + extern int errno; +#else +# ifndef _WIN32_WCE +# include +# endif +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +# ifdef M_I86 + #include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif +#ifdef VMS +# define NO_vsnprintf +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */