diff --git a/src/286.c b/src/286.c deleted file mode 100644 index 8fe4b58..0000000 --- a/src/286.c +++ /dev/null @@ -1,3787 +0,0 @@ -#include "ibm.h" -#include "x86.h" -#include "x86_flags.h" -#include "cpu.h" -#include "pit.h" -#include "keyboard.h" - -#define getword getword286 - -#define checkio_perm(port) if (!IOPLp) \ - { \ - x86gpf(NULL,0); \ - break; \ - } - -#undef readmemb -#undef writememb - -#define readmemb(s,a) ((readlookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF)?readmemb386l(s,a):ram[readlookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]) -#define writememb(s,a,v) if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF) writememb386l(s,a,v); else ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]=v -#define writememw(s,a,v) if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFE) writememwl(s,a,v); else *((uint16_t *)(&ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))=v - -extern int keywaiting; - -#define checklimit(a) - -/*#define checklimit(a) if (msw&1 && (a)) \ - { \ - pclog("Seg limit GPF at %04X:%04X\n",CS,pc); \ - pclog("%04X %04X %04X %i %04X %04X\n", ealimitw, ealimit, eaaddr, mod, _ds.limit, _ss.limit); \ - x86gpf(NULL,0); \ - break; \ - }*/ - -#define NOTRM if (!(msw & 1))\ - { \ - x86_int(6); \ - break; \ - } - - -static inline uint8_t geteab() -{ - if (mod==3) - return (rm&4)?regs[rm&3].b.h:regs[rm&3].b.l; -// cycles-=3; - return readmemb(easeg, eaaddr); -} - -static inline uint16_t geteaw() -{ - if (mod==3) - return regs[rm].w; -// cycles-=3; -// if (output==3) printf("GETEAW %04X:%08X\n",easeg,eaaddr); - return readmemw(easeg, eaaddr); -} - -static inline uint16_t geteaw2() -{ - if (mod==3) - return regs[rm].w; -// cycles-=2; -// printf("Getting addr from %04X:%04X %05X\n",easeg,eaaddr+2,easeg+eaaddr+2); - return readmemw(easeg,(eaaddr+2)&0xFFFF); -} - -static inline void seteab(uint8_t val) -{ - if (mod==3) - { - if (rm&4) regs[rm&3].b.h=val; - else regs[rm&3].b.l=val; - } - else - { -// cycles-=2; - writememb(easeg, eaaddr, val); - } -} - -static inline void seteaw(uint16_t val) -{ - if (mod==3) - regs[rm].w=val; - else - { -// cycles-=2; - writememw(easeg, eaaddr, val); -// writememb(easeg+eaaddr+1,val>>8); - } -} - -#undef fetchea - -#define fetchea() { rmdat=readmemb(cs, pc); pc++; \ - reg=(rmdat>>3)&7; \ - mod=(rmdat>>6)&3; \ - rm=rmdat&7; \ - if (mod!=3) fetcheal286(); } - -void fetcheal286() -{ - if (!mod && rm==6) { eaaddr=getword(); easeg=ds; ealimit=_ds.limit; ealimitw=_ds.limitw; } - else - { - switch (mod) - { - case 0: - eaaddr=0; - break; - case 1: - eaaddr=(uint16_t)(int8_t)readmemb(cs, pc); pc++; - break; - case 2: - eaaddr=getword(); - break; - } - eaaddr+=(*mod1add[0][rm])+(*mod1add[1][rm]); - easeg=*mod1seg[rm]; - if (mod1seg[rm] == &ss) { ealimit=_ss.limit; ealimitw=_ss.limitw; } - else { ealimit=_ds.limit; ealimitw=_ds.limitw; } -// if (output) pclog("Limit %08X %08X %08X %08X\n",ealimit,_ds.limit,mod1seg[rm],&ss); - } - eaaddr&=0xFFFF; -} - -void rep286(int fv) -{ - uint8_t temp; - uint32_t c;//=CX; - uint8_t temp2; - uint16_t tempw,tempw2,tempw3,of=flags; - uint32_t ipc=oldpc;//pc-1; - int changeds=0; - uint32_t oldds; - uint32_t templ,templ2; - int tempz; - int tempi; -// if (output) pclog("REP32 %04X %04X ",use32,rep32); - startrep: - temp=opcode2=readmemb(cs,pc); pc++; -// if (firstrepcycle && temp==0xA5) pclog("REP MOVSW %06X:%04X %06X:%04X\n",ds,SI,es,DI); -// if (output) pclog("REP %02X %04X\n",temp,ipc); - c = CX; -/* if (rep32 && (msw&1)) - { - if (temp!=0x67 && temp!=0x66 && (rep32|temp)!=0x1AB && (rep32|temp)!=0x3AB) pclog("32-bit REP %03X %08X %04X:%06X\n",temp|rep32,c,CS,pc); - }*/ - switch (temp) - { - case 0x26: /*ES:*/ - oldds=ds; - ds=es; - rds=ES; - changeds=1; - goto startrep; - break; - case 0x2E: /*CS:*/ - oldds=ds; - ds=cs; - rds=CS; - changeds=1; - goto startrep; - break; - case 0x36: /*SS:*/ - oldds=ds; - ds=ss; - rds=SS; - changeds=1; - goto startrep; - break; - case 0x3E: /*DS:*/ - oldds=ds; - ds=ds; - changeds=1; - goto startrep; - break; - case 0x6C: /*REP INSB*/ - if (c>0) - { - checkio_perm(DX); - temp2=inb(DX); - writememb(es,DI,temp2); - if (abrt) break; - if (flags&D_FLAG) DI--; - else DI++; - c--; - cycles-=15; - } - if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } - else firstrepcycle=1; - break; - case 0x6D: /*REP INSW*/ - if (c>0) - { - tempw=inw(DX); - writememw(es,DI,tempw); - if (abrt) break; - if (flags&D_FLAG) DI-=2; - else DI+=2; - c--; - cycles-=15; - } - if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } - else firstrepcycle=1; - break; - case 0x6E: /*REP OUTSB*/ - if (c>0) - { - temp2=readmemb(ds,SI); - if (abrt) break; - checkio_perm(DX); - outb(DX,temp2); - if (flags&D_FLAG) SI--; - else SI++; - c--; - cycles-=14; - } - if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } - else firstrepcycle=1; - break; - case 0x6F: /*REP OUTSW*/ - if (c>0) - { - tempw=readmemw(ds,SI); - if (abrt) break; -// pclog("OUTSW %04X -> %04X\n",SI,tempw); - outw(DX,tempw); - if (flags&D_FLAG) SI-=2; - else SI+=2; - c--; - cycles-=14; - } - if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } - else firstrepcycle=1; - break; - case 0xA4: /*REP MOVSB*/ - if (c>0) - { - temp2=readmemb(ds,SI); if (abrt) break; - writememb(es,DI,temp2); if (abrt) break; -// if (output==3) pclog("MOVSB %08X:%04X -> %08X:%04X %02X\n",ds,SI,es,DI,temp2); - if (flags&D_FLAG) { DI--; SI--; } - else { DI++; SI++; } - c--; - cycles-=(is486)?3:4; - } - if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } - else firstrepcycle=1; - break; - case 0xA5: /*REP MOVSW*/ - if (c>0) - { - tempw=readmemw(ds,SI); if (abrt) break; - writememw(es,DI,tempw); if (abrt) break; - if (flags&D_FLAG) { DI-=2; SI-=2; } - else { DI+=2; SI+=2; } - c--; - cycles-=(is486)?3:4; - } - if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } - else firstrepcycle=1; - break; - case 0xA6: /*REP CMPSB*/ - if (fv) flags|=Z_FLAG; - else flags&=~Z_FLAG; - if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) - { - temp=readmemb(ds,SI); - temp2=readmemb(es,DI); - if (abrt) { flags=of; break; } - if (flags&D_FLAG) { DI--; SI--; } - else { DI++; SI++; } - c--; - cycles-=(is486)?7:9; - setsub8(temp,temp2); - } - if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; } - else firstrepcycle=1; - break; - case 0xA7: /*REP CMPSW*/ - if (fv) flags|=Z_FLAG; - else flags&=~Z_FLAG; - if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) - { - tempw=readmemw(ds,SI); - tempw2=readmemw(es,DI); - if (abrt) { flags=of; break; } - if (flags&D_FLAG) { DI-=2; SI-=2; } - else { DI+=2; SI+=2; } - c--; - cycles-=(is486)?7:9; - setsub16(tempw,tempw2); - } - if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; } - else firstrepcycle=1; - break; - - case 0xAA: /*REP STOSB*/ - if (c>0) - { - writememb(es,DI,AL); - if (abrt) break; - if (flags&D_FLAG) DI--; - else DI++; - c--; - cycles-=(is486)?4:5; - } - if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } - else firstrepcycle=1; - break; - case 0xAB: /*REP STOSW*/ - if (c>0) - { - writememw(es,DI,AX); - if (abrt) break; - if (flags&D_FLAG) DI-=2; - else DI+=2; - c--; - cycles-=(is486)?4:5; - } - if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } - else firstrepcycle=1; - break; - case 0xAC: /*REP LODSB*/ -// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSB %04X(%06X):%06X\n",CS,cs,pc); - if (c>0) - { - AL=readmemb(ds,SI); - if (abrt) break; - if (flags&D_FLAG) SI--; - else SI++; - c--; - cycles-=5; - } - if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } - else firstrepcycle=1; - break; - case 0xAD: /*REP LODSW*/ -// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSW %04X(%06X):%06X\n",CS,cs,pc); - if (c>0) - { - AX=readmemw(ds,SI); - if (abrt) break; - if (flags&D_FLAG) SI-=2; - else SI+=2; - c--; - cycles-=5; - } - if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } - else firstrepcycle=1; - break; - case 0xAE: /*REP SCASB*/ -// if (es==0xFFFFFFFF) pclog("Null selector REP SCASB %04X(%06X):%06X\n",CS,cs,pc); -// tempz=(fv)?1:0; - if (fv) flags|=Z_FLAG; - else flags&=~Z_FLAG; - if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) - { - temp2=readmemb(es,DI); - if (abrt) { flags=of; break; } - setsub8(AL,temp2); - if (flags&D_FLAG) DI--; - else DI++; - c--; - cycles-=(is486)?5:8; - } - if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; } - else firstrepcycle=1; - break; - case 0xAF: /*REP SCASW*/ -// if (es==0xFFFFFFFF) pclog("Null selector REP SCASW %04X(%06X):%06X\n",CS,cs,pc); - if (fv) flags|=Z_FLAG; - else flags&=~Z_FLAG; - if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) - { - tempw=readmemw(es,DI); - if (abrt) { flags=of; break; } - setsub16(AX,tempw); - if (flags&D_FLAG) DI-=2; - else DI+=2; - c--; - cycles-=(is486)?5:8; - } - if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; } - else firstrepcycle=1; - break; - - default: - pc=ipc; - cycles-=20; - x86illegal(); - pclog("Bad REP %02X\n", temp); - //dumpregs(); - //exit(-1); - } - CX=c; - if (changeds) ds=oldds; -// if (output) pclog("%03X %03X\n",rep32,use32); -} - -void x86illegal() -{ - uint16_t addr; - pclog("x86 illegal %04X %08X %04X:%08X %02X\n",msw,cr0,CS,pc,opcode); -// if (output) -// { -// dumpregs(); -// exit(-1); -// } - if (msw&1) - { - pmodeint(6,0); - } - else - { - if (ssegs) { ss=oldss; _ss.limit=oldsslimit; _ss.limitw=oldsslimitw; } - writememw(ss,((SP-2)&0xFFFF),flags); - writememw(ss,((SP-4)&0xFFFF),CS); - writememw(ss,((SP-6)&0xFFFF),pc); - SP-=6; - flags&=~I_FLAG; - flags&=~T_FLAG; - addr=6<<2; - pc=readmemw(0,addr); - loadcs(readmemw(0,addr+2)); - } - cycles-=70; -} -//#endif -//#if 0 - -static inline uint8_t getbytef() -{ - uint8_t temp = readmemb(cs, pc); pc++; - return temp; -} -static inline uint16_t getwordf() -{ - uint16_t tempw = readmemw(cs, pc); pc+=2; - return tempw; -} - -/*Conditional jump timing is WRONG*/ -void exec286(int cycs) -{ - uint8_t temp,temp2; - uint16_t addr,tempw,tempw2,tempw3,tempw4; - int8_t offset; - volatile int tempws, tempws2; - uint32_t templ, templ2, templ3; - int8_t temps; - int16_t temps16; - int c;//,cycdiff; - int tempi; - FILE *f; - int trap; - int cyclast; -// printf("Run 286! %i %i\n",cycles,cycs); - cycles+=cycs; -// i86_Execute(cycs); -// return; - while (cycles>0) - { - cyclast = cycdiff; - cycdiff=cycles; - oldcs=CS; - oldpc=pc; - oldcpl=CPL; - - opcodestart: - opcode = readmemb(cs, pc); - if (abrt) goto opcodeend; - tempc=flags&C_FLAG; - trap=flags&T_FLAG; - - if (output && /*cs<0xF0000 && */!ssegs)//opcode!=0x26 && opcode!=0x36 && opcode!=0x2E && opcode!=0x3E) - { - if ((opcode!=0xF2 && opcode!=0xF3) || firstrepcycle) - { - if (!skipnextprint) printf("%04X(%06X):%04X : %04X %04X %04X %04X %04X(%06X) %04X(%06X) %04X(%06X) %04X(%06X) %04X %04X %04X %04X %02X %04X %04X %04X %04X %04X %08X %i %i %i %08X %i %f %f\n",CS,cs,pc,AX,BX,CX,DX,CS,cs,DS,ds,ES,es,SS,ss,DI,SI,BP,SP,opcode,flags,msw,ram[0x7c3e],ram[(0x7c3e)+3],ram[0x7c40],_ds.limitw,keybsenddelay,keywaiting,ins, _ss.limit, cyclast, pit.c[1], PITCONST); - skipnextprint=0; -// ins++; -/* if (ins==50000) - { - dumpregs(); - exit(-1); - }*/ -/* if (ins==500000) - { - dumpregs(); - exit(-1); - }*/ - } - } -//#endif - pc++; - inhlt=0; -// if (ins==500000) { dumpregs(); exit(0); }*/ - switch (opcode) - { - case 0x00: /*ADD 8,reg*/ - fetchea(); - //if (!rmdat && output) pc--; -/* if (!rmdat && output) - { - pclog("Crashed\n"); -// clear_keybuf(); -// readkey(); - dumpregs(); - exit(-1); - }*/ - if (mod == 3) - { - temp = getr8(rm); - temp2 = getr8(reg); - setadd8(temp, temp2); - setr8(rm, temp + temp2); - cycles -= 2; - } - else - { - temp = geteab(); if (abrt) break; - temp2 = getr8(reg); - seteab(temp + temp2); if (abrt) break; - setadd8(temp, temp2); - cycles -= 7; - } - break; - case 0x01: /*ADD 16,reg*/ - fetchea(); - if (mod == 3) - { - setadd16(regs[rm].w, regs[reg].w); - regs[rm].w += regs[reg].w; - cycles -= 2; - } - else - { - tempw = geteaw(); if (abrt) break; - seteaw(tempw + regs[reg].w); if (abrt) break; - setadd16(tempw, regs[reg].w); - cycles -= 7; - } - break; - case 0x02: /*ADD reg,8*/ - fetchea(); - temp=geteab(); if (abrt) break; - setadd8(getr8(reg),temp); - setr8(reg,getr8(reg)+temp); - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x03: /*ADD reg,16*/ - fetchea(); - tempw=geteaw(); if (abrt) break; - setadd16(regs[reg].w,tempw); - regs[reg].w+=tempw; - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x04: /*ADD AL,#8*/ - temp=getbytef(); - setadd8(AL,temp); - AL+=temp; - cycles -= 3; - break; - case 0x05: /*ADD AX,#16*/ - tempw=getwordf(); - setadd16(AX,tempw); - AX+=tempw; - cycles -= 3; - break; - - case 0x06: /*PUSH ES*/ - if (ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),ES); if (abrt) break; - SP-=2; - cycles-=3; - break; - case 0x07: - if (ssegs) ss=oldss; - tempw=readmemw(ss,SP); if (abrt) break; - loadseg(tempw,&_es); if (abrt) break; - SP+=2; - cycles -= (msw & 1) ? 20 : 5; - break; - - case 0x08: /*OR 8,reg*/ - fetchea(); - if (mod == 3) - { - temp = getr8(rm) | getr8(reg); - setr8(rm, temp); - setznp8(temp); - cycles -= 2; - } - else - { - temp = geteab(); if (abrt) break; - temp2 = getr8(reg); - seteab(temp | temp2); if (abrt) break; - setznp8(temp | temp2); - cycles -= 7; - } - break; - case 0x09: /*OR 16,reg*/ - fetchea(); - if (mod == 3) - { - regs[rm].w |= regs[reg].w; - setznp16(regs[rm].w); - cycles -= 2; - } - else - { - tempw = geteaw() | regs[reg].w; if (abrt) break; - seteaw(tempw); if (abrt) break; - setznp16(tempw); - cycles -= 7; - } - break; - case 0x0A: /*OR reg,8*/ - fetchea(); - temp=geteab(); if (abrt) break; - temp|=getr8(reg); - setznp8(temp); - setr8(reg,temp); - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x0B: /*OR reg,16*/ - fetchea(); - tempw=geteaw(); if (abrt) break; - tempw|=regs[reg].w; - setznp16(tempw); - regs[reg].w=tempw; - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x0C: /*OR AL,#8*/ - AL|=getbytef(); - setznp8(AL); - cycles -= 2; - break; - case 0x0D: /*OR AX,#16*/ - AX|=getwordf(); - setznp16(AX); - cycles -= 2; - break; - - case 0x0E: /*PUSH CS*/ - if (ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),CS); if (abrt) break; - SP-=2; - cycles-=3; - break; - - case 0x0F: - temp = readmemb(cs, pc); pc++; - opcode2 = temp; -// if (temp>5 && temp!=0x82 && temp!=0x85 && temp!=0x84 && temp!=0x87 && temp!=0x8D && temp!=0x8F && temp!=0x8C && temp!=0x20 && temp!=0x22) pclog("Using magic 386 0F instruction %02X!\n",temp); - switch (temp) - { - case 0: - fetchea(); if (abrt) break; - switch (rmdat&0x38) - { - case 0x00: /*SLDT*/ - NOTRM - seteaw(ldt.seg); - cycles -= (mod == 3) ? 3 : 2; - break; - case 0x08: /*STR*/ - NOTRM - seteaw(tr.seg); - cycles -= (mod == 3) ? 3 : 2; - break; - case 0x10: /*LLDT*/ - if (CPL && (msw & 1)) - { - pclog("Invalid LLDT!\n"); - x86gpf(NULL,0); - break; - } - NOTRM - ldt.seg=geteaw(); -// pclog("Load LDT %04X ",ldt.seg); - templ=(ldt.seg&~7)+gdt.base; -// pclog("%06X ",gdt.base); - templ3=readmemw(0,templ)+((readmemb(0,templ+6)&0xF)<<16); - templ2=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16)|(readmemb(0,templ+7)<<24); - if (abrt) break; - ldt.limit=templ3; - ldt.access=readmemb(0,templ+6); - if (readmemb(0,templ+6)&0x80) - { - ldt.limit<<=12; - ldt.limit|=0xFFF; - } - ldt.base=templ2; -// /*if (output==3) */pclog("LLDT %04X %08X %04X %08X %08X\n",ldt.seg,ldt.base,ldt.limit,readmeml(0,templ),readmeml(0,templ+4)); - - cycles -= (mod == 3) ? 17 : 19; - break; - case 0x18: /*LTR*/ - if (CPL && (msw & 1)) - { - pclog("Invalid LTR!\n"); - x86gpf(NULL,0); - break; - } - NOTRM - tr.seg=geteaw(); - templ=(tr.seg&~7)+gdt.base; - templ3=readmemw(0,templ)+((readmemb(0,templ+6)&0xF)<<16); - templ2=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16)|(readmemb(0,templ+7)<<24); - temp=readmemb(0,templ+5); - if (abrt) break; - tr.limit=templ3; - tr.access=readmemb(0,templ+6); - if (readmemb(0,templ+6)&0x80) - { - tr.limit<<=12; - tr.limit|=0xFFF; - } - tr.base=templ2; -// pclog("TR base = %08X\n",templ2); - tr.access=temp; - cycles -= (mod == 3) ? 17 : 19; - break; - case 0x20: /*VERR*/ - NOTRM - tempw=geteaw(); if (abrt) break; - flags&=~Z_FLAG; - if (!(tempw&0xFFFC)) break; /*Null selector*/ - cpl_override=1; - tempi=(tempw&~7)<((tempw&4)?ldt.limit:gdt.limit); - tempw2=readmemw(0,((tempw&4)?ldt.base:gdt.base)+(tempw&~7)+4); - cpl_override=0; - if (abrt) break; - if (!(tempw2&0x1000)) tempi=0; - if ((tempw2&0xC00)!=0xC00) /*Exclude conforming code segments*/ - { - tempw3=(tempw2>>13)&3; /*Check permissions*/ - if (tempw3>13)&3; /*Check permissions*/ - if (tempw3> 16) | 0xFF00); - cycles -= 11; - break; - case 0x08: /*SIDT*/ - seteaw(idt.limit); - writememw(easeg, eaaddr + 2, idt.base); - writememw(easeg, eaaddr + 4, (idt.base >> 16) | 0xFF00); - cycles -= 12; - break; - case 0x10: /*LGDT*/ - if (CPL && (msw & 1)) - { - pclog("Invalid LGDT!\n"); - x86gpf(NULL,0); - break; - } - tempw=geteaw(); - templ=readmeml(0,easeg+eaaddr+2)&0xFFFFFF; - if (abrt) break; - gdt.limit=tempw; - gdt.base=templ; - cycles-=11; - break; - case 0x18: /*LIDT*/ - if (CPL && (msw & 1)) - { - pclog("Invalid LIDT!\n"); - x86gpf(NULL,0); - break; - } - tempw=geteaw(); - templ=readmeml(0,easeg+eaaddr+2)&0xFFFFFF; - if (abrt) break; - idt.limit=tempw; - idt.base=templ; - cycles-=12; - break; - - case 0x20: /*SMSW*/ - if (is486) seteaw(msw); - else seteaw(msw|0xFF00); -// pclog("SMSW %04X:%04X %04X %i\n",CS,pc,msw,is486); - cycles -= (mod == 3) ? 2 : 3; - break; - case 0x30: /*LMSW*/ - if (CPL && (msw&1)) - { - pclog("LMSW - ring not zero!\n"); - x86gpf(NULL,0); - break; - } - tempw=geteaw(); if (abrt) break; - if (msw&1) tempw|=1; - msw=tempw; - cycles -= (mod == 3) ? 3 : 6; - pclog("LMSW %04X %08X %04X:%04X\n", msw, cs, CS, pc); - break; - - default: - pclog("Bad 0F 01 opcode %02X\n",rmdat&0x38); - pc-=3; - x86illegal(); - break; -// dumpregs(); -// exit(-1); - } - break; - - case 2: /*LAR*/ - NOTRM - fetchea(); - tempw=geteaw(); if (abrt) break; -// pclog("LAR seg %04X\n",tempw); - - if (!(tempw&0xFFFC)) { flags&=~Z_FLAG; break; } /*Null selector*/ - tempi=(tempw&~7)<((tempw&4)?ldt.limit:gdt.limit); - if (tempi) - { - cpl_override=1; - tempw2=readmemw(0,((tempw&4)?ldt.base:gdt.base)+(tempw&~7)+4); - cpl_override=0; - if (abrt) break; - } - flags&=~Z_FLAG; -// pclog("tempw2 %04X %i %04X %04X\n",tempw2,tempi,ldt.limit,gdt.limit); - if ((tempw2&0x1F00)==0x000) tempi=0; - if ((tempw2&0x1F00)==0x800) tempi=0; - if ((tempw2&0x1F00)==0xA00) tempi=0; - if ((tempw2&0x1F00)==0xD00) tempi=0; - if ((tempw2&0x1C00)<0x1C00) /*Exclude conforming code segments*/ - { - tempw3=(tempw2>>13)&3; - if (tempw3>13)&3; - if (tempw3 9)) - { - tempi = ((uint16_t)AL) + 6; - AL += 6; - flags |= A_FLAG; - if (tempi & 0x100) flags |= C_FLAG; - } - if ((flags&C_FLAG) || (AL>0x9F)) - { - AL+=0x60; - flags|=C_FLAG; - } - tempw = flags & (C_FLAG | A_FLAG); - setznp8(AL); - flags |= tempw; - cycles -= 3; - break; - - case 0x28: /*SUB 8,reg*/ - fetchea(); - if (mod == 3) - { - temp = getr8(rm); - temp2 = getr8(reg); - setsub8(temp, temp2); - setr8(rm, temp - temp2); - cycles -= 2; - } - else - { - temp = geteab(); if (abrt) break; - temp2 = getr8(reg); - seteab(temp - temp2); if (abrt) break; - setsub8(temp, temp2); - cycles -= 7; - } - break; - case 0x29: /*SUB 16,reg*/ - fetchea(); - if (mod == 3) - { - setsub16(regs[rm].w, regs[reg].w); - regs[rm].w -= regs[reg].w; - cycles -= 2; - } - else - { - tempw = geteaw(); if (abrt) break; - seteaw(tempw - regs[reg].w); if (abrt) break; - setsub16(tempw, regs[reg].w); - cycles -= 7; - } - break; - case 0x2A: /*SUB reg,8*/ - fetchea(); - temp=geteab(); if (abrt) break; - setsub8(getr8(reg),temp); - setr8(reg,getr8(reg)-temp); - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x2B: /*SUB reg,16*/ - fetchea(); - tempw=geteaw(); if (abrt) break; - setsub16(regs[reg].w,tempw); - regs[reg].w-=tempw; - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x2C: /*SUB AL,#8*/ - temp=getbytef(); - setsub8(AL,temp); - AL-=temp; - cycles -= 3; - break; - case 0x2D: /*SUB AX,#16*/ - tempw=getwordf(); - setsub16(AX,tempw); - AX-=tempw; - cycles -= 3; - break; - - case 0x2E: /*CS:*/ - oldss=ss; - oldds=ds; - ds=ss=cs; - rds=CS; - ssegs=2; - cycles-=2; - goto opcodestart; - - case 0x2F: /*DAS*/ - if ((flags&A_FLAG)||((AL&0xF)>9)) - { - tempi=((uint16_t)AL)-6; - AL-=6; - flags|=A_FLAG; - if (tempi&0x100) flags|=C_FLAG; - } -// else -// flags&=~A_FLAG; - if ((flags&C_FLAG)||(AL>0x9F)) - { - AL-=0x60; - flags|=C_FLAG; - } -// else -// flags&=~C_FLAG; - tempw = flags & (C_FLAG | A_FLAG); - setznp8(AL); - flags |= tempw; - cycles -= 3; - break; - - case 0x30: /*XOR 8,reg*/ - fetchea(); - if (mod == 3) - { - temp = getr8(rm) ^ getr8(reg); - setr8(rm, temp); - setznp8(temp); - cycles -= 2; - } - else - { - temp = geteab(); if (abrt) break; - temp ^= getr8(reg); - seteab(temp); if (abrt) break; - setznp8(temp); - cycles -= 7; - } - break; - case 0x31: /*XOR 16,reg*/ - fetchea(); - if (mod == 3) - { - regs[rm].w ^= regs[reg].w; - setznp16(regs[rm].w); - cycles -= 2; - } - else - { - tempw = geteaw() ^ regs[reg].w; if (abrt) break; - seteaw(tempw); if (abrt) break; - setznp16(tempw); - cycles -= 7; - } - break; - case 0x32: /*XOR reg,8*/ - fetchea(); - temp=geteab(); if (abrt) break; - temp^=getr8(reg); - setznp8(temp); - setr8(reg,temp); - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x33: /*XOR reg,16*/ - fetchea(); - tempw=geteaw(); if (abrt) break; - tempw^=regs[reg].w; - setznp16(tempw); - regs[reg].w=tempw; - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x34: /*XOR AL,#8*/ - AL^=getbytef(); - setznp8(AL); - cycles -= 3; - break; - case 0x35: /*XOR AX,#16*/ - AX^=getwordf(); - setznp16(AX); - cycles -= 3; - break; - - case 0x36: /*SS:*/ - oldss=ss; - oldds=ds; - ds=ss=ss; - rds=SS; - ssegs=2; - cycles-=2; - goto opcodestart; -// break; - - case 0x37: /*AAA*/ - if ((flags&A_FLAG)||((AL&0xF)>9)) - { - AL+=6; - AH++; - flags|=(A_FLAG|C_FLAG); - } - else - flags&=~(A_FLAG|C_FLAG); - AL&=0xF; - cycles -= 3; - break; - - case 0x38: /*CMP 8,reg*/ - fetchea(); - temp=geteab(); if (abrt) break; - setsub8(temp,getr8(reg)); - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x39: /*CMP 16,reg*/ - fetchea(); - tempw=geteaw(); if (abrt) break; -// if (output) pclog("CMP %04X %04X\n",tempw,regs[reg].w); - setsub16(tempw,regs[reg].w); - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x3A: /*CMP reg,8*/ - fetchea(); - temp=geteab(); if (abrt) break; -// if (output) pclog("CMP %02X-%02X\n",getr8(reg),temp); - setsub8(getr8(reg),temp); - cycles -= (mod == 3) ? 2 : 6; - break; - case 0x3B: /*CMP reg,16*/ - fetchea(); - tempw=geteaw(); if (abrt) break; - setsub16(regs[reg].w,tempw); - cycles -= (mod == 3) ? 2 : 6; - break; - case 0x3C: /*CMP AL,#8*/ - temp=getbytef(); - setsub8(AL,temp); - cycles -= 3; - break; - case 0x3D: /*CMP AX,#16*/ - tempw=getwordf(); - setsub16(AX,tempw); - cycles -= 3; - break; - - case 0x3E: /*DS:*/ - oldss=ss; - oldds=ds; - ds=ss=ds; - ssegs=2; - cycles-=2; - goto opcodestart; -// break; - - case 0x3F: /*AAS*/ - if ((flags&A_FLAG)||((AL&0xF)>9)) - { - AL-=6; - AH--; - flags|=(A_FLAG|C_FLAG); - } - else - flags&=~(A_FLAG|C_FLAG); - AL&=0xF; - cycles -= 3; - break; - - case 0x40: case 0x41: case 0x42: case 0x43: /*INC r16*/ - case 0x44: case 0x45: case 0x46: case 0x47: - setadd16nc(regs[opcode&7].w,1); - regs[opcode&7].w++; - cycles -= 2; - break; - case 0x48: case 0x49: case 0x4A: case 0x4B: /*DEC r16*/ - case 0x4C: case 0x4D: case 0x4E: case 0x4F: - setsub16nc(regs[opcode&7].w,1); - regs[opcode&7].w--; - cycles -= 2; - break; - - case 0x50: case 0x51: case 0x52: case 0x53: /*PUSH r16*/ - case 0x54: case 0x55: case 0x56: case 0x57: - if (ssegs) ss=oldss; - writememw(ss,(SP-2)&0xFFFF,regs[opcode&7].w); if (abrt) break; - SP-=2; - cycles -= 3; - break; - case 0x58: case 0x59: case 0x5A: case 0x5B: /*POP r16*/ - case 0x5C: case 0x5D: case 0x5E: case 0x5F: - if (ssegs) ss=oldss; - SP+=2; - tempw=readmemw(ss,(SP-2)&0xFFFF); if (abrt) { SP-=2; break; } - regs[opcode&7].w=tempw; - cycles -= 5; - break; - - case 0x60: /*PUSHA*/ - writememw(ss,((SP-2)&0xFFFF),AX); - writememw(ss,((SP-4)&0xFFFF),CX); - writememw(ss,((SP-6)&0xFFFF),DX); - writememw(ss,((SP-8)&0xFFFF),BX); - writememw(ss,((SP-10)&0xFFFF),SP); - writememw(ss,((SP-12)&0xFFFF),BP); - writememw(ss,((SP-14)&0xFFFF),SI); - writememw(ss,((SP-16)&0xFFFF),DI); - if (!abrt) SP-=16; - cycles -= 17; - break; - case 0x61: /*POPA*/ - DI=readmemw(ss,((SP)&0xFFFF)); if (abrt) break; - SI=readmemw(ss,((SP+2)&0xFFFF)); if (abrt) break; - BP=readmemw(ss,((SP+4)&0xFFFF)); if (abrt) break; - BX=readmemw(ss,((SP+8)&0xFFFF)); if (abrt) break; - DX=readmemw(ss,((SP+10)&0xFFFF)); if (abrt) break; - CX=readmemw(ss,((SP+12)&0xFFFF)); if (abrt) break; - AX=readmemw(ss,((SP+14)&0xFFFF)); if (abrt) break; - SP+=16; - cycles -= 19; - break; - - case 0x62: /*BOUND*/ - fetchea(); - tempw=geteaw(); - tempw2=readmemw(easeg,eaaddr+2); if (abrt) break; - if (((int16_t)regs[reg].w<(int16_t)tempw) || ((int16_t)regs[reg].w>(int16_t)tempw2)) - { - x86_int(5); - } - cycles -= 13; - break; - - case 0x63: /*ARPL*/ - NOTRM - fetchea(); - tempw=geteaw(); if (abrt) break; - if ((tempw&3)<(regs[reg].w&3)) - { - tempw=(tempw&0xFFFC)|(regs[reg].w&3); - seteaw(tempw); if (abrt) break; - flags|=Z_FLAG; - } - else - flags&=~Z_FLAG; - cycles -= (mod == 3) ? 10 : 11; - break; - - case 0x68: /*PUSH #w*/ - tempw=getword(); - writememw(ss,((SP-2)&0xFFFF),tempw); if (abrt) break; - SP-=2; - cycles -= 3; - break; - case 0x69: /*IMUL r16*/ - fetchea(); - tempw=geteaw(); if (abrt) break; - tempw2=getword(); if (abrt) break; - templ=((int)(int16_t)tempw)*((int)(int16_t)tempw2); - if ((templ>>16)!=0 && (templ>>16)!=0xFFFF) flags|=C_FLAG|V_FLAG; - else flags&=~(C_FLAG|V_FLAG); - regs[reg].w=templ&0xFFFF; - cycles -= (mod == 3) ? 21 : 24; - break; - case 0x6A: /*PUSH #eb*/ - tempw=readmemb(cs,pc); pc++; - if (tempw&0x80) tempw|=0xFF00; - writememw(ss,((SP-2)&0xFFFF),tempw); if (abrt) break; - SP-=2; - cycles -= 3; - break; - case 0x6B: /*IMUL r8*/ - fetchea(); - tempw=geteaw(); if (abrt) break; - tempw2=readmemb(cs,pc); pc++; if (abrt) break; - if (tempw2&0x80) tempw2|=0xFF00; - templ=((int)(int16_t)tempw)*((int)(int16_t)tempw2); - if ((templ>>16)!=0 && ((templ>>16)&0xFFFF)!=0xFFFF) flags|=C_FLAG|V_FLAG; - else flags&=~(C_FLAG|V_FLAG); - regs[reg].w=templ&0xFFFF; - cycles -= (mod == 3) ? 21 : 24; - break; - - case 0x6C: /*INSB*/ - checkio_perm(DX); - temp=inb(DX); - writememb(es,DI,temp); if (abrt) break; - if (flags&D_FLAG) DI--; - else DI++; - cycles -= 5; - break; - case 0x6D: /*INSW*/ - checkio_perm(DX); - checkio_perm(DX+1); - tempw=inw(DX); - writememw(es,DI,tempw); if (abrt) break; - if (flags&D_FLAG) DI-=2; - else DI+=2; - cycles -= 5; - break; - case 0x6E: /*OUTSB*/ - temp=readmemb(ds,SI); if (abrt) break; - checkio_perm(DX); - if (flags&D_FLAG) SI--; - else SI++; - outb(DX,temp); - cycles -= 5; - break; - case 0x6F: /*OUTSW*/ - tempw=readmemw(ds,SI); if (abrt) break; - checkio_perm(DX); - checkio_perm(DX+1); - if (flags&D_FLAG) SI-=2; - else SI+=2; - outw(DX,tempw); -// outb(DX+1,tempw>>8); - cycles -= 5; - break; - - case 0x70: /*JO*/ - offset=(int8_t)getbytef(); - if (flags&V_FLAG) { pc += offset; cycles -= 4; cycles -= 2; } - cycles -= 3; - break; - case 0x71: /*JNO*/ - offset=(int8_t)getbytef(); - if (!(flags&V_FLAG)) { pc += offset; cycles -= 4; cycles -= 2; } - cycles -= 3; - break; - case 0x72: /*JB*/ - offset=(int8_t)getbytef(); - if (flags&C_FLAG) { pc += offset; cycles -= 4; cycles -= 2; } - cycles -= 3; - break; - case 0x73: /*JNB*/ - offset=(int8_t)getbytef(); - if (!(flags&C_FLAG)) { pc += offset; cycles -= 4; cycles -= 2; } - cycles -= 3; - break; - case 0x74: /*JZ*/ - offset=(int8_t)getbytef(); - if (flags&Z_FLAG) { pc += offset; cycles -= 4; cycles -= 2; } - cycles -= 3; - break; - case 0x75: /*JNZ*/ - offset=(int8_t)getbytef(); - if (!(flags&Z_FLAG)) { pc += offset; cycles -= 4; cycles -= 2; } - cycles -= 3; - break; - case 0x76: /*JBE*/ - offset=(int8_t)getbytef(); - if (flags&(C_FLAG|Z_FLAG)) { pc += offset; cycles -= 4; cycles -= 2; } - cycles -= 3; - break; - case 0x77: /*JNBE*/ - offset=(int8_t)getbytef(); - if (!(flags&(C_FLAG|Z_FLAG))) { pc += offset; cycles -= 4; cycles -= 2; } - cycles -= 3; - break; - case 0x78: /*JS*/ - offset=(int8_t)getbytef(); - if (flags&N_FLAG) { pc += offset; cycles -= 4; cycles -= 2; } - cycles -= 3; - break; - case 0x79: /*JNS*/ - offset=(int8_t)getbytef(); - if (!(flags&N_FLAG)) { pc += offset; cycles -= 4; cycles -= 2; } - cycles -= 3; - break; - case 0x7A: /*JP*/ - offset=(int8_t)getbytef(); - if (flags&P_FLAG) { pc += offset; cycles -= 4; cycles -= 2; } - cycles -= 3; - break; - case 0x7B: /*JNP*/ - offset=(int8_t)getbytef(); - if (!(flags&P_FLAG)) { pc += offset; cycles -= 4; cycles -= 2; } - cycles -= 3; - break; - case 0x7C: /*JL*/ - offset=(int8_t)getbytef(); - temp=(flags&N_FLAG)?1:0; - temp2=(flags&V_FLAG)?1:0; - if (temp!=temp2) { pc += offset; cycles -= 4; cycles -= 2; } - cycles -= 3; - break; - case 0x7D: /*JNL*/ - offset=(int8_t)getbytef(); - temp=(flags&N_FLAG)?1:0; - temp2=(flags&V_FLAG)?1:0; - if (temp==temp2) { pc += offset; cycles -= 4; cycles -= 2; } - cycles -= 3; - break; - case 0x7E: /*JLE*/ - offset=(int8_t)getbytef(); - temp=(flags&N_FLAG)?1:0; - temp2=(flags&V_FLAG)?1:0; - if ((flags&Z_FLAG) || (temp!=temp2)) { pc += offset; cycles -= 4; cycles -= 2; } - cycles -= 3; - break; - case 0x7F: /*JNLE*/ - offset=(int8_t)getbytef(); - temp=(flags&N_FLAG)?1:0; - temp2=(flags&V_FLAG)?1:0; - if (!((flags&Z_FLAG) || (temp!=temp2))) { pc += offset; cycles -= 4; cycles -= 2; } - cycles -= 3; - break; - - - case 0x80: - case 0x82: - fetchea(); - temp=geteab(); if (abrt) break; - temp2=readmemb(cs,pc); pc++; if (abrt) break; - switch (rmdat&0x38) - { - case 0x00: /*ADD b,#8*/ - seteab(temp+temp2); if (abrt) break; - setadd8(temp,temp2); - cycles -= (mod == 3) ? 3 : 7; - break; - case 0x08: /*OR b,#8*/ - temp|=temp2; - seteab(temp); if (abrt) break; - setznp8(temp); - cycles -= (mod == 3) ? 3 : 7; - break; - case 0x10: /*ADC b,#8*/ - seteab(temp+temp2+tempc); if (abrt) break; - setadc8(temp,temp2); - cycles -= (mod == 3) ? 3 : 7; - break; - case 0x18: /*SBB b,#8*/ - seteab(temp-(temp2+tempc)); if (abrt) break; - setsbc8(temp,temp2); - cycles -= (mod == 3) ? 3 : 7; - break; - case 0x20: /*AND b,#8*/ - temp&=temp2; - seteab(temp); if (abrt) break; - setznp8(temp); - cycles -= (mod == 3) ? 3 : 7; - break; - case 0x28: /*SUB b,#8*/ - seteab(temp-temp2); if (abrt) break; - setsub8(temp,temp2); - cycles -= (mod == 3) ? 3 : 7; - break; - case 0x30: /*XOR b,#8*/ - temp^=temp2; - seteab(temp); if (abrt) break; - setznp8(temp); - cycles -= (mod == 3) ? 3 : 7; - break; - case 0x38: /*CMP b,#8*/ - setsub8(temp,temp2); - cycles -= (mod == 3) ? 3 : 6; - break; - -// default: -// pclog("Bad 80 opcode %02X\n",rmdat&0x38); -// dumpregs(); -// exit(-1); - } - break; - - case 0x81: - fetchea(); - tempw=geteaw(); if (abrt) break; - tempw2=getword(); if (abrt) break; - switch (rmdat&0x38) - { - case 0x00: /*ADD w,#16*/ - seteaw(tempw+tempw2); if (abrt) break; - setadd16(tempw,tempw2); - cycles -= (mod == 3) ? 3 : 7; - break; - case 0x08: /*OR w,#16*/ - tempw|=tempw2; - seteaw(tempw); if (abrt) break; - setznp16(tempw); - cycles -= (mod == 3) ? 3 : 7; - break; - case 0x10: /*ADC w,#16*/ - seteaw(tempw+tempw2+tempc); if (abrt) break; - setadc16(tempw,tempw2); - cycles -= (mod == 3) ? 3 : 7; - break; - case 0x20: /*AND w,#16*/ - tempw&=tempw2; - seteaw(tempw); if (abrt) break; - setznp16(tempw); - cycles -= (mod == 3) ? 3 : 7; - break; - case 0x18: /*SBB w,#16*/ - seteaw(tempw-(tempw2+tempc)); if (abrt) break; - setsbc16(tempw,tempw2); - cycles -= (mod == 3) ? 3 : 7; - break; - case 0x28: /*SUB w,#16*/ - seteaw(tempw-tempw2); if (abrt) break; - setsub16(tempw,tempw2); - cycles -= (mod == 3) ? 3 : 7; - break; - case 0x30: /*XOR w,#16*/ - tempw^=tempw2; - seteaw(tempw); if (abrt) break; - setznp16(tempw); - cycles -= (mod == 3) ? 3 : 7; - break; - case 0x38: /*CMP w,#16*/ -// pclog("CMP %04X %04X\n", tempw, tempw2); - setsub16(tempw,tempw2); - cycles -= (mod == 3) ? 3 : 6; - break; - } - break; - - case 0x83: - fetchea(); - tempw=geteaw(); if (abrt) break; - tempw2=readmemb(cs,pc); pc++; if (abrt) break; - if (tempw2&0x80) tempw2|=0xFF00; - switch (rmdat&0x38) - { - case 0x00: /*ADD w,#8*/ - seteaw(tempw+tempw2); if (abrt) break; - setadd16(tempw,tempw2); - cycles -= (mod == 3) ? 3 : 7; - break; - case 0x08: /*OR w,#8*/ - tempw|=tempw2; - seteaw(tempw); if (abrt) break; - setznp16(tempw); - cycles -= (mod == 3) ? 3 : 7; - break; - case 0x10: /*ADC w,#8*/ - seteaw(tempw+tempw2+tempc); if (abrt) break; - setadc16(tempw,tempw2); - cycles -= (mod == 3) ? 3 : 7; - break; - case 0x18: /*SBB w,#8*/ - seteaw(tempw-(tempw2+tempc)); if (abrt) break; - setsbc16(tempw,tempw2); - cycles -= (mod == 3) ? 3 : 7; - break; - case 0x20: /*AND w,#8*/ - tempw&=tempw2; - seteaw(tempw); if (abrt) break; - setznp16(tempw); - cycles -= (mod == 3) ? 3 : 7; - break; - case 0x28: /*SUB w,#8*/ - seteaw(tempw-tempw2); if (abrt) break; - setsub16(tempw,tempw2); - cycles -= (mod == 3) ? 3 : 7; - break; - case 0x30: /*XOR w,#8*/ - tempw^=tempw2; - seteaw(tempw); if (abrt) break; - setznp16(tempw); - cycles -= (mod == 3) ? 3 : 7; - break; - case 0x38: /*CMP w,#8*/ - setsub16(tempw,tempw2); - cycles -= (mod == 3) ? 3 : 6; - break; - -// default: -// pclog("Bad 83 opcode %02X\n",rmdat&0x38); -// dumpregs(); -// exit(-1); - } - break; - - case 0x84: /*TEST b,reg*/ - fetchea(); - temp=geteab(); if (abrt) break; - temp2=getr8(reg); - setznp8(temp&temp2); - cycles -= (mod == 3) ? 2 : 6; - break; - case 0x85: /*TEST w,reg*/ - fetchea(); - tempw=geteaw(); if (abrt) break; - tempw2=regs[reg].w; - setznp16(tempw&tempw2); - cycles -= (mod == 3) ? 2 : 6; - break; - case 0x86: /*XCHG b,reg*/ - fetchea(); - temp=geteab(); if (abrt) break; - seteab(getr8(reg)); if (abrt) break; - setr8(reg,temp); - cycles -= (mod == 3) ? 3 : 5; - break; - case 0x87: /*XCHG w,reg*/ - fetchea(); - tempw=geteaw(); if (abrt) break; - seteaw(regs[reg].w); if (abrt) break; - regs[reg].w=tempw; - cycles -= (mod == 3) ? 3 : 5; - break; - - case 0x88: /*MOV b,reg*/ - fetchea(); - seteab(getr8(reg)); - cycles -= (mod == 3) ? 2 : 3; - break; - case 0x89: /*MOV w,reg*/ - fetchea(); - seteaw(regs[reg].w); - cycles -= (mod == 3) ? 2 : 3; - break; - case 0x8A: /*MOV reg,b*/ - fetchea(); - temp=geteab(); if (abrt) break; - setr8(reg,temp); - cycles -= (mod == 3) ? 5 : 3; - break; - case 0x8B: /*MOV reg,w*/ - fetchea(); - tempw=geteaw(); if (abrt) break; - regs[reg].w=tempw; - cycles -= (mod == 3) ? 5 : 3; - break; - - case 0x8C: /*MOV w,sreg*/ - fetchea(); - switch (rmdat&0x38) - { - case 0x00: /*ES*/ - seteaw(ES); - break; - case 0x08: /*CS*/ - seteaw(CS); - break; - case 0x18: /*DS*/ - if (ssegs) ds=oldds; - seteaw(DS); - break; - case 0x10: /*SS*/ - if (ssegs) ss=oldss; - seteaw(SS); - break; - } - cycles -= (mod == 3) ? 2 : 3; - break; - - case 0x8D: /*LEA*/ - fetchea(); - regs[reg].w=eaaddr; - cycles -= 3; - break; - - case 0x8E: /*MOV sreg,w*/ - fetchea(); - switch (rmdat&0x38) - { - case 0x00: /*ES*/ - tempw=geteaw(); if (abrt) break; - loadseg(tempw,&_es); - break; - case 0x18: /*DS*/ - tempw=geteaw(); if (abrt) break; - loadseg(tempw,&_ds); - if (ssegs) oldds=ds; - break; - case 0x10: /*SS*/ -// if (output==3) pclog("geteaw\n"); - tempw=geteaw(); if (abrt) break; -// if (output==3) pclog("loadseg\n"); - loadseg(tempw,&_ss); -// if (output==3) pclog("done\n"); - if (ssegs) oldss=ss; - skipnextprint=1; - noint=1; - break; - } - if (msw & 1) cycles -= (mod == 3) ? 17 : 19; - else cycles -= (mod == 3) ? 2 : 5; - break; - - case 0x8F: /*POPW*/ - if (ssegs) templ2=oldss; - else templ2=ss; - tempw=readmemw(templ2,SP); if (abrt) break; - SP+=2; - fetchea(); - if (ssegs) ss=oldss; - seteaw(tempw); - if (abrt) SP-=2; - cycles -= 5; - break; - - case 0x90: /*NOP*/ - cycles -= 3; - break; - - case 0x91: case 0x92: case 0x93: /*XCHG AX*/ - case 0x94: case 0x95: case 0x96: case 0x97: - tempw=AX; - AX=regs[opcode&7].w; - regs[opcode&7].w=tempw; - cycles -= 3; - break; - - case 0x98: /*CBW*/ - AH=(AL&0x80)?0xFF:0; - cycles -= 2; - break; - case 0x99: /*CWD*/ - DX=(AX&0x8000)?0xFFFF:0; - cycles -= 2; - break; - case 0x9A: /*CALL FAR*/ - tempw=getword(); - tempw2=getword(); if (abrt) break; - tempw3 = CS; - templ2 = pc; - if (ssegs) ss=oldss; - oxpc=pc; - pc=tempw; - optype=CALL; - if (msw&1) loadcscall(tempw2); - else loadcs(tempw2); - optype=0; - if (abrt) break; - oldss=ss; - writememw(ss,(SP-2)&0xFFFF,tempw3); - writememw(ss,(SP-4)&0xFFFF,templ2); if (abrt) break; - SP-=4; - cycles -= (msw & 1) ? 26 : 13; - break; - case 0x9B: /*WAIT*/ - cycles -= 3; - break; - case 0x9C: /*PUSHF*/ - if (ssegs) ss=oldss; - if (msw & 1) { writememw(ss, ((SP-2)&0xFFFF), flags & 0x7fff); } - else { writememw(ss, ((SP-2)&0xFFFF), flags & 0x0fff); } - if (abrt) break; - SP-=2; - cycles -= 3; - break; - case 0x9D: /*POPF*/ - if (ssegs) ss=oldss; - tempw=readmemw(ss,SP); if (abrt) break; - SP+=2; - if (!(CPL) || !(msw&1)) flags=(tempw&0xFFD5)|2; - else if (IOPLp) flags=(flags&0x3000)|(tempw&0x4FD5)|2; - else flags=(flags&0x7200)|(tempw&0x0DD5)|2; - pclog("POPF %04X %04X %04X:%04X\n", tempw, flags, CS, pc); - cycles -= 5; - break; - case 0x9E: /*SAHF*/ - flags=(flags&0xFF00)|(AH&0xD5)|2; - cycles -= 2; - break; - case 0x9F: /*LAHF*/ - AH=flags&0xFF; - cycles -= 2; - break; - - case 0xA0: /*MOV AL,(w)*/ - addr=getword(); if (abrt) break; - temp=readmemb(ds,addr); if (abrt) break; - AL=temp; - cycles -= 5; - break; - case 0xA1: /*MOV AX,(w)*/ - addr=getword(); if (abrt) break; - tempw=readmemw(ds,addr); if (abrt) break; - AX=tempw; - cycles -= 5; - break; - case 0xA2: /*MOV (w),AL*/ - addr=getword(); if (abrt) break; - writememb(ds,addr,AL); - cycles -= 3; - break; - case 0xA3: /*MOV (w),AX*/ - addr=getword(); if (abrt) break; - writememw(ds,addr,AX); - cycles -= 3; - break; - - case 0xA4: /*MOVSB*/ - temp=readmemb(ds,SI); if (abrt) break; - writememb(es,DI,temp); if (abrt) break; - if (flags&D_FLAG) { DI--; SI--; } - else { DI++; SI++; } - cycles -= 5; - break; - case 0xA5: /*MOVSW*/ - tempw=readmemw(ds,SI); if (abrt) break; - writememw(es,DI,tempw); if (abrt) break; - if (flags&D_FLAG) { DI-=2; SI-=2; } - else { DI+=2; SI+=2; } - cycles -= 5; - break; - case 0xA6: /*CMPSB*/ - temp =readmemb(ds,SI); - temp2=readmemb(es,DI); - if (abrt) break; - setsub8(temp,temp2); - if (flags&D_FLAG) { DI--; SI--; } - else { DI++; SI++; } - cycles -= 8; - break; - case 0xA7: /*CMPSW*/ - tempw =readmemw(ds,SI); - tempw2=readmemw(es,DI); - if (abrt) break; - setsub16(tempw,tempw2); - if (flags&D_FLAG) { DI-=2; SI-=2; } - else { DI+=2; SI+=2; } - cycles -= 8; - break; - case 0xA8: /*TEST AL,#8*/ - temp=getbytef(); - setznp8(AL&temp); - cycles -= 3; - break; - case 0xA9: /*TEST AX,#16*/ - tempw=getwordf(); - setznp16(AX&tempw); - cycles -= 3; - break; - case 0xAA: /*STOSB*/ - writememb(es,DI,AL); if (abrt) break; - if (flags&D_FLAG) DI--; - else DI++; - cycles -= 3; - break; - case 0xAB: /*STOSW*/ - writememw(es,DI,AX); if (abrt) break; - if (flags&D_FLAG) DI-=2; - else DI+=2; - cycles -= 3; - break; - case 0xAC: /*LODSB*/ - temp=readmemb(ds,SI); - if (abrt) break; - AL=temp; - if (flags&D_FLAG) SI--; - else SI++; - cycles -= 5; - break; - case 0xAD: /*LODSW*/ - tempw=readmemw(ds,SI); - if (abrt) break; - AX=tempw; -// if (output) pclog("Load from %05X:%04X\n",ds,SI); - if (flags&D_FLAG) SI-=2; - else SI+=2; - cycles -= 5; - break; - case 0xAE: /*SCASB*/ - temp=readmemb(es,DI); - if (abrt) break; - setsub8(AL,temp); - if (flags&D_FLAG) DI--; - else DI++; - cycles -= 7; - break; - case 0xAF: /*SCASW*/ - tempw=readmemw(es,DI); - if (abrt) break; - setsub16(AX,tempw); - if (flags&D_FLAG) DI-=2; - else DI+=2; - cycles -= 7; - break; - - case 0xB0: /*MOV AL,#8*/ - AL=getbytef(); - cycles -= 2; - break; - case 0xB1: /*MOV CL,#8*/ - CL=getbytef(); - cycles -= 2; - break; - case 0xB2: /*MOV DL,#8*/ - DL=getbytef(); - cycles -= 2; - break; - case 0xB3: /*MOV BL,#8*/ - BL=getbytef(); - cycles -= 2; - break; - case 0xB4: /*MOV AH,#8*/ - AH=getbytef(); - cycles -= 2; - break; - case 0xB5: /*MOV CH,#8*/ - CH=getbytef(); - cycles -= 2; - break; - case 0xB6: /*MOV DH,#8*/ - DH=getbytef(); - cycles -= 2; - break; - case 0xB7: /*MOV BH,#8*/ - BH=getbytef(); - cycles -= 2; - break; - case 0xB8: case 0xB9: case 0xBA: case 0xBB: /*MOV reg,#16*/ - case 0xBC: case 0xBD: case 0xBE: case 0xBF: - regs[opcode&7].w=getwordf(); - cycles -= 2; - break; - - case 0xC0: - fetchea(); - c=readmemb(cs,pc); pc++; - temp=geteab(); if (abrt) break; - c&=31; - if (!c) break; - cycles -= c; - switch (rmdat&0x38) - { - case 0x00: /*ROL b,CL*/ - while (c>0) - { - temp2=(temp&0x80)?1:0; - temp=(temp<<1)|temp2; - c--; - } - seteab(temp); if (abrt) break; - flags&=~(C_FLAG|V_FLAG); - if (temp2) flags|=C_FLAG; - if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; - cycles -= (mod == 3) ? 5 : 8; - break; - case 0x08: /*ROR b,CL*/ - while (c>0) - { - temp2=temp&1; - temp>>=1; - if (temp2) temp|=0x80; - c--; - } - seteab(temp); if (abrt) break; - flags&=~(C_FLAG|V_FLAG); - if (temp2) flags|=C_FLAG; - if ((temp^(temp>>1))&0x40) flags|=V_FLAG; - cycles -= (mod == 3) ? 5 : 8; - break; - case 0x10: /*RCL b,CL*/ - temp2=flags&C_FLAG; - while (c>0) - { - tempc=(temp2)?1:0; - temp2=temp&0x80; - temp=(temp<<1)|tempc; - c--; - if (is486) cycles--; - } - seteab(temp); if (abrt) break; - flags&=~(C_FLAG|V_FLAG); - if (temp2) flags|=C_FLAG; - if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; - cycles -= (mod == 3) ? 5 : 8; - break; - case 0x18: /*RCR b,CL*/ - temp2=flags&C_FLAG; - while (c>0) - { - tempc=(temp2)?0x80:0; - temp2=temp&1; - temp=(temp>>1)|tempc; - c--; - if (is486) cycles--; - } - seteab(temp); if (abrt) break; - flags&=~(C_FLAG|V_FLAG); - if (temp2) flags|=C_FLAG; - if ((temp^(temp>>1))&0x40) flags|=V_FLAG; - cycles -= (mod == 3) ? 5 : 8; - break; - case 0x20: case 0x30: /*SHL b,CL*/ - seteab(temp<>c); if (abrt) break; - setznp8(temp>>c); - if ((temp>>(c-1))&1) flags|=C_FLAG; - if (c==1 && temp&0x80) flags|=V_FLAG; - cycles -= (mod == 3) ? 5 : 8; - break; - case 0x38: /*SAR b,CL*/ - tempc=((temp>>(c-1))&1); - while (c>0) - { - temp>>=1; - if (temp&0x40) temp|=0x80; - c--; - } - seteab(temp); if (abrt) break; - setznp8(temp); - if (tempc) flags|=C_FLAG; - cycles -= (mod == 3) ? 5 : 8; - break; - -// default: -// pclog("Bad C0 opcode %02X\n",rmdat&0x38); -// dumpregs(); -// exit(-1); - } - break; - - case 0xC1: - fetchea(); - c=readmemb(cs,pc)&31; pc++; - tempw=geteaw(); if (abrt) break; - if (!c) break; - cycles -= c; - switch (rmdat&0x38) - { - case 0x00: /*ROL w,CL*/ - while (c>0) - { - temp=(tempw&0x8000)?1:0; - tempw=(tempw<<1)|temp; - c--; - } - seteaw(tempw); if (abrt) break; - flags&=~(C_FLAG|V_FLAG); - if (temp) flags|=C_FLAG; - if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; - cycles -= (mod == 3) ? 5 : 8; - break; - case 0x08: /*ROR w,CL*/ - while (c>0) - { - tempw2=(tempw&1)?0x8000:0; - tempw=(tempw>>1)|tempw2; - c--; - } - seteaw(tempw); if (abrt) break; - flags&=~(C_FLAG|V_FLAG); - if (tempw2) flags|=C_FLAG; - if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; - cycles -= (mod == 3) ? 5 : 8; - break; - case 0x10: /*RCL w,CL*/ - temp2=flags&C_FLAG; - while (c>0) - { - tempc=(temp2)?1:0; - temp2=(tempw>>15); - tempw=(tempw<<1)|tempc; - c--; - if (is486) cycles--; - } - seteaw(tempw); if (abrt) break; - flags&=~(C_FLAG|V_FLAG); - if (temp2) flags|=C_FLAG; - if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; - cycles -= (mod == 3) ? 5 : 8; - break; - case 0x18: /*RCR w,CL*/ - temp2=flags&C_FLAG; - while (c>0) - { - tempc=(temp2)?0x8000:0; - temp2=tempw&1; - tempw=(tempw>>1)|tempc; - c--; - if (is486) cycles--; - } - seteaw(tempw); if (abrt) break; - flags&=~(C_FLAG|V_FLAG); - if (temp2) flags|=C_FLAG; - if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; - cycles -= (mod == 3) ? 5 : 8; - break; - - case 0x20: case 0x30: /*SHL w,CL*/ - seteaw(tempw<>c); if (abrt) break; - setznp16(tempw>>c); - if ((tempw>>(c-1))&1) flags|=C_FLAG; - if (c==1 && tempw&0x8000) flags|=V_FLAG; - cycles -= (mod == 3) ? 5 : 8; - break; - - case 0x38: /*SAR w,CL*/ - tempw2=tempw&0x8000; - tempc=(tempw>>(c-1))&1; - while (c>0) - { - tempw=(tempw>>1)|tempw2; - c--; - } - seteaw(tempw); if (abrt) break; - setznp16(tempw); - if (tempc) flags|=C_FLAG; - cycles -= (mod == 3) ? 5 : 8; - break; - -// default: -// pclog("Bad C1 opcode %02X\n",rmdat&0x38); -// dumpregs(); -// exit(-1); - } - break; - - case 0xC2: /*RET*/ - tempw=getword(); - if (ssegs) ss=oldss; - tempw2=readmemw(ss,SP); if (abrt) break; - SP+=2+tempw; - pc=tempw2; - cycles -= 11; - break; - case 0xC3: /*RET*/ - if (ssegs) ss=oldss; - tempw=readmemw(ss,SP); if (abrt) break; - SP+=2; - pc=tempw; - cycles -= 11; - break; - case 0xC4: /*LES*/ - fetchea(); - tempw2=readmemw(easeg,eaaddr); - tempw=readmemw(easeg,eaaddr+2); if (abrt) break; - loadseg(tempw,&_es); if (abrt) break; - regs[reg].w=tempw2; - cycles -= 7; - break; - case 0xC5: /*LDS*/ - fetchea(); - tempw2=readmemw(easeg,eaaddr); - tempw=readmemw(easeg,eaaddr+2); if (abrt) break; - loadseg(tempw,&_ds); if (abrt) break; - if (ssegs) oldds=ds; - regs[reg].w=tempw2; - cycles -= 7; - break; - case 0xC6: /*MOV b,#8*/ - fetchea(); - temp=readmemb(cs,pc); pc++; if (abrt) break; - seteab(temp); - cycles -= (mod == 3) ? 2 : 3; - break; - case 0xC7: /*MOV w,#16*/ - fetchea(); - tempw=getword(); if (abrt) break; - seteaw(tempw); - cycles -= (mod == 3) ? 2 : 3; - break; - case 0xC8: /*ENTER*/ - tempw2=getword(); - tempi=readmemb(cs,pc); pc++; - templ=BP; - writememw(ss,((SP-2)&0xFFFF),BP); if (abrt) break; - SP-=2; - templ2=SP; - if (tempi>0) - { - while (--tempi) - { - BP-=2; - tempw=readmemw(ss,BP); - if (abrt) { SP=templ2; BP=templ; break; } - writememw(ss,((SP-2)&0xFFFF),tempw); SP-=2; - if (abrt) { SP=templ2; BP=templ; break; } - cycles-=(is486)?3:4; - } - writememw(ss,((SP-2)&0xFFFF),templ2); SP-=2; - if (abrt) { SP=templ2; BP=templ; break; } - cycles -= 4; - } - BP = templ2; - SP-=tempw2; - cycles -= 12; - break; - case 0xC9: /*LEAVE*/ - templ=SP; - SP=BP; - tempw=readmemw(ss,SP); SP+=2; - if (abrt) { SP=templ; break; } - BP=tempw; - cycles -= 5; - break; - case 0xCA: /*RETF*/ - tempw=getword(); - if (msw&1) - { - pmoderetf(0,tempw); - break; - } - tempw2=CPL; - if (ssegs) ss=oldss; - oxpc=pc; - pc=readmemw(ss,SP); - loadcs(readmemw(ss,SP+2)); - if (abrt) break; - SP+=4+tempw; - cycles -= 15; - break; - case 0xCB: /*RETF*/ - if (msw&1) - { - pmoderetf(0,0); - break; - } - tempw2=CPL; - if (ssegs) ss=oldss; - oxpc=pc; - pc=readmemw(ss,SP); - loadcs(readmemw(ss,SP+2)); - if (abrt) break; - SP+=4; - cycles -= 15; - break; - case 0xCC: /*INT 3*/ - if (msw&1) - { - pmodeint(3,1); - cycles -= 40; - } - else - { - if (ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),flags); - writememw(ss,((SP-4)&0xFFFF),CS); - writememw(ss,((SP-6)&0xFFFF),pc); - SP-=6; - addr=3<<2; -// flags&=~I_FLAG; - flags&=~T_FLAG; - oxpc=pc; - pc=readmemw(0,addr); - loadcs(readmemw(0,addr+2)); - cycles -= 23; - } - break; - case 0xCD: /*INT*/ - lastpc=pc; - lastcs=CS; - temp=readmemb(cs,pc); pc++; - intrt: - pclog("INT %02X %04X %04X %04X %04X %04X:%04X\n", temp, AX, BX, CX, DX, CS, pc); - if (1) - { - if (msw&1) - { -// pclog("PMODE int %02X %04X at %04X:%04X ",temp,AX,CS,pc); - pmodeint(temp,1); - cycles -= 40; -// pclog("to %04X:%04X\n",CS,pc); - } - else - { - if (ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),flags); - writememw(ss,((SP-4)&0xFFFF),CS); - writememw(ss,((SP-6)&0xFFFF),pc); - SP-=6; - addr=temp<<2; -// flags&=~I_FLAG; - flags&=~T_FLAG; - oxpc=pc; -// pclog("%04X:%04X : ",CS,pc); - pc=readmemw(0,addr); - loadcs(readmemw(0,addr+2)); - cycles -= 23; -// pclog("INT %02X - %04X %04X:%04X\n",temp,addr,CS,pc); - } - } - break; - case 0xCE: /*INTO*/ - if (flags&V_FLAG) - { - temp=4; - goto intrt; -/* pclog("INTO interrupt!\n"); - dumpregs(); - exit(-1);*/ - } - cycles-=3; - break; - case 0xCF: /*IRET*/ - if (ssegs) ss=oldss; - if (msw&1) - { - optype=IRET; - pmodeiret(0); - optype=0; - } - else - { - tempw=CS; - tempw2=pc; - inint=0; - oxpc=pc; - pc=readmemw(ss,SP); - loadcs(readmemw(ss,((SP+2)&0xFFFF))); - flags=(readmemw(ss,((SP+4)&0xFFFF))&0x0FD5)|2; - SP+=6; - } - cycles -= 17; - break; - - case 0xD0: - fetchea(); - temp=geteab(); if (abrt) break; - switch (rmdat&0x38) - { - case 0x00: /*ROL b,1*/ - seteab((temp<<1)|((temp&0x80)?1:0)); if (abrt) break; - if (temp&0x80) flags|=C_FLAG; - else flags&=~C_FLAG; - temp<<=1; - if (flags&C_FLAG) temp|=1; - if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x08: /*ROR b,1*/ - seteab((temp>>1)|((temp&1)?0x80:0)); if (abrt) break; - if (temp&1) flags|=C_FLAG; - else flags&=~C_FLAG; - temp>>=1; - if (flags&C_FLAG) temp|=0x80; - if ((temp^(temp>>1))&0x40) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x10: /*RCL b,1*/ - temp2=flags&C_FLAG; - seteab((temp<<1)|temp2); if (abrt) break; - if (temp&0x80) flags|=C_FLAG; - else flags&=~C_FLAG; - temp<<=1; - if (temp2) temp|=1; - if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x18: /*RCR b,1*/ - temp2=flags&C_FLAG; - seteab((temp>>1)|(temp2?0x80:0)); if (abrt) break; - if (temp&1) flags|=C_FLAG; - else flags&=~C_FLAG; - temp>>=1; - if (temp2) temp|=0x80; - if ((temp^(temp>>1))&0x40) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x20: case 0x30: /*SHL b,1*/ - seteab(temp<<1); if (abrt) break; - setznp8(temp<<1); - if (temp&0x80) flags|=C_FLAG; - if ((temp^(temp<<1))&0x80) flags|=V_FLAG; - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x28: /*SHR b,1*/ - seteab(temp>>1); if (abrt) break; - setznp8(temp>>1); - if (temp&1) flags|=C_FLAG; - if (temp&0x80) flags|=V_FLAG; - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x38: /*SAR b,1*/ - seteab((temp>>1)|(temp&0x80)); if (abrt) break; - setznp8((temp>>1)|(temp&0x80)); - if (temp&1) flags|=C_FLAG; - cycles -= (mod == 3) ? 2 : 7; - break; - -// default: -// pclog("Bad D0 opcode %02X\n",rmdat&0x38); -// dumpregs(); -// exit(-1); - } - break; - case 0xD1: - fetchea(); - tempw=geteaw(); if (abrt) break; - switch (rmdat&0x38) - { - case 0x00: /*ROL w,1*/ - seteaw((tempw<<1)|(tempw>>15)); if (abrt) break; - if (tempw&0x8000) flags|=C_FLAG; - else flags&=~C_FLAG; - tempw<<=1; - if (flags&C_FLAG) tempw|=1; - if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x08: /*ROR w,1*/ - seteaw((tempw>>1)|(tempw<<15)); if (abrt) break; - if (tempw&1) flags|=C_FLAG; - else flags&=~C_FLAG; - tempw>>=1; - if (flags&C_FLAG) tempw|=0x8000; - if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x10: /*RCL w,1*/ - temp2=flags&C_FLAG; - seteaw((tempw<<1)|temp2); if (abrt) break; - if (tempw&0x8000) flags|=C_FLAG; - else flags&=~C_FLAG; - tempw<<=1; - if (temp2) tempw|=1; - if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x18: /*RCR w,1*/ - temp2=flags&C_FLAG; - seteaw((tempw>>1)|(temp2?0x8000:0)); if (abrt) break; - if (tempw&1) flags|=C_FLAG; - else flags&=~C_FLAG; - tempw>>=1; - if (temp2) tempw|=0x8000; - if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x20: case 0x30: /*SHL w,1*/ - seteaw(tempw<<1); if (abrt) break; - setznp16(tempw<<1); - if (tempw&0x8000) flags|=C_FLAG; - if ((tempw^(tempw<<1))&0x8000) flags|=V_FLAG; - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x28: /*SHR w,1*/ - seteaw(tempw>>1); if (abrt) break; - setznp16(tempw>>1); - if (tempw&1) flags|=C_FLAG; - if (tempw&0x8000) flags|=V_FLAG; - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x38: /*SAR w,1*/ - seteaw((tempw>>1)|(tempw&0x8000)); if (abrt) break; - setznp16((tempw>>1)|(tempw&0x8000)); - if (tempw&1) flags|=C_FLAG; - cycles -= (mod == 3) ? 2 : 7; - break; - - default: - pclog("Bad D1 opcode %02X\n",rmdat&0x38); - } - break; - - case 0xD2: - fetchea(); - temp=geteab(); if (abrt) break; - c=CL&31; -// cycles-=c; - if (!c) break; -// if (c>7) pclog("Shiftb %i %02X\n",rmdat&0x38,c); - cycles -= c; - switch (rmdat&0x38) - { - case 0x00: /*ROL b,CL*/ - while (c>0) - { - temp2=(temp&0x80)?1:0; - temp=(temp<<1)|temp2; - c--; - } - seteab(temp); if (abrt) break; - flags&=~(C_FLAG|V_FLAG); - if (temp2) flags|=C_FLAG; - if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; - cycles -= (mod == 3) ? 5 : 8; - break; - case 0x08: /*ROR b,CL*/ - while (c>0) - { - temp2=temp&1; - temp>>=1; - if (temp2) temp|=0x80; - c--; - } - seteab(temp); if (abrt) break; - flags&=~(C_FLAG|V_FLAG); - if (temp2) flags|=C_FLAG; - if ((temp^(temp>>1))&0x40) flags|=V_FLAG; - cycles -= (mod == 3) ? 5 : 8; - break; - case 0x10: /*RCL b,CL*/ - tempc=flags&C_FLAG; - while (c>0) - { - templ=tempc; - tempc=temp&0x80; - temp<<=1; - if (templ) temp|=1; - c--; - } - seteab(temp); if (abrt) break; - flags&=~(C_FLAG|V_FLAG); - if (tempc) flags|=C_FLAG; - if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; - cycles -= (mod == 3) ? 5 : 8; - break; - case 0x18: /*RCR b,CL*/ - tempc=flags&C_FLAG; - while (c>0) - { - templ=tempc; - tempc=temp&1; - temp>>=1; - if (templ) temp|=0x80; - c--; - } - seteab(temp); if (abrt) break; - flags&=~(C_FLAG|V_FLAG); - if (tempc) flags|=C_FLAG; - if ((temp^(temp>>1))&0x40) flags|=V_FLAG; - cycles -= (mod == 3) ? 5 : 8; - break; - case 0x20: case 0x30: /*SHL b,CL*/ - seteab(temp<>c); if (abrt) break; - setznp8(temp>>c); - if ((temp>>(c-1))&1) flags|=C_FLAG; - if (c==1 && temp&0x80) flags|=V_FLAG; - cycles -= (mod == 3) ? 5 : 8; - break; - case 0x38: /*SAR b,CL*/ - tempc=(temp>>(c-1))&1; - while (c>0) - { - temp>>=1; - if (temp&0x40) temp|=0x80; - c--; - } - seteab(temp); if (abrt) break; - setznp8(temp); - if (tempc) flags|=C_FLAG; - cycles -= (mod == 3) ? 5 : 8; - break; - -// default: -// pclog("Bad D2 opcode %02X\n",rmdat&0x38); -// dumpregs(); -// exit(-1); - } - break; - - case 0xD3: - fetchea(); - tempw=geteaw(); if (abrt) break; - c=CL&31; - if (!c) break; - cycles -= c; - switch (rmdat&0x38) - { - case 0x00: /*ROL w,CL*/ - while (c>0) - { - temp=(tempw&0x8000)?1:0; - tempw=(tempw<<1)|temp; - c--; - } - seteaw(tempw); if (abrt) break; - flags&=~(C_FLAG|V_FLAG); - if (temp) flags|=C_FLAG; - if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; - cycles -= (mod == 3) ? 5 : 8; - break; - case 0x08: /*ROR w,CL*/ - while (c>0) - { - tempw2=(tempw&1)?0x8000:0; - tempw=(tempw>>1)|tempw2; - c--; - } - seteaw(tempw); if (abrt) break; - flags&=~(C_FLAG|V_FLAG); - if (tempw2) flags|=C_FLAG; - if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; - cycles -= (mod == 3) ? 5 : 8; - break; - case 0x10: /*RCL w,CL*/ - tempc=flags&C_FLAG; - while (c>0) - { - templ=tempc; - tempc=tempw&0x8000; - tempw=(tempw<<1)|templ; - c--; - } - seteaw(tempw); if (abrt) break; - flags&=~(C_FLAG|V_FLAG); - if (tempc) flags|=C_FLAG; - if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; - cycles -= (mod == 3) ? 5 : 8; - break; - case 0x18: /*RCR w,CL*/ - tempc=flags&C_FLAG; - while (c>0) - { - templ=tempc; - tempw2=(templ&1)?0x8000:0; - tempc=tempw&1; - tempw=(tempw>>1)|tempw2; - c--; - } - seteaw(tempw); if (abrt) break; - flags&=~(C_FLAG|V_FLAG); - if (tempc) flags|=C_FLAG; - if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; - cycles -= (mod == 3) ? 5 : 8; - break; - - case 0x20: case 0x30: /*SHL w,CL*/ - seteaw(tempw<>c); if (abrt) break; - setznp16(tempw>>c); - if ((tempw>>(c-1))&1) flags|=C_FLAG; - if (c==1 && tempw&0x8000) flags|=V_FLAG; - cycles -= (mod == 3) ? 5 : 8; - break; - - case 0x38: /*SAR w,CL*/ - tempw2=tempw&0x8000; - tempc=((int16_t)tempw>>(c-1))&1; - while (c>0) - { - tempw=(tempw>>1)|tempw2; - c--; - } - seteaw(tempw); if (abrt) break; - setznp16(tempw); - if (tempc) flags|=C_FLAG; - cycles -= (mod == 3) ? 5 : 8; - break; - -// default: -// pclog("Bad D3 opcode %02X\n",rmdat&0x38); -// dumpregs(); -// exit(-1); - } - break; - - case 0xD4: /*AAM*/ - tempws=readmemb(cs,pc); pc++; - AH=AL/tempws; - AL%=tempws; - setznp16(AX); - cycles -= 16; - break; - case 0xD5: /*AAD*/ - tempws=readmemb(cs,pc); pc++; - AL=(AH*tempws)+AL; - AH=0; - setznp16(AX); - cycles -= 14; - break; - case 0xD6: /*SETALC*/ - AL=(flags&C_FLAG)?0xFF:0; - cycles -= 3; - break; - case 0xD7: /*XLAT*/ - addr=(BX+AL)&0xFFFF; - temp=readmemb(ds,addr); if (abrt) break; - AL=temp; - cycles -= 5; - break; - case 0xD9: case 0xDA: case 0xDB: case 0xDD: /*ESCAPE*/ - case 0xD8: - case 0xDC: - case 0xDE: - case 0xDF: - if ((msw & 6) == 4) - { - pc=oldpc; - pmodeint(7,0); - cycles -= 40; - } - else - { - fetchea(); - } - break; - - case 0xE0: /*LOOPNE*/ - offset=(int8_t)readmemb(cs,pc); pc++; - CX--; - if (CX && !(flags&Z_FLAG)) { pc+=offset; cycles -= 4; cycles -= 2; } - cycles -= 4; - break; - case 0xE1: /*LOOPE*/ - offset=(int8_t)readmemb(cs,pc); pc++; - CX--; - if (CX && (flags&Z_FLAG)) { pc+=offset; cycles -= 4; cycles -= 2; } - cycles -= 4; - break; - case 0xE2: /*LOOP*/ - offset=(int8_t)readmemb(cs,pc); pc++; - CX--; - if (CX) { pc+=offset; cycles -= 4; cycles -= 2; } - cycles -= 4; - break; - case 0xE3: /*JCXZ*/ - offset=(int8_t)readmemb(cs,pc); pc++; - if (!CX) { pc+=offset; cycles -= 4; cycles -= 2; } - cycles-=4; - break; - - case 0xE4: /*IN AL*/ - temp=readmemb(cs,pc); - checkio_perm(temp); - pc++; - AL=inb(temp); - cycles -= 5; - break; - case 0xE5: /*IN AX*/ - temp=readmemb(cs,pc); - checkio_perm(temp); - checkio_perm(temp+1); - pc++; - AX=inw(temp); - cycles -= 5; - break; - case 0xE6: /*OUT AL*/ - temp=readmemb(cs,pc); - checkio_perm(temp); - pc++; - outb(temp,AL); - cycles -= 3; - break; - case 0xE7: /*OUT AX*/ - temp=readmemb(cs,pc); - checkio_perm(temp); - checkio_perm(temp+1); - pc++; - outw(temp,AX); - cycles -= 3; - break; - - case 0xE8: /*CALL rel 16*/ - tempw=getword(); if (abrt) break; - if (ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),pc); if (abrt) break; - SP-=2; - pc+=(int16_t)tempw; - cycles -= 7; - break; - case 0xE9: /*JMP rel 16*/ - tempw=getword(); if (abrt) break; - pc+=(int16_t)tempw; - cycles -= 7; - break; - case 0xEA: /*JMP far*/ - addr=getword(); - tempw=getword(); if (abrt) { if (output==3) pclog("JMP ABRT\n"); break; } - oxpc=pc; - pc=addr; - loadcsjmp(tempw,oxpc); - cycles -= 11; - break; - case 0xEB: /*JMP rel*/ - offset=(int8_t)readmemb(cs,pc); pc++; - pc+=offset; - cycles -= 7; - break; - case 0xEC: /*IN AL,DX*/ - checkio_perm(DX); - AL=inb(DX); - cycles -= 5; - break; - case 0xED: /*IN AX,DX*/ - checkio_perm(DX); - checkio_perm(DX+1); - AX=inw(DX); - cycles -= 5; - break; - case 0xEE: /*OUT DX,AL*/ - checkio_perm(DX); - outb(DX,AL); - cycles -= 4; - break; - case 0xEF: /*OUT DX,AX*/ - checkio_perm(DX); - checkio_perm(DX+1); - outw(DX,AX); - cycles -= 4; - break; - - case 0xF0: /*LOCK*/ - break; - - case 0xF2: /*REPNE*/ - rep386(0); - break; - case 0xF3: /*REPE*/ - rep386(1); - break; - - case 0xF4: /*HLT*/ - inhlt=1; - pc--; - cycles -= 2; -/* if (!(flags & I_FLAG)) - { - pclog("Complete HLT\n"); - dumpregs(); - exit(-1); - }*/ - break; - case 0xF5: /*CMC*/ - flags^=C_FLAG; - cycles -= 2; - break; - - case 0xF6: - fetchea(); - temp=geteab(); if (abrt) break; - switch (rmdat&0x38) - { - case 0x00: /*TEST b,#8*/ - temp2=readmemb(cs,pc); pc++; if (abrt) break; -// pclog("TEST %02X,%02X\n",temp,temp2); -/* if (cs==0x700 && !temp && temp2==0x10) - { - dumpregs(); - exit(-1); - }*/ - temp&=temp2; - setznp8(temp); - cycles -= (mod == 3) ? 3 : 6; - break; - case 0x10: /*NOT b*/ - temp=~temp; - seteab(temp); - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x18: /*NEG b*/ - setsub8(0,temp); - temp=0-temp; - seteab(temp); - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x20: /*MUL AL,b*/ -// setznp8(AL); - AX=AL*temp; -// if (AX) flags&=~Z_FLAG; -// else flags|=Z_FLAG; - if (AH) flags|=(C_FLAG|V_FLAG); - else flags&=~(C_FLAG|V_FLAG); - cycles -= (mod == 3) ? 13 : 16; - break; - case 0x28: /*IMUL AL,b*/ -// setznp8(AL); - tempws=(int)((int8_t)AL)*(int)((int8_t)temp); - AX=tempws&0xFFFF; -// if (AX) flags&=~Z_FLAG; -// else flags|=Z_FLAG; - if (AH && AH!=0xFF) flags|=(C_FLAG|V_FLAG); - else flags&=~(C_FLAG|V_FLAG); - cycles -= (mod == 3) ? 13 : 16; - break; - case 0x30: /*DIV AL,b*/ - tempw=AX; - if (temp) tempw2=tempw/temp; -// pclog("DIV %04X/%02X %04X:%04X\n",tempw,temp,CS,pc); - if (temp && !(tempw2&0xFF00)) - { - tempw2=tempw%temp; - AH=tempw2; - tempw/=temp; - AL=tempw&0xFF; - flags|=0x8D5; /*Not a Cyrix*/ - } - else - { - pclog("DIVb BY 0 %04X:%04X\n",cs>>4,pc); - pc=oldpc; - if (msw&1) pmodeint(0,0); - else - { -// pclog("%04X:%04X\n",cs>>4,pc); - writememw(ss,(SP-2)&0xFFFF,flags); - writememw(ss,(SP-4)&0xFFFF,CS); - writememw(ss,(SP-6)&0xFFFF,pc); - SP-=6; - flags&=~I_FLAG; - oxpc=pc; - pc=readmemw(0,0); - loadcs(readmemw(0,2)); - } -// cs=loadcs(CS); -// cs=CS<<4; -// pclog("Div by zero %04X:%04X %02X %02X\n",cs>>4,pc,0xf6,0x30); -// dumpregs(); -// exit(-1); - } - cycles -= (mod == 3) ? 14 : 17; - break; - case 0x38: /*IDIV AL,b*/ -// pclog("IDIV %04X/%02X\n",tempw,temp); - tempws=(int)(int16_t)AX; - if (temp!=0) tempws2=tempws/(int)((int8_t)temp); - temps=tempws2&0xFF; - if ((temp!=0) && ((int)temps==tempws2)) - { - tempw2=tempws%(int)((int8_t)temp); - AH=tempw2&0xFF; - AL=tempws2&0xFF; - if (!cpu_iscyrix) flags|=0x8D5; /*Not a Cyrix*/ - } - else - { - pclog("IDIVb exception - %X / %08X = %X\n",tempws,temp,tempws2); -// pclog("IDIVb BY 0 %04X:%04X\n",cs>>4,pc); - pc=oldpc; - if (msw&1) pmodeint(0,0); - else - { - writememw(ss,(SP-2)&0xFFFF,flags); - writememw(ss,(SP-4)&0xFFFF,CS); - writememw(ss,(SP-6)&0xFFFF,pc); - SP-=6; - flags&=~I_FLAG; - oxpc=pc; - pc=readmemw(0,0); - loadcs(readmemw(0,2)); - } -// cs=loadcs(CS); -// cs=CS<<4; -// pclog("Div by zero %04X:%04X %02X %02X\n",cs>>4,pc,0xf6,0x38); - } - cycles -= (mod == 3) ? 17 : 20; - break; - - default: - pclog("Bad F6 opcode %02X\n",rmdat&0x38); - x86illegal(); -// dumpregs(); -// exit(-1); - } - break; - - case 0xF7: - fetchea(); - tempw=geteaw(); if (abrt) break; - switch (rmdat&0x38) - { - case 0x00: /*TEST w*/ - tempw2=getword(); if (abrt) break; -// if (output==3) pclog("TEST %04X %04X\n",tempw,tempw2); - setznp16(tempw&tempw2); - cycles -= (mod == 3) ? 3 : 6; - break; - case 0x10: /*NOT w*/ - seteaw(~tempw); - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x18: /*NEG w*/ - setsub16(0,tempw); - tempw=0-tempw; - seteaw(tempw); - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x20: /*MUL AX,w*/ -// setznp16(AX); - templ=AX*tempw; - AX=templ&0xFFFF; - DX=templ>>16; -// if (AX|DX) flags&=~Z_FLAG; -// else flags|=Z_FLAG; - if (DX) flags|=(C_FLAG|V_FLAG); - else flags&=~(C_FLAG|V_FLAG); - cycles -= (mod == 3) ? 21 : 24; - break; - case 0x28: /*IMUL AX,w*/ - templ=(int)((int16_t)AX)*(int)((int16_t)tempw); - AX=templ&0xFFFF; - DX=templ>>16; - if (DX && DX!=0xFFFF) flags|=(C_FLAG|V_FLAG); - else flags&=~(C_FLAG|V_FLAG); - cycles -= (mod == 3) ? 21 : 24; - break; - case 0x30: /*DIV AX,w*/ - templ=(DX<<16)|AX; - if (tempw) templ2=templ/tempw; - if (tempw && !(templ2&0xFFFF0000)) - { - tempw2=templ%tempw; - DX=tempw2; - templ/=tempw; - AX=templ&0xFFFF; - if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ - } - else - { -// AX=DX=0; -// break; - pclog("DIVw BY 0 %04X:%04X %i\n",cs>>4,pc,ins); -// dumpregs(); -// exit(-1); - pc=oldpc; - if (msw&1) pmodeint(0,0); - else - { -// pclog("%04X:%04X\n",cs>>4,pc); - writememw(ss,(SP-2)&0xFFFF,flags); - writememw(ss,(SP-4)&0xFFFF,CS); - writememw(ss,(SP-6)&0xFFFF,pc); - SP-=6; - flags&=~I_FLAG; - oxpc=pc; - pc=readmemw(0,0); - loadcs(readmemw(0,2)); - } -// cs=loadcs(CS); -// cs=CS<<4; -// pclog("Div by zero %04X:%04X %02X %02X 1\n",cs>>4,pc,0xf7,0x30); - } - cycles -= (mod == 3) ? 22 : 25; - break; - case 0x38: /*IDIV AX,w*/ - tempws=(int)((DX<<16)|AX); - if (tempw!=0) tempws2=tempws/(int)((int16_t)tempw); - temps16=tempws2&0xFFFF; -// pclog("IDIV %i %i ",tempws,tempw); - if ((tempw!=0) && ((int)temps16==tempws2)) - { - DX=tempws%(int)((int16_t)tempw); - AX=tempws2&0xFFFF; - if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ - } - else - { - pclog("IDIVw exception - %X / %08X = %X\n",tempws,tempw,tempws2); -// pclog("IDIVw BY 0 %04X:%04X\n",cs>>4,pc); -// DX=0; -// AX=0xFFFF; - pc=oldpc; - if (msw&1) pmodeint(0,0); - else - { -// pclog("%04X:%04X\n",cs>>4,pc); - writememw(ss,(SP-2)&0xFFFF,flags); - writememw(ss,(SP-4)&0xFFFF,CS); - writememw(ss,(SP-6)&0xFFFF,pc); - SP-=6; - flags&=~I_FLAG; - oxpc=pc; - pc=readmemw(0,0); - loadcs(readmemw(0,2)); - } -// cs=loadcs(CS); -// cs=CS<<4; -// pclog("Div by zero %04X:%04X %02X %02X 1\n",cs>>4,pc,0xf7,0x38); - } - cycles -= (mod == 3) ? 25 : 28; - break; - - default: - pclog("Bad F7 opcode %02X\n",rmdat&0x38); - x86illegal(); -// dumpregs(); -// exit(-1); - } - break; - - case 0xF8: /*CLC*/ - flags&=~C_FLAG; - cycles -= 2; - break; - case 0xF9: /*STC*/ -// pclog("STC %04X\n",pc); - flags|=C_FLAG; - cycles -= 2; - break; - case 0xFA: /*CLI*/ - if (!IOPLp) - { - x86gpf(NULL,0); - } - else - flags&=~I_FLAG; - cycles -= 3; - break; - case 0xFB: /*STI*/ - if (!IOPLp) - { - x86gpf(NULL,0); - } - else - flags|=I_FLAG; - cycles -= 2; - break; - case 0xFC: /*CLD*/ - flags&=~D_FLAG; - cycles -= 2; - break; - case 0xFD: /*STD*/ - flags|=D_FLAG; - cycles -= 2; - break; - - case 0xFE: /*INC/DEC b*/ - fetchea(); - temp=geteab(); if (abrt) break; - if (rmdat&0x38) - { - seteab(temp-1); if (abrt) break; - flags&=~V_FLAG; - setsub8nc(temp,1); - temp2=temp-1; - if ((temp&0x80) && !(temp2&0x80)) flags|=V_FLAG; - } - else - { - seteab(temp+1); if (abrt) break; - flags&=~V_FLAG; - setadd8nc(temp,1); - temp2=temp+1; - if ((temp2&0x80) && !(temp&0x80)) flags|=V_FLAG; - } - cycles -= (mod == 3) ? 2 : 7; - break; - - case 0xFF: - fetchea(); - switch (rmdat&0x38) - { - case 0x00: /*INC w*/ - tempw=geteaw(); if (abrt) break; - seteaw(tempw+1); if (abrt) break; - setadd16nc(tempw,1); - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x08: /*DEC w*/ - tempw=geteaw(); if (abrt) break; - seteaw(tempw-1); if (abrt) break; - setsub16nc(tempw,1); - cycles -= (mod == 3) ? 2 : 7; - break; - case 0x10: /*CALL*/ - tempw=geteaw(); - if (abrt) break; - if (ssegs) ss=oldss; - writememw(ss,(SP-2)&0xFFFF,pc); if (abrt) break; - SP-=2; - pc=tempw; - cycles -= (mod == 3) ? 7 : 11; - break; - case 0x18: /*CALL far*/ - tempw=readmemw(easeg,eaaddr); - tempw2=readmemw(easeg,(eaaddr+2)); if (output==3) pclog("CALL FAR %04X:%04X\n",tempw,tempw2); if (abrt) break; - tempw3=CS; - templ2=pc; - if (ssegs) ss=oldss; - oxpc=pc; - pc=tempw; - optype=CALL; - if (msw&1) loadcscall(tempw2); - else loadcs(tempw2); - optype=0; - if (abrt) break; - oldss=ss; - writememw(ss,(SP-2)&0xFFFF,tempw3); - writememw(ss,((SP-4)&0xFFFF),templ2); - SP-=4; - cycles -= 16; - break; - case 0x20: /*JMP*/ - tempw=geteaw(); if (abrt) break; - pc=tempw; - cycles -= (mod == 3) ? 7 : 11; - break; - case 0x28: /*JMP far*/ - oxpc=pc; - tempw=readmemw(easeg,eaaddr); - tempw2=readmemw(easeg,eaaddr+2); if (abrt) break; - pc=tempw; - loadcsjmp(tempw2,oxpc); if (abrt) break; - cycles -= 15; - break; - case 0x30: /*PUSH w*/ - tempw=geteaw(); if (abrt) break; - if (ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),tempw); if (abrt) break; - SP-=2; - cycles -= (mod==3) ? 3 : 5; - break; - - default: - pclog("Bad FF opcode %02X\n",rmdat&0x38); - x86illegal(); - //dumpregs(); - //exit(-1); - } - break; - - default: -// pc--; -// cycles-=8; -// break; - pclog("Bad opcode %02X at %04X:%04X from %04X:%04X %08X\n",opcode,cs>>4,pc,old8>>16,old8&0xFFFF,old82); - x86illegal(); -// dumpregs(); -// exit(-1); - } - opcodeend: - pc&=0xFFFF; - -// output = 3; -/* output = 3; - - if (pc == 0xcdd && CS == 0xf000) - { - dumpregs(); - exit(-1); - }*/ - //if (ins == 20768972) output = 3; - - if (ssegs) - { - ds=oldds; _ds.limit=olddslimit; _ds.limitw=olddslimitw; - ss=oldss; _ss.limit=oldsslimit; _ss.limitw=oldsslimitw; - ssegs=0; - } - if (abrt) - { - tempi = abrt; - abrt = 0; - x86_doabrt(tempi); - if (abrt) - { - abrt = 0; - CS = oldcs; - pc = oldpc; - pclog("Double fault\n"); -// dumpregs(); -// exit(-1); - pmodeint(8, 0); - if (abrt) - { - abrt = 0; - softresetx86(); - pclog("Triple fault - reset\n"); - } - } - } - cycdiff-=cycles; - - pit.c[0]-=cycdiff; - pit.c[1]-=cycdiff; - if (ppi.pb&1) pit.c[2]-=cycdiff; - - if ((pit.c[0]<1)||(pit.c[1]<1)||(pit.c[2]<1)) pit_poll(); - - spktime-=cycdiff; - if (spktime<=0.0) - { - spktime+=SPKCONST; -// pclog("1Poll spk\n"); - pollspk(); - pollgussamp(); - getsbsamp(); - polladlib(); - getdacsamp(); -// pclog("2Poll spk\n"); - } - soundtime-=cycdiff; - if (soundtime<=0.0) - { - soundtime+=SOUNDCONST; -// pclog("1Poll sound60hz\n"); - pollsound60hz(); -// pclog("2Poll sound60hz\n"); - } - gustime-=cycdiff; - while (gustime<=0.0) - { - gustime+=GUSCONST; - pollgus(); - } - gustime2-=cycdiff; - while (gustime2<=0.0) - { - gustime2+=GUSCONST2; - pollgus2(); - } - vidtime-=cycdiff; - if (vidtime<=0.0) - { -// pclog("1Poll video\n"); - pollvideo(); -// pclog("2Poll video\n"); - } - if (disctime) - { - disctime-=cycdiff/4; - if (disctime<=0) - { -// pclog("1Poll disc\n"); - disctime=0; - fdc_poll(); -// pclog("2Poll disc\n"); - } - } - if (mousedelay) - { - mousedelay-=20; - if (!mousedelay) - { -// pclog("1Poll mouse\n"); - mousecallback(); -// pclog("2Poll disc\n"); - } - } - if (sbenable) - { - sbcount-=cycdiff; - if (sbcount<0) - { - sbcount+=sblatcho; - pollsb(); - } - } - if (sb_enable_i) - { - sb_count_i-=cycdiff; - if (sb_count_i<0) - { - sb_count_i+=sblatchi; - sb_poll_i(); - } - } - rtctime-=cycdiff; - if (rtctime<0) - { - nvr_rtc(); - } - if (idecallback[0]) - { - idecallback[0]--; - if (idecallback[0]<=0) - { -// pclog("IDE time over\n"); - idecallback[0]=0; - callbackide(0); - } - } - if (idecallback[1]) - { - idecallback[1]--; - if (idecallback[1]<=0) - { -// pclog("IDE time over\n"); - idecallback[1]=0; - callbackide(1); - } - } - if (trap && (flags&T_FLAG) && !noint) - { - if (msw&1) - { - pmodeint(1,0); - cycles -= 40; - } - else - { - writememw(ss,(SP-2)&0xFFFF,flags); - writememw(ss,(SP-4)&0xFFFF,CS); - writememw(ss,(SP-6)&0xFFFF,pc); - SP-=6; - addr=1<<2; - flags&=~I_FLAG; - flags&=~T_FLAG; - pc=readmemw(0,addr); - loadcs(readmemw(0,addr+2)); - cycles -= 23; - } - } - else if ((flags&I_FLAG) && (((pic.pend&~pic.mask)&~pic.mask2) || ((pic2.pend&~pic2.mask)&~pic2.mask2)) && !ssegs && !noint) - { -// pclog("Test %02X %02X %02X\n", pic.pend, pic.mask, pic.mask2); - temp=picinterrupt(); - if (temp!=0xFF) - { -// pclog("286 int %02X %02X %02X %02X\n",temp, pic.pend, pic.mask, pic.mask2); - if (inhlt) pc++; -// intcount++; - if (msw&1) - { - pmodeint(temp,0); - cycles -= 40; - } - else - { - writememw(ss,(SP-2)&0xFFFF,flags); - writememw(ss,(SP-4)&0xFFFF,CS); - writememw(ss,(SP-6)&0xFFFF,pc); - SP-=6; - addr=temp<<2; - flags&=~I_FLAG; - flags&=~T_FLAG; - pc=readmemw(0,addr); - loadcs(readmemw(0,addr+2)); - cycles -= 23; - } - inint=1; - } - } - -/* if (pc==0xCC32 && es>0x180000) - { - pc=0xCBEB; -// output=1; -// timetolive=500000; - }*/ - - if (noint) noint=0; - ins++; - insc++; - -// if (ins == 25000000) output = 3; -/* if (timetolive) - { - timetolive--; - if (!timetolive) - { - dumpregs(); - exit(-1); - } //output=0; - }*/ - keybsenddelay--; - if (keybsenddelay<1) - { - keybsenddelay = 2500; - keyboard_poll(); - } - //output = 3; - } -} -//#endif diff --git a/src/386.h b/src/386.h new file mode 100644 index 0000000..b3c6d16 --- /dev/null +++ b/src/386.h @@ -0,0 +1,2 @@ +extern void cpu_386_flags_extract(); +extern void cpu_386_flags_rebuild(); diff --git a/src/386_ops.h b/src/386_ops.h new file mode 100644 index 0000000..f687920 --- /dev/null +++ b/src/386_ops.h @@ -0,0 +1,499 @@ +#include "x86_ops.h" + +OpFn *x86_opcodes; +OpFn *x86_opcodes_0f; + +static inline void PUSH_W(uint16_t val) +{ + if (stack32) + { + writememw(ss, ESP - 2, val); if (abrt) return; + ESP -= 2; + } + else + { + writememw(ss, (SP - 2) & 0xFFFF, val); if (abrt) return; + SP -= 2; + } +} + +static inline void PUSH_L(uint32_t val) +{ + if (stack32) + { + writememl(ss, ESP - 4, val); if (abrt) return; + ESP -= 4; + } + else + { + writememl(ss, (SP - 4) & 0xFFFF, val); if (abrt) return; + SP -= 4; + } +} + +static inline uint16_t POP_W() +{ + uint16_t ret; + if (stack32) + { + ret = readmemw(ss, ESP); if (abrt) return 0; + ESP += 2; + } + else + { + ret = readmemw(ss, SP); if (abrt) return 0; + SP += 2; + } + return ret; +} + +static inline uint32_t POP_L() +{ + uint32_t ret; + if (stack32) + { + ret = readmeml(ss, ESP); if (abrt) return 0; + ESP += 4; + } + else + { + ret = readmeml(ss, SP); if (abrt) return 0; + SP += 4; + } + return ret; +} + +#include "x86_ops_arith.h" +#include "x86_ops_atomic.h" +#include "x86_ops_bcd.h" +#include "x86_ops_bit.h" +#include "x86_ops_bitscan.h" +#include "x86_ops_call.h" +#include "x86_ops_flag.h" +#include "x86_ops_fpu.h" +#include "x86_ops_inc_dec.h" +#include "x86_ops_int.h" +#include "x86_ops_io.h" +#include "x86_ops_jump.h" +#include "x86_ops_misc.h" +#include "x86_ops_mov.h" +#include "x86_ops_mov_ctrl.h" +#include "x86_ops_mov_seg.h" +#include "x86_ops_movx.h" +#include "x86_ops_msr.h" +#include "x86_ops_mul.h" +#include "x86_ops_pmode.h" +#include "x86_ops_prefix.h" +#include "x86_ops_rep.h" +#include "x86_ops_ret.h" +#include "x86_ops_set.h" +#include "x86_ops_shift.h" +#include "x86_ops_stack.h" +#include "x86_ops_string.h" +#include "x86_ops_xchg.h" + +static int ILLEGAL(uint32_t fetchdat) +{ + pc = oldpc; + x86illegal(); + return 0; +} + +static int op0F_w_a16(uint32_t fetchdat) +{ + int opcode = fetchdat & 0xff; + pc++; + + return x86_opcodes_0f[opcode](fetchdat >> 8); +} +static int op0F_l_a16(uint32_t fetchdat) +{ + int opcode = fetchdat & 0xff; + pc++; + + return x86_opcodes_0f[opcode | 0x100](fetchdat >> 8); +} +static int op0F_w_a32(uint32_t fetchdat) +{ + int opcode = fetchdat & 0xff; + pc++; + + return x86_opcodes_0f[opcode | 0x200](fetchdat >> 8); +} +static int op0F_l_a32(uint32_t fetchdat) +{ + int opcode = fetchdat & 0xff; + pc++; + + return x86_opcodes_0f[opcode | 0x300](fetchdat >> 8); +} + +void x86_setopcodes(OpFn *opcodes, OpFn *opcodes_0f) +{ + x86_opcodes = opcodes; + x86_opcodes_0f = opcodes_0f; +} + +OpFn ops_286_0f[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn ops_386_0f[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, opRDTSC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,ILLEGAL, ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, opRDTSC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, opRDTSC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,ILLEGAL, ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, opRDTSC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn ops_286[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, op_ES, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, op_CS, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, op_SS, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, op_DS, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, ILLEGAL, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, op_ES, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, op_CS, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, op_SS, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, op_DS, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, ILLEGAL, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, op_ES, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, op_CS, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, op_SS, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, op_DS, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, ILLEGAL, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, op_ES, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, op_CS, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, op_SS, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, op_DS, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, ILLEGAL, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, +}; + +OpFn ops_386[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, op_ES, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, op_CS, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, op_SS, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, op_DS, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, op_FS, op_GS, op_66, op_67, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, ILLEGAL, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_l_rmw_a16,opADD_b_rm_a16, opADD_l_rm_a16, opADD_AL_imm, opADD_EAX_imm, opPUSH_ES_l, opPOP_ES_l, opOR_b_rmw_a16, opOR_l_rmw_a16, opOR_b_rm_a16, opOR_l_rm_a16, opOR_AL_imm, opOR_EAX_imm, opPUSH_CS_l, op0F_l_a16, +/*10*/ opADC_b_rmw_a16,opADC_l_rmw_a16,opADC_b_rm_a16, opADC_l_rm_a16, opADC_AL_imm, opADC_EAX_imm, opPUSH_SS_l, opPOP_SS_l, opSBB_b_rmw_a16,opSBB_l_rmw_a16,opSBB_b_rm_a16, opSBB_l_rm_a16, opSBB_AL_imm, opSBB_EAX_imm, opPUSH_DS_l, opPOP_DS_l, +/*20*/ opAND_b_rmw_a16,opAND_l_rmw_a16,opAND_b_rm_a16, opAND_l_rm_a16, opAND_AL_imm, opAND_EAX_imm, op_ES, opDAA, opSUB_b_rmw_a16,opSUB_l_rmw_a16,opSUB_b_rm_a16, opSUB_l_rm_a16, opSUB_AL_imm, opSUB_EAX_imm, op_CS, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_l_rmw_a16,opXOR_b_rm_a16, opXOR_l_rm_a16, opXOR_AL_imm, opXOR_EAX_imm, op_SS, opAAA, opCMP_b_rmw_a16,opCMP_l_rmw_a16,opCMP_b_rm_a16, opCMP_l_rm_a16, opCMP_AL_imm, opCMP_EAX_imm, op_DS, opAAS, + +/*40*/ opINC_EAX, opINC_ECX, opINC_EDX, opINC_EBX, opINC_ESP, opINC_EBP, opINC_ESI, opINC_EDI, opDEC_EAX, opDEC_ECX, opDEC_EDX, opDEC_EBX, opDEC_ESP, opDEC_EBP, opDEC_ESI, opDEC_EDI, +/*50*/ opPUSH_EAX, opPUSH_ECX, opPUSH_EDX, opPUSH_EBX, opPUSH_ESP, opPUSH_EBP, opPUSH_ESI, opPUSH_EDI, opPOP_EAX, opPOP_ECX, opPOP_EDX, opPOP_EBX, opPOP_ESP, opPOP_EBP, opPOP_ESI, opPOP_EDI, +/*60*/ opPUSHA_l, opPOPA_l, opBOUND_l_a16, opARPL_a16, op_FS, op_GS, op_66, op_67, opPUSH_imm_l, opIMUL_l_il_a16,opPUSH_imm_bl, opIMUL_l_ib_a16,opINSB_a16, opINSL_a16, opOUTSB_a16, opOUTSL_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_l_a16, ILLEGAL, op83_l_a16, opTEST_b_a16, opTEST_l_a16, opXCHG_b_a16, opXCHG_l_a16, opMOV_b_r_a16, opMOV_l_r_a16, opMOV_r_b_a16, opMOV_r_l_a16, opMOV_l_seg_a16,opLEA_l_a16, opMOV_seg_w_a16,opPOPL_a16, +/*90*/ opNOP, opXCHG_EAX_ECX, opXCHG_EAX_EDX, opXCHG_EAX_EBX, opXCHG_EAX_ESP, opXCHG_EAX_EBP, opXCHG_EAX_ESI, opXCHG_EAX_EDI, opCWDE, opCDQ, opCALL_far_l, opWAIT, opPUSHFD, opPOPFD, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_EAX_a16, opMOV_a16_AL, opMOV_a16_EAX, opMOVSB_a16, opMOVSL_a16, opCMPSB_a16, opCMPSL_a16, opTEST_AL, opTEST_EAX, opSTOSB_a16, opSTOSL_a16, opLODSB_a16, opLODSL_a16, opSCASB_a16, opSCASL_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_EAX_imm, opMOV_ECX_imm, opMOV_EDX_imm, opMOV_EBX_imm, opMOV_ESP_imm, opMOV_EBP_imm, opMOV_ESI_imm, opMOV_EDI_imm, + +/*c0*/ opC0_a16, opC1_l_a16, opRET_l_imm, opRET_l, opLES_l_a16, opLDS_l_a16, opMOV_b_imm_a16,opMOV_l_imm_a16,opENTER_l, opLEAVE_l, opRETF_a32_imm, opRETF_a32, opINT3, opINT, opINTO, opIRETD, +/*d0*/ opD0_a16, opD1_l_a16, opD2_a16, opD3_l_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_EAX_imm, opOUT_AL_imm, opOUT_EAX_imm, opCALL_r32, opJMP_r32, opJMP_far_a32, opJMP_r8, opIN_AL_DX, opIN_EAX_DX, opOUT_AL_DX, opOUT_EAX_DX, +/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_l_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_l_a16, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a32,opADD_w_rmw_a32,opADD_b_rm_a32, opADD_w_rm_a32, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a32, opOR_w_rmw_a32, opOR_b_rm_a32, opOR_w_rm_a32, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a32, +/*10*/ opADC_b_rmw_a32,opADC_w_rmw_a32,opADC_b_rm_a32, opADC_w_rm_a32, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a32,opSBB_w_rmw_a32,opSBB_b_rm_a32, opSBB_w_rm_a32, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a32,opAND_w_rmw_a32,opAND_b_rm_a32, opAND_w_rm_a32, opAND_AL_imm, opAND_AX_imm, op_ES, opDAA, opSUB_b_rmw_a32,opSUB_w_rmw_a32,opSUB_b_rm_a32, opSUB_w_rm_a32, opSUB_AL_imm, opSUB_AX_imm, op_CS, opDAS, +/*30*/ opXOR_b_rmw_a32,opXOR_w_rmw_a32,opXOR_b_rm_a32, opXOR_w_rm_a32, opXOR_AL_imm, opXOR_AX_imm, op_SS, opAAA, opCMP_b_rmw_a32,opCMP_w_rmw_a32,opCMP_b_rm_a32, opCMP_w_rm_a32, opCMP_AL_imm, opCMP_AX_imm, op_DS, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a32, opARPL_a32, op_FS, op_GS, op_66, op_67, opPUSH_imm_w, opIMUL_w_iw_a32,opPUSH_imm_bw, opIMUL_w_ib_a32,opINSB_a32, opINSW_a32, opOUTSB_a32, opOUTSW_a32, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a32, op81_w_a32, ILLEGAL, op83_w_a32, opTEST_b_a32, opTEST_w_a32, opXCHG_b_a32, opXCHG_w_a32, opMOV_b_r_a32, opMOV_w_r_a32, opMOV_r_b_a32, opMOV_r_w_a32, opMOV_w_seg_a32,opLEA_w_a32, opMOV_seg_w_a32,opPOPW_a32, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a32, opMOV_AX_a32, opMOV_a32_AL, opMOV_a32_AX, opMOVSB_a32, opMOVSW_a32, opCMPSB_a32, opCMPSW_a32, opTEST_AL, opTEST_AX, opSTOSB_a32, opSTOSW_a32, opLODSB_a32, opLODSW_a32, opSCASB_a32, opSCASW_a32, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a32, opC1_w_a32, opRET_w_imm, opRET_w, opLES_w_a32, opLDS_w_a32, opMOV_b_imm_a32,opMOV_w_imm_a32,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET, +/*d0*/ opD0_a32, opD1_w_a32, opD2_a32, opD3_w_a32, opAAM, opAAD, opSETALC, opXLAT_a32, opESCAPE_d8_a32,opESCAPE_d9_a32,opESCAPE_da_a32,opESCAPE_db_a32,opESCAPE_dc_a32,opESCAPE_dd_a32,opESCAPE_de_a32,opESCAPE_df_a32, +/*e0*/ opLOOPNE_l, opLOOPE_l, opLOOP_l, opJECXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a32, opF7_w_a32, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a32, opFF_w_a32, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a32,opADD_l_rmw_a32,opADD_b_rm_a32, opADD_l_rm_a32, opADD_AL_imm, opADD_EAX_imm, opPUSH_ES_l, opPOP_ES_l, opOR_b_rmw_a32, opOR_l_rmw_a32, opOR_b_rm_a32, opOR_l_rm_a32, opOR_AL_imm, opOR_EAX_imm, opPUSH_CS_l, op0F_l_a32, +/*10*/ opADC_b_rmw_a32,opADC_l_rmw_a32,opADC_b_rm_a32, opADC_l_rm_a32, opADC_AL_imm, opADC_EAX_imm, opPUSH_SS_l, opPOP_SS_l, opSBB_b_rmw_a32,opSBB_l_rmw_a32,opSBB_b_rm_a32, opSBB_l_rm_a32, opSBB_AL_imm, opSBB_EAX_imm, opPUSH_DS_l, opPOP_DS_l, +/*20*/ opAND_b_rmw_a32,opAND_l_rmw_a32,opAND_b_rm_a32, opAND_l_rm_a32, opAND_AL_imm, opAND_EAX_imm, op_ES, opDAA, opSUB_b_rmw_a32,opSUB_l_rmw_a32,opSUB_b_rm_a32, opSUB_l_rm_a32, opSUB_AL_imm, opSUB_EAX_imm, op_CS, opDAS, +/*30*/ opXOR_b_rmw_a32,opXOR_l_rmw_a32,opXOR_b_rm_a32, opXOR_l_rm_a32, opXOR_AL_imm, opXOR_EAX_imm, op_SS, opAAA, opCMP_b_rmw_a32,opCMP_l_rmw_a32,opCMP_b_rm_a32, opCMP_l_rm_a32, opCMP_AL_imm, opCMP_EAX_imm, op_DS, opAAS, + +/*40*/ opINC_EAX, opINC_ECX, opINC_EDX, opINC_EBX, opINC_ESP, opINC_EBP, opINC_ESI, opINC_EDI, opDEC_EAX, opDEC_ECX, opDEC_EDX, opDEC_EBX, opDEC_ESP, opDEC_EBP, opDEC_ESI, opDEC_EDI, +/*50*/ opPUSH_EAX, opPUSH_ECX, opPUSH_EDX, opPUSH_EBX, opPUSH_ESP, opPUSH_EBP, opPUSH_ESI, opPUSH_EDI, opPOP_EAX, opPOP_ECX, opPOP_EDX, opPOP_EBX, opPOP_ESP, opPOP_EBP, opPOP_ESI, opPOP_EDI, +/*60*/ opPUSHA_l, opPOPA_l, opBOUND_l_a32, opARPL_a32, op_FS, op_GS, op_66, op_67, opPUSH_imm_l, opIMUL_l_il_a32,opPUSH_imm_bl, opIMUL_l_ib_a32,opINSB_a32, opINSL_a32, opOUTSB_a32, opOUTSL_a32, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a32, op81_l_a32, ILLEGAL, op83_l_a32, opTEST_b_a32, opTEST_l_a32, opXCHG_b_a32, opXCHG_l_a32, opMOV_b_r_a32, opMOV_l_r_a32, opMOV_r_b_a32, opMOV_r_l_a32, opMOV_l_seg_a32,opLEA_l_a32, opMOV_seg_w_a32,opPOPL_a32, +/*90*/ opNOP, opXCHG_EAX_ECX, opXCHG_EAX_EDX, opXCHG_EAX_EBX, opXCHG_EAX_ESP, opXCHG_EAX_EBP, opXCHG_EAX_ESI, opXCHG_EAX_EDI, opCWDE, opCDQ, opCALL_far_l, opWAIT, opPUSHFD, opPOPFD, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a32, opMOV_EAX_a32, opMOV_a32_AL, opMOV_a32_EAX, opMOVSB_a32, opMOVSL_a32, opCMPSB_a32, opCMPSL_a32, opTEST_AL, opTEST_EAX, opSTOSB_a32, opSTOSL_a32, opLODSB_a32, opLODSL_a32, opSCASB_a32, opSCASL_a32, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_EAX_imm, opMOV_ECX_imm, opMOV_EDX_imm, opMOV_EBX_imm, opMOV_ESP_imm, opMOV_EBP_imm, opMOV_ESI_imm, opMOV_EDI_imm, + +/*c0*/ opC0_a32, opC1_l_a32, opRET_l_imm, opRET_l, opLES_l_a32, opLDS_l_a32, opMOV_b_imm_a32,opMOV_l_imm_a32,opENTER_l, opLEAVE_l, opRETF_a32_imm, opRETF_a32, opINT3, opINT, opINTO, opIRETD, +/*d0*/ opD0_a32, opD1_l_a32, opD2_a32, opD3_l_a32, opAAM, opAAD, opSETALC, opXLAT_a32, opESCAPE_d8_a32,opESCAPE_d9_a32,opESCAPE_da_a32,opESCAPE_db_a32,opESCAPE_dc_a32,opESCAPE_dd_a32,opESCAPE_de_a32,opESCAPE_df_a32, +/*e0*/ opLOOPNE_l, opLOOPE_l, opLOOP_l, opJECXZ, opIN_AL_imm, opIN_EAX_imm, opOUT_AL_imm, opOUT_EAX_imm, opCALL_r32, opJMP_r32, opJMP_far_a32, opJMP_r8, opIN_AL_DX, opIN_EAX_DX, opOUT_AL_DX, opOUT_EAX_DX, +/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a32, opF7_l_a32, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a32, opFF_l_a32, +}; diff --git a/src/x86.c b/src/808x.c similarity index 89% rename from src/x86.c rename to src/808x.c index aa32eff..0fe7193 100644 --- a/src/x86.c +++ b/src/808x.c @@ -11,9 +11,13 @@ 2 clocks - fetch opcode 2 etc*/ #include #include "ibm.h" -#include "x86.h" -#include "mem.h" + +#include "cpu.h" #include "keyboard.h" +#include "mem.h" +#include "pic.h" +#include "timer.h" +#include "x86.h" int nextcyc=0; int cycdiff; @@ -21,7 +25,6 @@ int is8086=0; int memcycs; int nopageerrors=0; -float cassettetime; void FETCHCOMPLETE(); @@ -84,40 +87,21 @@ void writememl(uint32_t s, uint32_t a, uint32_t v) else *((uint32_t *)(&ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))=v; } -int lldt=0; -int notpresent; -uint16_t oldflags; + void dumpregs(); -int incga; -uint32_t old8,old82,old83; uint16_t oldcs; int oldcpl; -int dlE=0; -/*#define CS (cs>>4) -#define DS (ds>>4) -#define ES (es>>4) -#define SS (ss>>4)*/ - -//#define loadseg(a) ((a)<<4) - -int keyboardtimer; int tempc; -int bxcheck=0,spcheck=0; -uint16_t getword(); -int count40=0; -int dosfunc; uint8_t opcode; int times=0; uint16_t pc2,pc3; -int pit0=1; int noint=0; int output=0; int shadowbios=0; -int inint=0; int ins=0; //#define readmemb(a) (((a)<0xA0000)?ram[a]:readmembl(a)) @@ -266,6 +250,13 @@ inline void FETCHCLEAR() }*/ } +static uint16_t getword() +{ + uint8_t temp=FETCH(); + return temp|(FETCH()<<8); +} + + /*EA calculation*/ /*R/M - bits 0-2 - R/M bits 3-5 - Reg bits 6-7 - mod @@ -366,7 +357,7 @@ void makemod1table() mod1seg[4]=&ds; mod1seg[5]=&ds; mod1seg[6]=&ss; mod1seg[7]=&ds; } -void fetcheal() +static void fetcheal() { if (!mod && rm==6) { eaaddr=getword(); easeg=ds; FETCHADD(6); } else @@ -395,67 +386,6 @@ void fetcheal() } } -/*void fetchea() -{ - rmdat=readmemb(cs+pc); pc++; - reg=(rmdat>>3)&7; - mod=rmdat>>6; - rm=rmdat&7; - switch (mod) - { - case 0: - switch (rm) - { - case 0: eaaddr=BX+SI; easeg=ds; if (!AT) cycles-=7; break; - case 1: eaaddr=BX+DI; easeg=ds; if (!AT) cycles-=8; break; - case 2: eaaddr=BP+SI; easeg=ss; if (!AT) cycles-=8; break; - case 3: eaaddr=BP+DI; easeg=ss; if (!AT) cycles-=7; break; - case 4: eaaddr=SI; easeg=ds; if (!AT) cycles-=5; break; - case 5: eaaddr=DI; easeg=ds; if (!AT) cycles-=5; break; - case 6: eaaddr=getword(); easeg=ds; if (!AT) cycles-=6; break; - case 7: eaaddr=BX; easeg=ds; if (!AT) cycles-=5; break; - } - if (AT && !(rm&4)) cycles--; - break; - - case 1: - eaaddr=readmemb(cs+pc); pc++; - if (eaaddr&0x80) eaaddr|=0xFF00; -// if (output) printf("EAADDR %04X ",eaaddr); - switch (rm) - { - case 0: eaaddr+=BX+SI; easeg=ds; if (!AT) cycles-=11; break; - case 1: eaaddr+=BX+DI; easeg=ds; if (!AT) cycles-=12; break; - case 2: eaaddr+=BP+SI; easeg=ss; if (!AT) cycles-=12; break; - case 3: eaaddr+=BP+DI; easeg=ss; if (!AT) cycles-=11; break; - case 4: eaaddr+=SI; easeg=ds; if (!AT) cycles-=9; break; - case 5: eaaddr+=DI; easeg=ds; if (!AT) cycles-=9; break; - case 6: eaaddr+=BP; easeg=ss; if (!AT) cycles-=9; break; - case 7: eaaddr+=BX; easeg=ds; if (!AT) cycles-=9; break; - } - if (AT && !(rm&4)) cycles--; -// if (output) printf("%04X %04X",eaaddr,BX); - break; - - case 2: - eaaddr=getword(); - switch (rm) - { - case 0: eaaddr+=BX+SI; easeg=ds; if (!AT) cycles-=11; break; - case 1: eaaddr+=BX+DI; easeg=ds; if (!AT) cycles-=12; break; - case 2: eaaddr+=BP+SI; easeg=ss; if (!AT) cycles-=12; break; - case 3: eaaddr+=BP+DI; easeg=ss; if (!AT) cycles-=11; break; - case 4: eaaddr+=SI; easeg=ds; if (!AT) cycles-=9; break; - case 5: eaaddr+=DI; easeg=ds; if (!AT) cycles-=9; break; - case 6: eaaddr+=BP; easeg=ss; if (!AT) cycles-=9; break; - case 7: eaaddr+=BX; easeg=ds; if (!AT) cycles-=9; break; - } - if (AT && !(rm&4)) cycles--; - break; - } - eaaddr&=0xFFFF; -}*/ - static inline uint8_t geteab() { if (mod==3) @@ -562,56 +492,39 @@ void makeznptable() } int timetolive=0; -uint8_t cpu_readop(uint32_t addr) { return readmemb(addr); } -uint8_t cpu_readmem20(uint32_t addr) { return readmemb(addr); } - -void cpu_writemem20(uint32_t addr, uint8_t val) { writememb(addr,val); } - -uint16_t getword() -{ - uint8_t temp=FETCH(); - return temp|(FETCH()<<8); -// pc+=2; -// return readmemw(cs,(pc-2)); -} - -uint16_t getword286() -{ - uint16_t temp=readmemw(cs,pc); pc+=2; - return temp; -} - -int ratio1=0,ratio2=0; - extern uint32_t oldcs2; extern uint32_t oldpc2; +int indump = 0; + void dumpregs() { FILE *f; - int c,d=0,e=0; + int c,d=0,e=0,ff; + if (indump) return; + indump = 1; // return; output=0; // return; // savenvr(); -/* printf("The ratio is %i %i\n",ratio1,ratio2); - for (c=0;c<256;c++) - { - printf("ISRAM : %06X %i\n",c<<16,isram[c]); - }*/ // return; chdir(pcempath); nopageerrors=1; /* f=fopen("rram3.dmp","wb"); for (c=0;c<0x8000000;c++) putc(readmemb(c+0x10000000),f); fclose(f);*/ -/* f=fopen("ram.dmp","wb"); + f=fopen("ram.dmp","wb"); fwrite(ram,mem_size*1024*1024,1,f); + fclose(f); +/* pclog("Dumping rram5.dmp\n"); + f=fopen("rram5.dmp","wb"); + for (c=0;c<0x1000000;c++) putc(readmemb(c+0x10150000),f); fclose(f);*/ -/* f=fopen("rram.dmp","wb"); + pclog("Dumping rram.dmp\n"); + f=fopen("rram.dmp","wb"); for (c=0;c<0x1000000;c++) putc(readmemb(c),f); fclose(f); - f=fopen("rram2.dmp","wb"); +/* f=fopen("rram2.dmp","wb"); for (c=0;c<0x100000;c++) putc(readmemb(c+0xbff00000),f); fclose(f); f = fopen("stack.dmp","wb"); @@ -623,12 +536,15 @@ chdir(pcempath); f = fopen("tempx2.dmp","wb"); for (c = 0; c < 0x10000; c++) putc(readmemb(c+0xFDEF5000), f); fclose(f);*/ -/* f=fopen("rram4.dmp","wb"); - for (c=0;c<0x3000000;c++) putc(readmemb(c+0x80000000),f); - fclose(f);*/ -/* f=fopen("rram5.dmp","wb"); - for (c=0;c<0x1000000;c++) putc(readmemb(c+0x10000000),f); - fclose(f);*/ + pclog("Dumping rram4.dmp\n"); + f=fopen("rram4.dmp","wb"); + for (c=0;c<0x0050000;c++) + { + abrt = 0; + putc(readmemb386l(0,c+0x80000000),f); + } + fclose(f); + pclog("Dumping done\n"); /* f=fopen("rram6.dmp","wb"); for (c=0;c<0x1000000;c++) putc(readmemb(c+0xBF000000),f); fclose(f);*/ @@ -644,10 +560,10 @@ chdir(pcempath); f=fopen("ram8.bin","wb"); fwrite(ram+0x3D210,0x200,1,f); fclose(f); */ -/* f=fopen("vram.dmp","wb"); + f=fopen("vram.dmp","wb"); fwrite(vram,0x400000,1,f); fclose(f); - f=fopen("bios.dmp","wb"); +/* f=fopen("bios.dmp","wb"); fwrite(rom,0x20000,1,f); fclose(f); f=fopen("vbios.dmp","wb"); @@ -670,7 +586,7 @@ chdir(pcempath); else printf("AX=%04X BX=%04X CX=%04X DX=%04X DI=%04X SI=%04X BP=%04X SP=%04X\n",AX,BX,CX,DX,DI,SI,BP,SP); printf("PC=%04X CS=%04X DS=%04X ES=%04X SS=%04X FLAGS=%04X\n",pc,CS,DS,ES,SS,flags); - printf("%04X:%04X %04X:%04X %08X %08X %08X\n",oldcs,oldpc, oldcs2, oldpc2, old8,old82,old83); + printf("%04X:%04X %04X:%04X\n",oldcs,oldpc, oldcs2, oldpc2); printf("%i ins\n",ins); if (is386) printf("In %s mode\n",(msw&1)?((eflags&VM_FLAG)?"V86":"protected"):"real"); @@ -703,14 +619,28 @@ chdir(pcempath); printf("Entries in readlookup : %i writelookup : %i\n",d,e); d=0; x87_dumpregs(); + for (c = 0; c < 256; c++) + { + e = -1; + for (d = 0; d < 256; d++) + { + if (inscounts[d] > e) + { + e = inscounts[d]; + ff = d; + } + } + inscounts[ff] = -1; +// printf("Opcode %02x - %i\n", ff, e); + } /* for (c=0;c<1024*1024;c++) { if (mmucache[c]!=0xFFFFFFFF) d++; } printf("Entries in MMU cache : %i\n",d);*/ + indump = 0; } -int isAT; int resets = 0; void resetx86() { @@ -733,12 +663,12 @@ void resetx86() resetreadlookup(); makemod1table(); resetmcr(); - isAT=AT; FETCHCLEAR(); x87_reset(); cpu_set_edx(); ESP=0; mmu_perm=4; + memset(inscounts, 0, sizeof(inscounts)); } void softresetx86() @@ -759,32 +689,19 @@ void softresetx86() flags=2; } -#undef AT -#define AT isAT - -extern int is486; -void setznp8(uint8_t val) +static void setznp8(uint8_t val) { flags&=~0xC4; flags|=znptable8[val]; } -#define setznp168 setznp16 -void setznp16(uint16_t val) +static void setznp16(uint16_t val) { flags&=~0xC4; -// flags|=((val&0x8000)?N_FLAG:((!val)?Z_FLAG:0)); -// flags|=(((znptable8[val&0xFF]&P_FLAG)==(znptable8[val>>8]&P_FLAG))?P_FLAG:0); flags|=znptable16[val]; } -/*void setznp168(uint16_t val) -{ - flags&=~0xC4; - flags|=(znptable16[val]&0xC0)|(znptable8[val&0xFF]&4); -}*/ - -void setadd8(uint8_t a, uint8_t b) +static void setadd8(uint8_t a, uint8_t b) { uint16_t c=(uint16_t)a+(uint16_t)b; flags&=~0x8D5; @@ -793,7 +710,7 @@ void setadd8(uint8_t a, uint8_t b) if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; } -void setadd8nc(uint8_t a, uint8_t b) +static void setadd8nc(uint8_t a, uint8_t b) { uint16_t c=(uint16_t)a+(uint16_t)b; flags&=~0x8D4; @@ -801,7 +718,7 @@ void setadd8nc(uint8_t a, uint8_t b) if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; } -void setadc8(uint8_t a, uint8_t b) +static void setadc8(uint8_t a, uint8_t b) { uint16_t c=(uint16_t)a+(uint16_t)b+tempc; flags&=~0x8D5; @@ -810,7 +727,7 @@ void setadc8(uint8_t a, uint8_t b) if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; } -void setadd16(uint16_t a, uint16_t b) +static void setadd16(uint16_t a, uint16_t b) { uint32_t c=(uint32_t)a+(uint32_t)b; flags&=~0x8D5; @@ -819,7 +736,7 @@ void setadd16(uint16_t a, uint16_t b) if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; } -void setadd16nc(uint16_t a, uint16_t b) +static void setadd16nc(uint16_t a, uint16_t b) { uint32_t c=(uint32_t)a+(uint32_t)b; flags&=~0x8D4; @@ -827,7 +744,7 @@ void setadd16nc(uint16_t a, uint16_t b) if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; } -void setadc16(uint16_t a, uint16_t b) +static void setadc16(uint16_t a, uint16_t b) { uint32_t c=(uint32_t)a+(uint32_t)b+tempc; flags&=~0x8D5; @@ -837,7 +754,7 @@ void setadc16(uint16_t a, uint16_t b) if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; } -void setsub8(uint8_t a, uint8_t b) +static void setsub8(uint8_t a, uint8_t b) { uint16_t c=(uint16_t)a-(uint16_t)b; flags&=~0x8D5; @@ -846,7 +763,7 @@ void setsub8(uint8_t a, uint8_t b) if ((a^b)&(a^c)&0x80) flags|=V_FLAG; if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; } -void setsub8nc(uint8_t a, uint8_t b) +static void setsub8nc(uint8_t a, uint8_t b) { uint16_t c=(uint16_t)a-(uint16_t)b; flags&=~0x8D4; @@ -854,7 +771,7 @@ void setsub8nc(uint8_t a, uint8_t b) if ((a^b)&(a^c)&0x80) flags|=V_FLAG; if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; } -void setsbc8(uint8_t a, uint8_t b) +static void setsbc8(uint8_t a, uint8_t b) { uint16_t c=(uint16_t)a-(((uint16_t)b)+tempc); flags&=~0x8D5; @@ -863,7 +780,7 @@ void setsbc8(uint8_t a, uint8_t b) if ((a^b)&(a^c)&0x80) flags|=V_FLAG; if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; } -void setsub16(uint16_t a, uint16_t b) +static void setsub16(uint16_t a, uint16_t b) { uint32_t c=(uint32_t)a-(uint32_t)b; flags&=~0x8D5; @@ -873,7 +790,7 @@ void setsub16(uint16_t a, uint16_t b) // if (output) printf("%04X %04X %i\n",a^b,a^c,flags&V_FLAG); if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; } -void setsub16nc(uint16_t a, uint16_t b) +static void setsub16nc(uint16_t a, uint16_t b) { uint32_t c=(uint32_t)a-(uint32_t)b; flags&=~0x8D4; @@ -882,7 +799,7 @@ void setsub16nc(uint16_t a, uint16_t b) if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; } -void setsbc16(uint16_t a, uint16_t b) +static void setsbc16(uint16_t a, uint16_t b) { uint32_t c=(uint32_t)a-(((uint32_t)b)+tempc); flags&=~0x8D5; @@ -893,107 +810,31 @@ void setsbc16(uint16_t a, uint16_t b) if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; } - +int totaldiff = 0; +int current_diff = 0; void clockhardware() { - cycdiff-=cycles; - - keybsenddelay--; - if (keybsenddelay<1) - { - keybsenddelay = 1000;//2500; - keyboard_poll(); - } - - pit.c[0]-=cycdiff; - pit.c[1]-=cycdiff; - if (ppi.pb&1) pit.c[2]-=cycdiff; - - if ((pit.c[0]<1)||(pit.c[1]<1)||(pit.c[2]<1)) pit_poll(); - - spktime-=cycdiff; - if (spktime<=0.0) - { - spktime+=SPKCONST; - pollspk(); - pollgussamp(); - getsbsamp(); - getdacsamp(); - polladlib(); - } - soundtime-=cycdiff; - if (soundtime<=0.0) - { - soundtime+=SOUNDCONST; - pollsound60hz(); - } - gustime-=cycdiff; - while (gustime<=0.0) - { - gustime+=GUSCONST; -// printf("1Poll GUS %f %f\n",gustime,GUSCONST); - pollgus(); -// printf("2Poll GUS\n"); - } - vidtime-=cycdiff; - if (vidtime<=0.0) - { - pollvideo(); -// polltandy(); -// pollmda(); -// pollcga(); - } - if (disctime) - { - disctime-=(cycdiff/2); - if (disctime<=0) - { - disctime=0; - fdc_poll(); - } - } - if (mousedelay) - { - mousedelay--; - if (!mousedelay) - mousecallback(); - } - if (sbenable) - { - sbcount-=cycdiff; - if (sbcount<0) - { - sbcount+=sblatcho; - pollsb(); - } - } - rtctime-=cycdiff; - if (rtctime<0) - { - nvr_rtc(); - } - cycdiff=cycles; - if (idecallback[0]) - { - idecallback[0]--; - if (idecallback[0]<=0) - { -// pclog("IDE time over\n"); - idecallback[0]=0; - callbackide(0); - } - } + int diff = cycdiff - cycles - current_diff; + + current_diff += diff; + totaldiff += diff; + pit.c[0] -= diff; + pit.c[1] -= diff; + if (ppi.pb & 1) pit.c[2] -= diff; + if ((pit.c[0] < 1) || (pit.c[1] < 1) || (pit.c[2] < 1)) pit_poll(); + + timer_clock(diff); } - int firstrepcycle=1; -void cpu_writeport(uint32_t port, uint8_t val) { outb(port,val); } +int firstrepcycle=1; + void rep(int fv) { uint8_t temp; int c=CX; uint8_t temp2; - uint16_t tempw,tempw2,tempw3; + uint16_t tempw,tempw2; uint16_t ipc=oldpc;//pc-1; int changeds=0; uint32_t oldds; @@ -1051,9 +892,9 @@ void rep(int fv) if (flags&D_FLAG) { DI--; SI--; } else { DI++; SI++; } c--; - cycles-=((AT)?4:17); + cycles-=17; clockhardware(); - FETCHADD(((AT)?4:17)-memcycs); + FETCHADD(17-memcycs); } if (IRQTEST && c>0) pc=ipc; // if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } @@ -1069,9 +910,9 @@ void rep(int fv) if (flags&D_FLAG) { DI-=2; SI-=2; } else { DI+=2; SI+=2; } c--; - cycles-=((AT)?4:17); + cycles-=17; clockhardware(); - FETCHADD(((AT)?4:17)-memcycs); + FETCHADD(17 - memcycs); } if (IRQTEST && c>0) pc=ipc; // if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } @@ -1090,11 +931,10 @@ void rep(int fv) if (flags&D_FLAG) { DI--; SI--; } else { DI++; SI++; } c--; - if (!AT) cycles-=30; - else cycles-=9; + cycles -= 30; setsub8(temp,temp2); clockhardware(); - FETCHADD(((AT)?9:30)-memcycs); + FETCHADD(30 - memcycs); } if (IRQTEST && c>0 && (fv==((flags&Z_FLAG)?1:0))) pc=ipc; // if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; FETCHCLEAR(); } @@ -1111,11 +951,10 @@ void rep(int fv) if (flags&D_FLAG) { DI-=2; SI-=2; } else { DI+=2; SI+=2; } c--; - if (!AT) cycles-=30; - else cycles-=9; + cycles -= 30; setsub16(tempw,tempw2); clockhardware(); - FETCHADD(((AT)?9:30)-memcycs); + FETCHADD(30 - memcycs); } if (IRQTEST && c>0 && (fv==((flags&Z_FLAG)?1:0))) pc=ipc; // if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; FETCHCLEAR(); } @@ -1130,9 +969,9 @@ void rep(int fv) if (flags&D_FLAG) DI--; else DI++; c--; - cycles-=((AT)?3:10); + cycles -= 10; clockhardware(); - FETCHADD(((AT)?3:10)-memcycs); + FETCHADD(10 - memcycs); } if (IRQTEST && c>0) pc=ipc; // if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } @@ -1146,14 +985,13 @@ void rep(int fv) if (flags&D_FLAG) DI-=2; else DI+=2; c--; - cycles-=((AT)?3:10); + cycles -= 10; clockhardware(); - FETCHADD(((AT)?3:10)-memcycs); + FETCHADD(10 - memcycs); } if (IRQTEST && c>0) pc=ipc; // if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } // else firstrepcycle=1; -// printf("REP STOSW %04X:%04X %04X:%04X %04X %04X\n",CS,pc,ES,DI,AX,CX); } break; case 0xAC: /*REP LODSB*/ if (c>0) @@ -1191,7 +1029,7 @@ void rep(int fv) if (flags&D_FLAG) DI--; else DI++; c--; - cycles-=((AT)?8:15); + cycles -= 15; } //if (output) printf("%i %i %i %i\n",c,(c>0),(fv==((flags&Z_FLAG)?1:0)),((c>0) && (fv==((flags&Z_FLAG)?1:0)))); if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; FETCHCLEAR(); } @@ -1208,7 +1046,7 @@ void rep(int fv) if (flags&D_FLAG) DI-=2; else DI+=2; c--; - cycles-=((AT)?8:15); + cycles -= 15; } if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; FETCHCLEAR(); } else firstrepcycle=1; @@ -1233,7 +1071,7 @@ int firstrepcycle; int skipnextprint=0; -int instime=0,instimer=0; +int instime=0; //#if 0 void execx86(int cycs) { @@ -1245,7 +1083,7 @@ void execx86(int cycs) int c; int tempi; int trap; - FILE *f; + // printf("Run x86! %i %i\n",cycles,cycs); cycles+=cycs; // i86_Execute(cycs); @@ -1258,6 +1096,7 @@ void execx86(int cycs) // if (pc==0x96B && cs==0x9E040) { printf("Hit it\n"); output=1; timetolive=150; } // if (pc<0x8000) printf("%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X %i\n",pc,AX,BX,CX,DX,cs>>4,ds>>4,es>>4,ss>>4,DI,SI,BP,SP,opcode,flags,disctime); cycdiff=cycles; + current_diff = 0; cycles-=nextcyc; // if (instime) pclog("Cycles %i %i\n",cycles,cycdiff); nextcyc=0; @@ -1273,14 +1112,14 @@ void execx86(int cycs) // output=1; // if (output) printf("%04X:%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X\n",cs>>4,pc,AX,BX,CX,DX,cs>>4,ds>>4,es>>4,ss>>4,DI,SI,BP,SP,opcode,flags&~0x200,rmdat); //#if 0 - if (output && /*cs<0xF0000 && */!ssegs && (pc<0x43A || pc>0x44A))//opcode!=0x26 && opcode!=0x36 && opcode!=0x2E && opcode!=0x3E) + if (output) { - if ((opcode!=0xF2 && opcode!=0xF3) || firstrepcycle) - { +// if ((opcode!=0xF2 && opcode!=0xF3) || firstrepcycle) +// { if (!skipnextprint) printf("%04X:%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X %02X %02X %02X %02X\n",cs,pc,AX,BX,CX,DX,CS,DS,ES,SS,DI,SI,BP,SP,opcode,flags, ram[0x413], ram[0x414], ram[0x415], ram[0x416]); skipnextprint=0; // ins++; - } +// } } //#endif pc++; @@ -2549,74 +2388,24 @@ void execx86(int cycs) lastcs=CS; temp=FETCH(); -// if (temp == 0x13 && AX == 0x0201 && ES == 0x0BF5 && CX == 0x1D06) output = 3; -// if (temp==0x10 && !AH) printf("Entering mode %02X\n",AL); -// if (temp==0x18 || temp==0x19) { printf("INT %02X\n",temp); output=1; } -// /*if (temp==0x13) */printf("INT %02X %04X %04X:%04X %04X %04X:%04X %04X:%04X\n",temp,AX,ES,BX,CX,DS,DX,CS,pc); - //if (temp == 0x13 && AH == 2) output = 3; -/* if (CS==0xC800 && temp==0x13) - { - output=3; - timetolive=100000; - }*/ -/* if (temp==0x10) printf("INT 10 %04X %04X %04X %04X %04X:%04X %06X %06X %c\n",AX,BX,CX,DX,cs>>4,pc,ds,ds+DX, (AL > 31) ? AL : '.'); - if (temp == 0x10 && AX == 0xe35) - { - dumpregs(); + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),flags|0xF000); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),pc); + flags&=~T_FLAG; + SP-=6; + addr=temp<<2; + pc=readmemw(0,addr); + + loadcs(readmemw(0,addr+2)); + FETCHCLEAR(); - }*/ -/* if (temp==0x21 && AH==9) - { - addr=0; - while (ram[ds+DX+addr]!='$') - { - printf("%c",ram[ds+DX+addr]); - addr++; - } - printf("\n"); - printf("Called from %04X\n",readmemw(ss,SP)); - }*/ -// output=0; -// if (temp==0x13 && AH==3) printf("Write sector %04X:%04X %05X\n",es>>4,BX,es+BX); -/* if (temp==0x13 && (DL==0x80 || DL==0x81) && AH>0) - { - int13hdc(); - } - else *//*if (temp==0x13 && AH==2 && DL<2)// && FASTDISC) - { - int13read(); - //output=1; - } - else if (temp==0x13 && AH==3 && DL<2)// && FASTDISC) - { - int13write(); - } - else if (temp==0x13 && AH==4 && DL<2)// && FASTDISC) - { - AH=0; - flags&=~C_FLAG; - } - else - {*/ - if (ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),flags|0xF000); - writememw(ss,((SP-4)&0xFFFF),CS); - writememw(ss,((SP-6)&0xFFFF),pc); - flags&=~T_FLAG; - SP-=6; - addr=temp<<2; - pc=readmemw(0,addr); -// printf("CD\n"); - loadcs(readmemw(0,addr+2)); - FETCHCLEAR(); -// } cycles-=71; break; case 0xCF: /*IRET*/ if (ssegs) ss=oldss; tempw=CS; tempw2=pc; - inint=0; pc=readmemw(ss,SP); // printf("CF\n"); loadcs(readmemw(ss,((SP+2)&0xFFFF))); @@ -3063,14 +2852,14 @@ void execx86(int cycs) tempws=FETCH(); AH=AL/tempws; AL%=tempws; - setznp168(AX); + setznp16(AX); cycles-=83; break; case 0xD5: /*AAD*/ tempws=FETCH(); AL=(AH*tempws)+AL; AH=0; - setznp168(AX); + setznp16(AX); cycles-=60; break; case 0xD7: /*XLAT*/ @@ -3669,7 +3458,6 @@ void execx86(int cycs) // printf("INT INT INT\n"); loadcs(readmemw(0,addr+2)); FETCHCLEAR(); - inint=1; // printf("INTERRUPT\n"); } } diff --git a/src/adlib.c b/src/adlib.c deleted file mode 100644 index d4b2828..0000000 --- a/src/adlib.c +++ /dev/null @@ -1,187 +0,0 @@ -#include -#include -#include "ibm.h" -#include "mame/fmopl.h" -#include "mame/ymf262.h" - -/*Interfaces between PCem and the actual Adlib emulator*/ - -static int adlib_inited = 0; -int adlibpos=0; -void *YM3812[2]; -void *YMF262; -int fm_timers[2][2],fm_timers_enable[2][2]; - -void adlib_write(uint16_t a, uint8_t v) -{ -// printf("Adlib write %04X %02X %i\n",a,v,sbtype); - if (!sbtype) return; - if (sbtype=SBPRO2) - { - switch (a) - { - case 0x220: case 0x221: - case 0x222: case 0x223: - case 0x228: case 0x229: - case 0x388: case 0x389: - temp=ymf262_read(YMF262,a); -// pclog("YMF262 read %03X %02X\n",a,temp); - cycles-=(int)(isa_timing * 8); - return temp; - } - } - if (!sbtype) return 0xFF; - switch (a) - { - case 0x220: case 0x221: - if (sbtype=SBPRO2) - { - ymf262_update_one(YMF262,ad_bufs,size); - for (c=0;c -#include "ibm.h" - -int cmsaddrs[2]; -uint8_t cmsregs[2][32]; -uint16_t cmslatch[12],cmsnoisefreq[12]; -int cmsfreq[12]; -float cmscount[12]; -int cmsvol[12][2]; -int cmsstat[12]; -uint16_t cmsnoise[4]; -int cmsnoisecount[4]; -int cmsnoisetype[4]; - -#define CMSCONST (62500.0/44100.0) - -void getcms(signed short *p, int size) -{ - int c,d; - int ena[12],noiseena[12]; - for (c=0;c<6;c++) - { - ena[c]=(cmsregs[0][0x14]&(1<=(22050)) - { - cmscount[d]-=(22050); - cmsstat[d]^=1; - } - } - else if (noiseena[d]) - { - if (cmsnoise[d/3]&1) p[c] +=(cmsvol[d][0]*90); - if (cmsnoise[d/3]&1) p[c+1]+=(cmsvol[d][0]*90); - } - } - for (d=0;d<4;d++) - { - cmsnoisecount[d]+=cmsnoisefreq[d]; - while (cmsnoisecount[d]>=22050) - { - cmsnoisecount[d]-=22050; - cmsnoise[d]<<=1; - if (!(((cmsnoise[d]&0x4000)>>8)^(cmsnoise[d]&0x40))) cmsnoise[d]|=1; - } - } - } -} - -void writecms(uint16_t addr, uint8_t val) -{ - int voice; - int chip=(addr&2)>>1; - if (addr&1) - cmsaddrs[chip]=val&31; - else - { - cmsregs[chip][cmsaddrs[chip]&31]=val; - switch (cmsaddrs[chip]&31) - { - case 0x00: case 0x01: case 0x02: /*Volume*/ - case 0x03: case 0x04: case 0x05: - voice=cmsaddrs[chip]&7; - if (chip) voice+=6; - cmsvol[voice][0]=val&0xF;//((val&0xF)+(val>>4))>>1; - cmsvol[voice][1]=val>>4; - break; - case 0x08: case 0x09: case 0x0A: /*Frequency*/ - case 0x0B: case 0x0C: case 0x0D: - voice=cmsaddrs[chip]&7; - if (chip) voice+=6; - cmslatch[voice]=(cmslatch[voice]&0x700)|val; - cmsfreq[voice]=(15625<<(cmslatch[voice]>>8))/(511-(cmslatch[voice]&255)); - break; - case 0x10: case 0x11: case 0x12: /*Octave*/ - voice=(cmsaddrs[chip]&3)<<1; - if (chip) voice+=6; - cmslatch[voice]=(cmslatch[voice]&0xFF)|((val&7)<<8); - cmslatch[voice+1]=(cmslatch[voice+1]&0xFF)|((val&0x70)<<4); - cmsfreq[voice]=(15625<<(cmslatch[voice]>>8))/(511-(cmslatch[voice]&255)); - cmsfreq[voice+1]=(15625<<(cmslatch[voice+1]>>8))/(511-(cmslatch[voice+1]&255)); - break; - case 0x16: /*Noise*/ - voice=chip*2; - cmsnoisetype[voice]=val&3; - cmsnoisetype[voice+1]=(val>>4)&3; - break; - } - } -} - -uint8_t readcms(uint16_t addr) -{ - int chip=(addr&2)>>1; - if (addr&1) return cmsaddrs[chip]; - return cmsregs[chip][cmsaddrs[chip]&31]; -} - diff --git a/src/device.c b/src/device.c new file mode 100644 index 0000000..5a97eb0 --- /dev/null +++ b/src/device.c @@ -0,0 +1,59 @@ +#include "ibm.h" +#include "device.h" + +static void *device_priv[256]; +static device_t *devices[256]; + +void device_init() +{ + memset(devices, 0, sizeof(devices)); +} + +void device_add(device_t *d) +{ + int c = 0; + void *priv; + + while (devices[c] != NULL && c < 256) + c++; + + if (c >= 256) + fatal("device_add : too many devices\n"); + + priv = d->init(); + if (priv == NULL) + fatal("device_add : device init failed\n"); + + devices[c] = d; + device_priv[c] = priv; +} + +void device_close_all() +{ + int c; + + for (c = 0; c < 256; c++) + { + if (devices[c] != NULL) + { + devices[c]->close(device_priv[c]); + devices[c] = device_priv[c] = NULL; + } + } +} + +void device_speed_changed() +{ + int c; + + for (c = 0; c < 256; c++) + { + if (devices[c] != NULL) + { + if (devices[c]->speed_changed != NULL) + { + devices[c]->speed_changed(device_priv[c]); + } + } + } +} diff --git a/src/device.h b/src/device.h new file mode 100644 index 0000000..e1605a3 --- /dev/null +++ b/src/device.h @@ -0,0 +1,12 @@ +typedef struct device_t +{ + char name[50]; + void *(*init)(); + void (*close)(void *priv); + void (*speed_changed)(void *priv); +} device_t; + +void device_init(); +void device_add(device_t *d); +void device_close_all(); +void device_speed_changed(); diff --git a/src/gus.c b/src/gus.c deleted file mode 100644 index e53c440..0000000 --- a/src/gus.c +++ /dev/null @@ -1,625 +0,0 @@ -#include -#include -#include -#include "ibm.h" - -extern int ins; -extern int timetolive; -int output; -//#define GUSRATECONST (44100.0/48000.0) -uint8_t *gusram; - -struct -{ - int global; - uint32_t addr,dmaaddr; - int voice; - uint32_t start[32],end[32],cur[32]; - uint32_t startx[32],endx[32],curx[32]; - uint32_t rstart[32],rend[32],rcur[32]; - uint16_t freq[32]; - uint16_t rfreq[32]; - uint8_t ctrl[32]; - uint8_t rctrl[32]; - int curvol[32]; - int t1on,t2on; - uint8_t tctrl; - uint16_t t1,t2,t1l,t2l; - uint8_t irqstatus,irqstatus2; - uint8_t adcommand; - int waveirqs[32],rampirqs[32]; - int voices; - uint8_t dmactrl; -} gus; - -double vol16bit[4096]; - -void initgus() -{ - int c; - for (c=0;c<32;c++) - { - gus.ctrl[c]=1; - gus.rctrl[c]=1; - gus.rfreq[c]=63*512; - } - gusram=malloc(1024*1024); - - double out = 1.0; - for (c=4095;c>=0;c--) { - vol16bit[c]=out;//(float)c/4095.0;//out; - out/=1.002709201; /* 0.0235 dB Steps */ - } - - printf("Top volume %f %f %f %f\n",vol16bit[4095],vol16bit[3800],vol16bit[3000],vol16bit[2048]); - gus.voices=14; - -} - -void dumpgus() -{ -/* FILE *f=fopen("gusram.dmp","wb"); - fwrite(gusram,1024*1024,1,f); - fclose(f);*/ -} - -void pollgusirqs() -{ - int c; - gus.irqstatus&=~0x60; - for (c=0;c<32;c++) - { - if (gus.waveirqs[c]) - { -// gus.waveirqs[c]=0; - gus.irqstatus2=0x60|c; - gus.irqstatus|=0x20; -// printf("Voice IRQ %i %02X %i\n",c,gus.irqstatus2,ins); - picintlevel(0x20); -// output=3; -// timetolive=5000; - return; - } - if (gus.rampirqs[c]) - { -// gus.rampirqs[c]=0; - gus.irqstatus2=0xA0|c; - gus.irqstatus|=0x40; -// printf("Ramp IRQ %i %02X %i\n",c,gus.irqstatus2,ins); - picintlevel(0x20); - return; - } - } - gus.irqstatus2=0xE0; -// gus.irqstatus&=~0x20; - if (!gus.irqstatus) picintc(0x20); -} - -int gusirqnext=0; - -void writegus(uint16_t addr, uint8_t val) -{ - int c,d; -// printf("Write GUS %04X %02X %04X:%04X\n",addr,val,CS,pc); - switch (addr) - { - case 0x342: /*Voice select*/ - gus.voice=val&31; - break; - case 0x343: /*Global select*/ - gus.global=val; - break; - case 0x344: /*Global low*/ -// if (gus.global!=0x43 && gus.global!=0x44) printf("Writing register %02X %02X %02X\n",gus.global,gus.voice,val); - switch (gus.global) - { - case 0: /*Voice control*/ -// if (val&1 && !(gus.ctrl[gus.voice]&1)) printf("Voice on %i\n",gus.voice); - gus.ctrl[gus.voice]=val; - break; - case 1: /*Frequency control*/ - gus.freq[gus.voice]=(gus.freq[gus.voice]&0xFF00)|val; - break; - case 2: /*Start addr high*/ - gus.startx[gus.voice]=(gus.startx[gus.voice]&0xF807F)|(val<<7); - gus.start[gus.voice]=(gus.start[gus.voice]&0x1F00FFFF)|(val<<16); -// printf("Write %i start %08X %08X\n",gus.voice,gus.start[gus.voice],gus.startx[gus.voice]); - break; - case 3: /*Start addr low*/ - gus.start[gus.voice]=(gus.start[gus.voice]&0x1FFFFF00)|val; -// printf("Write %i start %08X %08X\n",gus.voice,gus.start[gus.voice],gus.startx[gus.voice]); - break; - case 4: /*End addr high*/ - gus.endx[gus.voice]=(gus.endx[gus.voice]&0xF807F)|(val<<7); - gus.end[gus.voice]=(gus.end[gus.voice]&0x1F00FFFF)|(val<<16); -// printf("Write %i end %08X %08X\n",gus.voice,gus.end[gus.voice],gus.endx[gus.voice]); - break; - case 5: /*End addr low*/ - gus.end[gus.voice]=(gus.end[gus.voice]&0x1FFFFF00)|val; -// printf("Write %i end %08X %08X\n",gus.voice,gus.end[gus.voice],gus.endx[gus.voice]); - break; - - case 0x6: /*Ramp frequency*/ - gus.rfreq[gus.voice] = (int)( (double)((val & 63)*512)/(double)(1 << (3*(val >> 6)))); -// printf("RFREQ %02X %i %i %f\n",val,gus.voice,gus.rfreq[gus.voice],(double)(val & 63)/(double)(1 << (3*(val >> 6)))); - break; - - case 0x9: /*Current volume*/ - gus.curvol[gus.voice]=gus.rcur[gus.voice]=(gus.rcur[gus.voice]&0x1FE0000)|(val<<9); -// printf("Vol %i is %04X\n",gus.voice,gus.curvol[gus.voice]); - break; - - case 0xA: /*Current addr high*/ - gus.cur[gus.voice]=(gus.cur[gus.voice]&0x1F00FFFF)|(val<<16); -gus.curx[gus.voice]=(gus.curx[gus.voice]&0xF807F00)|((val<<7)<<8); -// gus.cur[gus.voice]=(gus.cur[gus.voice]&0x0F807F00)|((val<<7)<<8); -// printf("Write %i cur %08X\n",gus.voice,gus.cur[gus.voice],gus.curx[gus.voice]); - break; - case 0xB: /*Current addr low*/ - gus.cur[gus.voice]=(gus.cur[gus.voice]&0x1FFFFF00)|val; -// printf("Write %i cur %08X\n",gus.voice,gus.cur[gus.voice],gus.curx[gus.voice]); - break; - - case 0x42: /*DMA address low*/ - gus.dmaaddr=(gus.dmaaddr&0xFF000)|(val<<4); - break; - - case 0x43: /*Address low*/ - gus.addr=(gus.addr&0xFFF00)|val; - break; - case 0x45: /*Timer control*/ -// printf("Timer control %02X\n",val); - gus.tctrl=val; - break; - } - break; - case 0x345: /*Global high*/ -// if (gus.global!=0x43 && gus.global!=0x44) printf("HWriting register %02X %02X %02X %04X:%04X\n",gus.global,gus.voice,val,CS,pc); - switch (gus.global) - { - case 0: /*Voice control*/ - if (!(val&1) && gus.ctrl[gus.voice]&1) - { -// printf("Voice on %i - start %05X end %05X freq %04X\n",gus.voice,gus.start[gus.voice],gus.end[gus.voice],gus.freq[gus.voice]); -// if (val&0x40) gus.cur[gus.voice]=gus.end[gus.voice]<<8; -// else gus.cur[gus.voice]=gus.start[gus.voice]<<8; - } - if (val&2) val|=1; - gus.waveirqs[gus.voice]=val&0x80; - gus.ctrl[gus.voice]=val&0x7F; - pollgusirqs(); - break; - case 1: /*Frequency control*/ - gus.freq[gus.voice]=(gus.freq[gus.voice]&0xFF)|(val<<8); - break; - case 2: /*Start addr high*/ - gus.startx[gus.voice]=(gus.startx[gus.voice]&0x07FFF)|(val<<15); - gus.start[gus.voice]=(gus.start[gus.voice]&0x00FFFFFF)|((val&0x1F)<<24); -// printf("Write %i start %08X %08X %02X\n",gus.voice,gus.start[gus.voice],gus.startx[gus.voice],val); - break; - case 3: /*Start addr low*/ - gus.startx[gus.voice]=(gus.startx[gus.voice]&0xFFF80)|(val&0x7F); - gus.start[gus.voice]=(gus.start[gus.voice]&0x1FFF00FF)|(val<<8); -// printf("Write %i start %08X %08X\n",gus.voice,gus.start[gus.voice],gus.startx[gus.voice]); - break; - case 4: /*End addr high*/ - gus.endx[gus.voice]=(gus.endx[gus.voice]&0x07FFF)|(val<<15); - gus.end[gus.voice]=(gus.end[gus.voice]&0x00FFFFFF)|((val&0x1F)<<24); -// printf("Write %i end %08X %08X %02X\n",gus.voice,gus.end[gus.voice],gus.endx[gus.voice],val); - break; - case 5: /*End addr low*/ - gus.endx[gus.voice]=(gus.endx[gus.voice]&0xFFF80)|(val&0x7F); - gus.end[gus.voice]=(gus.end[gus.voice]&0x1FFF00FF)|(val<<8); -// printf("Write %i end %08X %08X\n",gus.voice,gus.end[gus.voice],gus.endx[gus.voice]); - break; - - case 0x6: /*Ramp frequency*/ - gus.rfreq[gus.voice] = (int)( (double)((val & 63)*512)/(double)(1 << (3*(val >> 6)))); -// printf("RFREQ %02X %i %i %f %i\n",val,gus.voice,gus.rfreq[gus.voice],(double)(val & 63)/(double)(1 << (3*(val >> 6))),ins); - break; - case 0x7: /*Ramp start*/ - gus.rstart[gus.voice]=val<<17; - break; - case 0x8: /*Ramp end*/ - gus.rend[gus.voice]=val<<17; - break; - case 0x9: /*Current volume*/ - gus.curvol[gus.voice]=gus.rcur[gus.voice]=(gus.rcur[gus.voice]&0x1FE00)|(val<<17); -// printf("Vol %i is %04X\n",gus.voice,gus.curvol[gus.voice]); - break; - - case 0xA: /*Current addr high*/ - gus.cur[gus.voice]=(gus.cur[gus.voice]&0x00FFFFFF)|((val&0x1F)<<24); -gus.curx[gus.voice]=(gus.curx[gus.voice]&0x07FFF00)|((val<<15)<<8); -// printf("Write %i cur %08X %08X %02X\n",gus.voice,gus.cur[gus.voice],gus.curx[gus.voice],val); -// gus.cur[gus.voice]=(gus.cur[gus.voice]&0x007FFF00)|((val<<15)<<8); - break; - case 0xB: /*Current addr low*/ - gus.cur[gus.voice]=(gus.cur[gus.voice]&0x1FFF00FF)|(val<<8); -gus.curx[gus.voice]=(gus.curx[gus.voice]&0xFFF8000)|((val&0x7F)<<8); -// gus.cur[gus.voice]=(gus.cur[gus.voice]&0x0FFF8000)|((val&0x7F)<<8); -// printf("Write %i cur %08X %08X\n",gus.voice,gus.cur[gus.voice],gus.curx[gus.voice]); - break; - case 0xD: /*Ramp control*/ - if (val&2) val|=1; - gus.rampirqs[gus.voice]=val&0x80; - gus.rctrl[gus.voice]=val&0x7F; - pollgusirqs(); -// printf("Ramp control %02i %02X %02X %i\n",gus.voice,val,gus.rampirqs[gus.voice],ins); - break; - - case 0xE: - gus.voices=(val&63)+1; - if (gus.voices>32) gus.voices=32; - if (gus.voices<14) gus.voices=14; - gus.global=val; -// printf("GUS voices %i\n",val&31); - break; - - case 0x41: /*DMA*/ - if (val&1) - { -// printf("DMA start! %05X %02X\n",gus.dmaaddr,val); - c=0; - while (c<65536) - { - d=readdma3(); - if (d==-1) break; - if (val&0x80) d^=0x80; - gusram[gus.dmaaddr]=d; - gus.dmaaddr++; - gus.dmaaddr&=0xFFFFF; - c++; - } -// printf("Transferred %i bytes\n",c); - gus.dmactrl=val&~0x40; - if (val&0x20) gusirqnext=1; -// exit(-1); - } - break; - - case 0x42: /*DMA address low*/ - gus.dmaaddr=(gus.dmaaddr&0xFF0)|(val<<12); - break; - - case 0x43: /*Address low*/ - gus.addr=(gus.addr&0xF00FF)|(val<<8); - break; - case 0x44: /*Address high*/ - gus.addr=(gus.addr&0xFFFF)|((val<<16)&0xF0000); - break; - case 0x45: /*Timer control*/ - if (!(val&4)) gus.irqstatus&=~4; - if (!(val&8)) gus.irqstatus&=~8; -// printf("Timer control %02X\n",val); -/* if ((val&4) && !(gus.tctrl&4)) - { - gus.t1=gus.t1l; - gus.t1on=1; - }*/ - gus.tctrl=val; - break; - case 0x46: /*Timer 1*/ - gus.t1=gus.t1l=val; - gus.t1on=1; -// printf("GUS timer 1 %i\n",val); - break; - case 0x47: /*Timer 2*/ - gus.t2=gus.t2l=val<<2; - gus.t2on=1; -// printf("GUS timer 2 %i\n",val); - break; - } - break; - case 0x347: /*DRAM access*/ - gusram[gus.addr]=val; -// pclog("GUS RAM write %05X %02X\n",gus.addr,val); - gus.addr&=0xFFFFF; - break; - case 0x248: case 0x388: gus.adcommand=val; break; - } -} - -uint8_t readgus(uint16_t addr) -{ - uint8_t val; -// /*if (addr!=0x246) */printf("Read GUS %04X %04X(%06X):%04X %02X\n",addr,CS,cs,pc,gus.global); -// output=3; - switch (addr) - { - case 0x240: return 0; - case 0x246: /*IRQ status*/ - val=gus.irqstatus; -// printf("246 status %02X\n",val); -// gus.irqstatus=0; -// if (gus.irqstatus2==0xE0) picintc(0x20); - return val; - case 0x24A: - return gus.adcommand; - case 0x24B: case 0x24F: return 0; - case 0x340: /*MIDI status*/ - case 0x341: /*MIDI data*/ - return 0; - case 0x342: return gus.voice; - case 0x343: return gus.global; - case 0x344: /*Global low*/ -// /*if (gus.global!=0x43 && gus.global!=0x44) */printf("Reading register %02X %02X\n",gus.global,gus.voice); - switch (gus.global) - { - case 0x82: /*Start addr high*/ - return gus.start[gus.voice]>>16; - case 0x83: /*Start addr low*/ - return gus.start[gus.voice]&0xFF; - - case 0x89: /*Current volume*/ - return gus.rcur[gus.voice]>>9; - case 0x8A: /*Current addr high*/ - return gus.cur[gus.voice]>>16; - case 0x8B: /*Current addr low*/ - return gus.cur[gus.voice]&0xFF; - - case 0x8F: /*IRQ status*/ - val=gus.irqstatus2; -// pclog("Read IRQ status - %02X\n",val); - gus.rampirqs[gus.irqstatus2&0x1F]=0; - gus.waveirqs[gus.irqstatus2&0x1F]=0; - pollgusirqs(); - return val; - } - //fatal("Bad GUS global low read %02X\n",gus.global); - break; - case 0x345: /*Global high*/ -// /*if (gus.global!=0x43 && gus.global!=0x44) */printf("HReading register %02X %02X\n",gus.global,gus.voice); - switch (gus.global) - { - case 0x80: /*Voice control*/ - return gus.ctrl[gus.voice]|(gus.waveirqs[gus.voice]?0x80:0); - - case 0x82: /*Start addr high*/ - return gus.start[gus.voice]>>24; - case 0x83: /*Start addr low*/ - return gus.start[gus.voice]>>8; - - case 0x89: /*Current volume*/ - return gus.rcur[gus.voice]>>17; - - case 0x8A: /*Current addr high*/ - return gus.cur[gus.voice]>>24; - case 0x8B: /*Current addr low*/ - return gus.cur[gus.voice]>>8; - - case 0x8D: -// pclog("Read ramp control %02X %08X %08X %08X %08X\n",gus.rctrl[gus.voice]|(gus.rampirqs[gus.voice]?0x80:0),gus.rcur[gus.voice],gus.rfreq[gus.voice],gus.rstart[gus.voice],gus.rend[gus.voice]); - return gus.rctrl[gus.voice]|(gus.rampirqs[gus.voice]?0x80:0); - - case 0x8F: /*IRQ status*/ - val=gus.irqstatus2; -// pclog("Read IRQ status - %02X\n",val); - gus.rampirqs[gus.irqstatus2&0x1F]=0; - gus.waveirqs[gus.irqstatus2&0x1F]=0; - pollgusirqs(); - return val; - - case 0x41: /*DMA control*/ - val=gus.dmactrl|((gus.irqstatus&0x80)?0x40:0); - gus.irqstatus&=~0x80; - return val; - case 0x45: /*Timer control*/ - return gus.tctrl; - case 0x49: /*Sampling control*/ - return 0; - } - //fatal("Bad GUS global high read %02X\n",gus.global); - break; - case 0x346: return 0; - case 0x347: /*DRAM access*/ - val=gusram[gus.addr]; -// pclog("GUS RAM read %05X %02X\n",gus.addr,val); -// output=3; - gus.addr&=0xFFFFF; - return val; - case 0x349: return 0; - } -// printf("Bad GUS read %04X! %02X\n",addr,gus.global); -// exit(-1); - return 0; -} - -void pollgus() -{ - if (gus.t1on) - { - gus.t1++; - if (gus.t1>=0xFF) - { -// gus.t1on=0; - gus.t1=gus.t1l; - if (gus.tctrl&4) - { - picintlevel(0x20); - gus.irqstatus|=4; -// printf("GUS T1 IRQ!\n"); - } - } - } - if (gusirqnext) - { - gusirqnext=0; - gus.irqstatus|=0x80; - picintlevel(0x20); - } -} - -void pollgus2() -{ - if (gus.t2on) - { - gus.t2++; - if (gus.t2>=(0xFF<<2)) - { -// gus.t2on=0; - gus.t2=gus.t2l; - if (gus.tctrl&8) - { - picintlevel(0x20); - gus.irqstatus|=8; -// printf("GUS T2 IRQ!\n"); - } - } - } - if (gusirqnext) - { - gusirqnext=0; - gus.irqstatus|=0x80; - picintlevel(0x20); - } -} - -float gusfreqs[]= -{ - 44100,41160,38587,36317,34300,32494,30870,29400,28063,26843,25725,24696, - 23746,22866,22050,21289,20580,19916,19293 -}; - -int16_t gusbufferx[65536]; -int guspos=0; -void getgus(int16_t *p, int count) -{ - memcpy(p,gusbufferx,count*4); -// printf("Get %i samples %i\n",guspos,count); - guspos=0; - pollgusirqs(); -} - -void pollgussamp() -{ - uint32_t addr; - int c,d; - int16_t v; - int32_t vl; - int16_t p[2]; - float GUSRATECONST; - if (guspos>65500) return; -// return; - if (gus.voices<14) GUSRATECONST=44100.0/48000.0; - else GUSRATECONST=gusfreqs[gus.voices-14]/48000.0; -// printf("Voices %i freq %f\n",gus.voices,GUSRATECONST*48000.0); -// for (c=0;c>9; - addr=(addr&0xC0000)|((addr<<1)&0x3FFFE); - if (!(gus.freq[d]>>10)) /*Interpolate*/ - { - vl=(int16_t)(int8_t)((gusram[(addr+1)&0xFFFFF]^0x80)-0x80)*(511-(gus.cur[d]&511)); - vl+=(int16_t)(int8_t)((gusram[(addr+3)&0xFFFFF]^0x80)-0x80)*(gus.cur[d]&511); - v=vl>>9; - } - else - v=(int16_t)(int8_t)((gusram[(addr+1)&0xFFFFF]^0x80)-0x80); - } - else - { - if (!(gus.freq[d]>>10)) /*Interpolate*/ - { - vl=((int8_t)((gusram[(gus.cur[d]>>9)&0xFFFFF]^0x80)-0x80))*(511-(gus.cur[d]&511)); - vl+=((int8_t)((gusram[((gus.cur[d]>>9)+1)&0xFFFFF]^0x80)-0x80))*(gus.cur[d]&511); - v=vl>>9; - } - else - v=(int16_t)(int8_t)((gusram[(gus.cur[d]>>9)&0xFFFFF]^0x80)-0x80); - } -// v=(int16_t)((float)((gusram[(gus.cur[d]>>9)&0xFFFFF]^0x80)-0x80)*32.0*vol16bit[(gus.rcur[d]>>13)&4095]); - if ((gus.rcur[d]>>13)>4095) v=(int16_t)(float)(v)*24.0*vol16bit[4095]; - else v=(int16_t)(float)(v)*24.0*vol16bit[(gus.rcur[d]>>13)&4095]; -// if (!d) printf("%08X %08X %08X %05X %08X %08X %04X %f %04X %08X %i\n",gus.cur[d],gus.start[d],gus.end[d],gus.cur[d]>>9,gus.startx[d],gus.endx[d],gus.rcur[d],vol16bit[0],v,gus.freq[d],ins); -// if (!d) -// { - p[0]+=v; - p[1]+=v; -// } -// printf("Data from %08X\n",gus.cur[d]>>8); - if (gus.ctrl[d]&0x40) - { - gus.cur[d]-=(gus.freq[d]>>1)*GUSRATECONST; - if (gus.cur[d]<=gus.start[d]) - { - if (!(gus.rctrl[d]&4)) - { - if (!(gus.ctrl[d]&8)) gus.ctrl[d]|=1; - else if (gus.ctrl[d]&0x10) gus.ctrl[d]^=0x40; - gus.cur[d]=(gus.ctrl[d]&0x40)?gus.end[d]:gus.start[d]; - } - if (gus.ctrl[d]&0x20) gus.waveirqs[d]=1; - } - } - else - { - gus.cur[d]+=(gus.freq[d]>>1)*GUSRATECONST; -// pclog("GUS add %08X %f\n",gus.freq[d],GUSRATECONST); - if (gus.cur[d]>=gus.end[d]) - { - if (!(gus.rctrl[d]&4)) - { -// gus.ctrl[d]|=1; - if (!(gus.ctrl[d]&8)) gus.ctrl[d]|=1; - else if (gus.ctrl[d]&0x10) gus.ctrl[d]^=0x40; - gus.cur[d]=(gus.ctrl[d]&0x40)?gus.end[d]:gus.start[d]; - } - if (gus.ctrl[d]&0x20) gus.waveirqs[d]=1; - } - } - } - if (!(gus.rctrl[d]&1)) - { - if (gus.rctrl[d]&0x40) - { - gus.rcur[d]-=gus.rfreq[d]*GUSRATECONST*16; -// printf("RCUR- %i %i %i %i %i\n",d,gus.rfreq[d],gus.rcur[d],gus.rstart[d],gus.rend[d]); - if (gus.rcur[d]<=gus.rstart[d]) - { - if (gus.rctrl[d]&8) gus.rcur[d]=gus.rend[d]<<8; - else gus.rctrl[d]|=1; - if (gus.rctrl[d]&0x20) - { - gus.rampirqs[d]=1; -// pclog("Causing ramp IRQ %02X\n",gus.rctrl[d]); - } - } - } - else - { - gus.rcur[d]+=gus.rfreq[d]*GUSRATECONST*16; -// printf("RCUR+ %i %08X %08X %08X %08X\n",d,gus.rfreq[d],gus.rcur[d],gus.rstart[d],gus.rend[d]); - if (gus.rcur[d]>=gus.rend[d]) - { - if (gus.rctrl[d]&8) gus.rcur[d]=gus.rstart[d]<<8; - else gus.rctrl[d]|=1; - if (gus.rctrl[d]&0x20) - { - gus.rampirqs[d]=1; -// pclog("Causing ramp IRQ %02X\n",gus.rctrl[d]); - } - } - } - } - } - gusbufferx[guspos++]=p[0]; - gusbufferx[guspos++]=p[1]; - if (guspos==65536) guspos=0; -// } - pollgusirqs(); -} - -void gus_init() -{ - io_sethandler(0x0240, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL); - io_sethandler(0x0340, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL); - io_sethandler(0x0388, 0x0001, NULL, NULL, NULL, writegus, NULL, NULL); -} diff --git a/src/i430vx.c b/src/i430vx.c new file mode 100644 index 0000000..df4d8f7 --- /dev/null +++ b/src/i430vx.c @@ -0,0 +1,96 @@ +#include + +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "pci.h" + +#include "i430vx.h" + +static uint8_t card_i430vx[256]; + +static void i430vx_map(uint32_t addr, uint32_t size, int state) +{ + switch (state & 3) + { + case 0x0: mem_sethandler(addr, size, mem_read_bios, mem_read_biosw, mem_read_biosl, NULL, NULL, NULL , NULL); break; /*DRAM disabled, accesses directed to PCI bus*/ + case 0x1: mem_sethandler(addr, size, mem_read_ram, mem_read_ramw, mem_read_raml, NULL, NULL, NULL , NULL); break; /*Read only, DRAM write protected, non-cacheable*/ + case 0x2: mem_sethandler(addr, size, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_ram, mem_write_ramw, mem_write_raml, NULL); break; /*Write only*/ + case 0x3: mem_sethandler(addr, size, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, NULL); break; /*Read/write, non-cacheable*/ + /*Below are redundant*/ +// case 0x5: mem_sethandler(addr, size, mem_read_ram, mem_read_ramw, mem_read_raml, NULL, NULL, NULL ); break; /*Read only, DRAM write protected, cacheable*/ +// case 0x7: mem_sethandler(addr, size, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml); break; /*Read/write, non-cacheable*/ + } + flushmmucache_nopc(); +} +void i430vx_write(int func, int addr, uint8_t val, void *priv) +{ + if (func) + return; + + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + + case 0x59: /*PAM0*/ + if ((card_i430vx[0x59] ^ val) & 0xf0) + { + i430vx_map(0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); + } + pclog("i430vx_write : PAM0 write %02X\n", val); + break; + case 0x5e: /*PAM5*/ + if ((card_i430vx[0x5e] ^ val) & 0x0f) + i430vx_map(0xe0000, 0x04000, val & 0xf); + if ((card_i430vx[0x5e] ^ val) & 0xf0) + i430vx_map(0xe4000, 0x04000, val >> 4); + pclog("i430vx_write : PAM5 write %02X\n", val); + break; + case 0x5f: /*PAM6*/ + if ((card_i430vx[0x5f] ^ val) & 0x0f) + i430vx_map(0xe8000, 0x04000, val & 0xf); + if ((card_i430vx[0x5f] ^ val) & 0xf0) + i430vx_map(0xec000, 0x04000, val >> 4); + pclog("i430vx_write : PAM6 write %02X\n", val); + break; + } + + card_i430vx[addr] = val; +} + +uint8_t i430vx_read(int func, int addr, void *priv) +{ + if (func) + return 0xff; + + return card_i430vx[addr]; +} + + +void i430vx_init() +{ + pci_add_specific(0, i430vx_read, i430vx_write, NULL); + + memset(card_i430vx, 0, 256); + card_i430vx[0x00] = 0x86; card_i430vx[0x01] = 0x80; /*Intel*/ + card_i430vx[0x02] = 0x30; card_i430vx[0x03] = 0x70; /*82437VX*/ + card_i430vx[0x04] = 0x06; card_i430vx[0x05] = 0x00; + card_i430vx[0x06] = 0x00; card_i430vx[0x07] = 0x02; + card_i430vx[0x08] = 0x00; /*A0 stepping*/ + card_i430vx[0x09] = 0x00; card_i430vx[0x0a] = 0x00; card_i430vx[0x0b] = 0x06; + card_i430vx[0x52] = 0x42; /*256kb PLB cache*/ + card_i430vx[0x53] = 0x14; + card_i430vx[0x56] = 0x52; /*DRAM control*/ + card_i430vx[0x57] = 0x01; + card_i430vx[0x60] = card_i430vx[0x61] = card_i430vx[0x62] = card_i430vx[0x63] = card_i430vx[0x64] = 0x02; + card_i430vx[0x67] = 0x11; + card_i430vx[0x69] = 0x03; + card_i430vx[0x70] = 0x20; + card_i430vx[0x72] = 0x02; + card_i430vx[0x74] = 0x0e; + card_i430vx[0x78] = 0x23; +} diff --git a/src/i430vx.h b/src/i430vx.h new file mode 100644 index 0000000..22bde47 --- /dev/null +++ b/src/i430vx.h @@ -0,0 +1 @@ +void i430vx_init(); diff --git a/src/piix.c b/src/piix.c new file mode 100644 index 0000000..45dfdb2 --- /dev/null +++ b/src/piix.c @@ -0,0 +1,303 @@ +/*PRD format : + + word 0 - base address + word 1 - bits 1 - 15 = byte count, bit 31 = end of transfer +*/ +#include + +#include "ibm.h" +#include "ide.h" +#include "io.h" +#include "pci.h" + +#include "piix.h" + +uint8_t piix_bus_master_read(uint16_t port, void *priv); +void piix_bus_master_write(uint16_t port, uint8_t val, void *priv); + +static uint8_t card_piix[256], card_piix_ide[256]; + +void piix_write(int func, int addr, uint8_t val, void *priv) +{ + if (func > 1) + return; + + if (func == 1) /*IDE*/ + { + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + case 0x20: + val |= 1; + break; + case 0x41: + if ((val ^ card_piix_ide[0x41]) & 0x80) + { + if (val & 0x80) + ide_pri_enable(); + else + ide_pri_disable(); + } + break; + case 0x43: + if ((val ^ card_piix_ide[0x43]) & 0x80) + { + if (val & 0x80) + ide_sec_enable(); + else + ide_sec_disable(); + } + break; + } + card_piix_ide[addr] = val; + if ((addr & ~3) == 0x20) /*Bus master base address*/ + { + uint16_t base = (card_piix_ide[0x20] & 0xf0) | (card_piix_ide[0x21] << 8); + io_removehandler(0, 0x10000, piix_bus_master_read, NULL, NULL, piix_bus_master_write, NULL, NULL, NULL); + io_sethandler(base, 0x10, piix_bus_master_read, NULL, NULL, piix_bus_master_write, NULL, NULL, NULL); + } +// pclog("PIIX write %02X %02X\n", addr, val); + } + else + { + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + } + card_piix[addr] = val; + } +} + +uint8_t piix_read(int func, int addr, void *priv) +{ + if (func > 1) + return 0xff; + + if (func == 1) /*IDE*/ + { +// pclog("PIIX IDE read %02X %02X\n", addr, card_piix_ide[addr]); + return card_piix_ide[addr]; + } + else + return card_piix[addr]; +} + +struct +{ + uint8_t command; + uint8_t status; + uint32_t ptr, ptr_cur; + int count; + uint32_t addr; + int eot; +} piix_busmaster[2]; + +static void piix_bus_master_next_addr(int channel) +{ + piix_busmaster[channel].addr = (*(unsigned long *)(&ram[piix_busmaster[channel].ptr_cur])) & ~1; + piix_busmaster[channel].count = (*(unsigned long *)(&ram[piix_busmaster[channel].ptr_cur + 4])) & 0xfffe; + piix_busmaster[channel].eot = (*(unsigned long *)(&ram[piix_busmaster[channel].ptr_cur + 4])) >> 31; + piix_busmaster[channel].ptr_cur += 8; +// pclog("New DMA settings on channel %i - Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); +} + +void piix_bus_master_write(uint16_t port, uint8_t val, void *priv) +{ + int channel = (port & 8) ? 1 : 0; +// pclog("PIIX Bus Master write %04X %02X\n", port, val); + switch (port & 7) + { + case 0: + if ((val & 1) && !(piix_busmaster[channel].command & 1)) /*Start*/ + { + piix_busmaster[channel].ptr_cur = piix_busmaster[channel].ptr; + piix_bus_master_next_addr(channel); + piix_busmaster[channel].status |= 1; + } + if (!(val & 1) && (piix_busmaster[channel].command & 1)) /*Stop*/ + piix_busmaster[channel].status &= ~1; + + piix_busmaster[channel].command = val; + break; + case 2: + piix_busmaster[channel].status = (val & 0x60) | ((piix_busmaster[channel].status & ~val) & 6) | (piix_busmaster[channel].status & 1); + break; + case 4: + piix_busmaster[channel].ptr = (piix_busmaster[channel].ptr & 0xffffff00) | val; + break; + case 5: + piix_busmaster[channel].ptr = (piix_busmaster[channel].ptr & 0xffff00ff) | (val << 8); + break; + case 6: + piix_busmaster[channel].ptr = (piix_busmaster[channel].ptr & 0xff00ffff) | (val << 16); + break; + case 7: + piix_busmaster[channel].ptr = (piix_busmaster[channel].ptr & 0x00ffffff) | (val << 24); + break; + } +} + +uint8_t piix_bus_master_read(uint16_t port, void *priv) +{ + int channel = (port & 8) ? 1 : 0; + switch (port & 7) + { + case 0: + return piix_busmaster[channel].command; + case 2: + return piix_busmaster[channel].status; + case 4: + return piix_busmaster[channel].ptr; + case 5: + return piix_busmaster[channel].ptr >> 8; + case 6: + return piix_busmaster[channel].ptr >> 16; + case 7: + return piix_busmaster[channel].ptr >> 24; + } + return 0xff; +} + +int piix_bus_master_sector_read(int channel, uint8_t *data) +{ + int transferred = 0; + + if (!(piix_busmaster[channel].status & 1)) + return 1; /*DMA disabled*/ + + while (transferred < 512) + { + if (piix_busmaster[channel].count < (512 - transferred) && piix_busmaster[channel].eot) + fatal("DMA on channel %i - Read count less than 512! Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); + + if (piix_busmaster[channel].count < (512 - transferred)) + { +// pclog("Transferring smaller - %i bytes\n", piix_busmaster[channel].count); + memcpy(&ram[piix_busmaster[channel].addr], data + transferred, piix_busmaster[channel].count); + transferred += piix_busmaster[channel].count; + piix_busmaster[channel].addr += piix_busmaster[channel].count; + piix_busmaster[channel].count = 0; + } + else + { +// pclog("Transferring larger - %i bytes\n", 512 - transferred); + memcpy(&ram[piix_busmaster[channel].addr], data + transferred, 512 - transferred); + piix_busmaster[channel].addr += (512 - transferred); + piix_busmaster[channel].count -= (512 - transferred); + transferred += (512 - transferred); + } + +// pclog("DMA on channel %i - Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); + + if (!piix_busmaster[channel].count) + { +// pclog("DMA on channel %i - block over\n", channel); + if (piix_busmaster[channel].eot) /*End of transfer?*/ + { +// pclog("DMA on channel %i - transfer over\n", channel); + piix_busmaster[channel].status &= ~1; + } + else + piix_bus_master_next_addr(channel); + } + } + return 0; +} +int piix_bus_master_sector_write(int channel, uint8_t *data) +{ + int transferred = 0; + + if (!(piix_busmaster[channel].status & 1)) + return 1; /*DMA disabled*/ + + while (transferred < 512) + { + if (piix_busmaster[channel].count < (512 - transferred) && piix_busmaster[channel].eot) + fatal("DMA on channel %i - Write count less than 512! Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); + + if (piix_busmaster[channel].count < (512 - transferred)) + { +// pclog("Transferring smaller - %i bytes\n", piix_busmaster[channel].count); + memcpy(data + transferred, &ram[piix_busmaster[channel].addr], piix_busmaster[channel].count); + transferred += piix_busmaster[channel].count; + piix_busmaster[channel].addr += piix_busmaster[channel].count; + piix_busmaster[channel].count = 0; + } + else + { +// pclog("Transferring larger - %i bytes\n", 512 - transferred); + memcpy(data + transferred, &ram[piix_busmaster[channel].addr], 512 - transferred); + piix_busmaster[channel].addr += (512 - transferred); + piix_busmaster[channel].count -= (512 - transferred); + transferred += (512 - transferred); + } + +// pclog("DMA on channel %i - Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); + + if (!piix_busmaster[channel].count) + { +// pclog("DMA on channel %i - block over\n", channel); + if (piix_busmaster[channel].eot) /*End of transfer?*/ + { +// pclog("DMA on channel %i - transfer over\n", channel); + piix_busmaster[channel].status &= ~1; + } + else + piix_bus_master_next_addr(channel); + } + } + return 0; +} + +void piix_bus_master_set_irq(int channel) +{ + piix_busmaster[channel].status |= 4; +} + +void piix_init(int card) +{ + pci_add_specific(card, piix_read, piix_write, NULL); + + memset(card_piix, 0, 256); + card_piix[0x00] = 0x86; card_piix[0x01] = 0x80; /*Intel*/ + card_piix[0x02] = 0x2e; card_piix[0x03] = 0x12; /*82371FB (PIIX)*/ + card_piix[0x04] = 0x07; card_piix[0x05] = 0x00; + card_piix[0x06] = 0x00; card_piix[0x07] = 0x02; + card_piix[0x08] = 0x00; /*A0 stepping*/ + card_piix[0x09] = 0x00; card_piix[0x0a] = 0x01; card_piix[0x0b] = 0x06; + card_piix[0x0e] = 0x80; /*Multi-function device*/ + card_piix[0x4c] = 0x4d; + card_piix[0x4e] = 0x03; + card_piix[0x60] = card_piix[0x61] = card_piix[0x62] = card_piix[0x63] = 0x80; + card_piix[0x69] = 0x02; + card_piix[0x70] = card_piix[0x71] = 0x80; + card_piix[0x76] = card_piix[0x77] = 0x0c; + card_piix[0x78] = 0x02; card_piix[0x79] = 0x00; + card_piix[0xa0] = 0x08; + card_piix[0xa2] = card_piix[0xa3] = 0x00; + card_piix[0xa4] = card_piix[0xa5] = card_piix[0xa6] = card_piix[0xa7] = 0x00; + card_piix[0xa8] = 0x0f; + card_piix[0xaa] = card_piix[0xab] = 0x00; + card_piix[0xac] = 0x00; + card_piix[0xae] = 0x00; + + card_piix_ide[0x00] = 0x86; card_piix_ide[0x01] = 0x80; /*Intel*/ + card_piix_ide[0x02] = 0x30; card_piix_ide[0x03] = 0x12; /*82371FB (PIIX)*/ + card_piix_ide[0x04] = 0x00; card_piix_ide[0x05] = 0x00; + card_piix_ide[0x06] = 0x80; card_piix_ide[0x07] = 0x02; + card_piix_ide[0x08] = 0x00; + card_piix_ide[0x09] = 0x80; card_piix_ide[0x0a] = 0x01; card_piix_ide[0x0b] = 0x01; + card_piix_ide[0x0d] = 0x00; + card_piix_ide[0x0e] = 0x00; + card_piix_ide[0x20] = 0x01; card_piix_ide[0x21] = card_piix_ide[0x22] = card_piix_ide[0x23] = 0x00; /*Bus master interface base address*/ + card_piix_ide[0x40] = card_piix_ide[0x41] = 0x00; + card_piix_ide[0x42] = card_piix_ide[0x43] = 0x00; + + ide_set_bus_master(piix_bus_master_sector_read, piix_bus_master_sector_write, piix_bus_master_set_irq); +} diff --git a/src/piix.h b/src/piix.h new file mode 100644 index 0000000..0e85a27 --- /dev/null +++ b/src/piix.h @@ -0,0 +1 @@ +void piix_init(int card); diff --git a/src/ppi.h b/src/ppi.h deleted file mode 100644 index 2bdff7c..0000000 --- a/src/ppi.h +++ /dev/null @@ -1 +0,0 @@ -extern int wasgated; diff --git a/src/psg.c b/src/psg.c deleted file mode 100644 index 2aa4ea0..0000000 --- a/src/psg.c +++ /dev/null @@ -1,206 +0,0 @@ -#include "ibm.h" - -float volslog[16]= -{ - 0.00000f,0.59715f,0.75180f,0.94650f, - 1.19145f,1.50000f,1.88835f,2.37735f, - 2.99295f,3.76785f,4.74345f,5.97165f, - 7.51785f,9.46440f,11.9194f,15.0000f -}; - -float psgcount[4],psglatch[4]; -int psgstat[4]; -int snlatch[4],sncount[4]; -int snfreqlo[4],snfreqhi[4]; -int snvol[4]; -int curfreq[4]; -uint32_t snshift[2]={0x8000,0x8000}; - -#define SNCLOCK (2386360>>5) -uint8_t snnoise; - -void initpsg() -{ - int c; - for (c=0;c<4;c++) - { - psgcount[c]=psglatch[c]=100000; - psgstat[c]=0; - } -} - -#define PSGCONST (32000.0/48000.0) - -void getpsg(signed short *p, int size) -{ -// printf("Getpsg %08X %i\n",p,size); -// return; - int c,d; - for (c=0;c1.0) - { - psgcount[d]+=psglatch[d]; - psgstat[d]^=1; - } - if (psgcount[d]<=0.0) psgcount[d]=1.0; - } - d=(snnoise&4)?0:1; - if (snshift[d]&1) p[c]+=volslog[snvol[0]]*170; - psgcount[0]-=(512*PSGCONST); - while (psgcount[0]<=0.0 && psglatch[0]>1.0) - { - psgcount[0]+=psglatch[0]; - snshift[1]>>=1; - if (!snshift[1]) snshift[1]=0x4000; - if ((snshift[0]&1)^((snshift[0]&4)?1:0)^((snshift[0]&0x8000)?1:0)) - snshift[0]|=0x10000; - snshift[0]>>=1; - } - if (psgcount[0]<=0.0) psgcount[0]=1.0; - } -} - -int lasttone; -uint8_t firstdat; -void writepsg(uint16_t addr, uint8_t data) -{ - int c; - int freq; - pclog("Write PSG %02X\n", data); - if (data&0x80) - { - firstdat=data; - switch (data&0x70) - { - case 0: - snfreqlo[3]=data&0xF; - lasttone=3; - break; - case 0x10: - data&=0xF; - snvol[3]=0xF-data; - break; - case 0x20: - snfreqlo[2]=data&0xF; - lasttone=2; - break; - case 0x30: - data&=0xF; - snvol[2]=0xF-data; - break; - case 0x40: - snfreqlo[1]=data&0xF; - lasttone=1; - break; - case 0x50: - data&=0xF; - snvol[1]=0xF-data; - break; - case 0x60: - if ((data&3)!=(snnoise&3)) sncount[0]=0; - snnoise=data&0xF; - if ((data&3)==3) - { - curfreq[0]=curfreq[1]>>4; - snlatch[0]=snlatch[1]; - } - else - { - switch (data&3) - { - case 0: - snlatch[0]=128<<7; - curfreq[0]=SNCLOCK/256; - snlatch[0]=0x400; - sncount[0]=0; - break; - case 1: - snlatch[0]=256<<7; - curfreq[0]=SNCLOCK/512; - snlatch[0]=0x800; - sncount[0]=0; - break; - case 2: - snlatch[0]=512<<7; - curfreq[0]=SNCLOCK/1024; - snlatch[0]=0x1000; - sncount[0]=0; - break; - case 3: - snlatch[0]=snlatch[1]; - sncount[0]=0; - } - if (snnoise&4) snlatch[0]<<=1; - } - break; - case 0x70: - data&=0xF; - snvol[0]=0xF-data; - break; - } - } - else - { - if ((firstdat&0x70)==0x60) - { - if ((data&3)!=(snnoise&3)) sncount[0]=0; - snnoise=data&0xF; - if ((data&3)==3) - { - curfreq[0]=curfreq[1]>>4; - snlatch[0]=snlatch[1]; -// printf("SN 0 latch %04X\n",snlatch[0]); - } - else - { - switch (data&3) - { - case 0: - snlatch[0]=128<<7; - curfreq[0]=SNCLOCK/256; - snlatch[0]=0x400; - sncount[0]=0; - break; - case 1: - snlatch[0]=256<<7; - curfreq[0]=SNCLOCK/512; - snlatch[0]=0x800; - sncount[0]=0; - break; - case 2: - snlatch[0]=512<<7; - curfreq[0]=SNCLOCK/1024; - snlatch[0]=0x1000; - sncount[0]=0; - break; - case 3: - snlatch[0]=snlatch[1]; -// printf("SN 0 latch %04X\n",snlatch[0]); - sncount[0]=0; - } - if (snnoise&4) snlatch[0]<<=1; - } - return; - } - else - { - snfreqhi[lasttone]=data&0x3F; - freq=snfreqlo[lasttone]|(snfreqhi[lasttone]<<4); - snlatch[lasttone]=freq<<6; - } - } - for (c=0;c<4;c++) psglatch[c]=(float)snlatch[c]; -} - -void psg_init() -{ - pclog("psg_init\n"); - io_sethandler(0x00C0, 0x0001, NULL, NULL, NULL, writepsg, NULL, NULL); -} diff --git a/src/psg.h b/src/psg.h deleted file mode 100644 index a4cf69d..0000000 --- a/src/psg.h +++ /dev/null @@ -1 +0,0 @@ -void psg_init(); diff --git a/src/sblaster.c b/src/sblaster.c deleted file mode 100644 index 25038ec..0000000 --- a/src/sblaster.c +++ /dev/null @@ -1,1104 +0,0 @@ -/*Jazz sample rates : - 386-33 - 12kHz - 486-33 - 20kHz - 486-50 - 32kHz - Pentium - 45kHz*/ - -#include -#include -#include "ibm.h" -#include "filters.h" -#include "io.h" - -static int sb_8_length, sb_8_format, sb_8_autoinit, sb_8_pause, sb_8_enable, sb_8_autolen, sb_8_output; -static int sb_16_length, sb_16_format, sb_16_autoinit, sb_16_pause, sb_16_enable, sb_16_autolen, sb_16_output; -static int sb_pausetime = -1; - -static uint8_t sb_read_data[256]; -static int sb_read_wp, sb_read_rp; -static int sb_speaker; - -static int sb_data_stat=-1; - -static int sb_irqnum = 7; - -static uint8_t sbe2; -static int sbe2count; - -static int sbe2dat[4][9] = { - { 0x01, -0x02, -0x04, 0x08, -0x10, 0x20, 0x40, -0x80, -106 }, - { -0x01, 0x02, -0x04, 0x08, 0x10, -0x20, 0x40, -0x80, 165 }, - { -0x01, 0x02, 0x04, -0x08, 0x10, -0x20, -0x40, 0x80, -151 }, - { 0x01, -0x02, 0x04, -0x08, -0x10, 0x20, -0x40, 0x80, 90 } -}; - -static uint8_t sb_data[8]; -static int sb_commands[256]= -{ - -1,-1,-1,-1, 1, 2,-1, 0, 1,-1,-1,-1,-1,-1, 2, 1, - 1,-1,-1,-1, 2,-1, 2, 2,-1,-1,-1,-1, 0,-1,-1, 0, - 0,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1,-1, 0,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - 1, 2, 2,-1,-1,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1, 2, 2, 2, 2,-1,-1,-1,-1,-1, 0,-1, 0, - 2, 2,-1,-1,-1,-1,-1,-1, 2, 2,-1,-1,-1,-1,-1,-1, - 0,-1,-1,-1,-1,-1,-1,-1, 0,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 0, 0,-1, 0, 0, 0, 0,-1, 0, 0, 0,-1,-1,-1,-1,-1, - 1, 0, 1, 0, 1,-1,-1, 0, 0,-1,-1,-1,-1,-1,-1,-1, - -1,-1, 0,-1,-1,-1,-1,-1,-1, 1, 2,-1,-1,-1,-1, 0 -}; - -char sb16_copyright[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992."; -uint16_t sb_dsp_versions[] = {0, 0, 0x105, 0x200, 0x201, 0x300, 0x302, 0x405}; - -/*These tables were 'borrowed' from DOSBox*/ - int8_t scaleMap4[64] = { - 0, 1, 2, 3, 4, 5, 6, 7, 0, -1, -2, -3, -4, -5, -6, -7, - 1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, -11, -13, -15, - 2, 6, 10, 14, 18, 22, 26, 30, -2, -6, -10, -14, -18, -22, -26, -30, - 4, 12, 20, 28, 36, 44, 52, 60, -4, -12, -20, -28, -36, -44, -52, -60 - }; - uint8_t adjustMap4[64] = { - 0, 0, 0, 0, 0, 16, 16, 16, - 0, 0, 0, 0, 0, 16, 16, 16, - 240, 0, 0, 0, 0, 16, 16, 16, - 240, 0, 0, 0, 0, 16, 16, 16, - 240, 0, 0, 0, 0, 16, 16, 16, - 240, 0, 0, 0, 0, 16, 16, 16, - 240, 0, 0, 0, 0, 0, 0, 0, - 240, 0, 0, 0, 0, 0, 0, 0 - }; - - int8_t scaleMap26[40] = { - 0, 1, 2, 3, 0, -1, -2, -3, - 1, 3, 5, 7, -1, -3, -5, -7, - 2, 6, 10, 14, -2, -6, -10, -14, - 4, 12, 20, 28, -4, -12, -20, -28, - 5, 15, 25, 35, -5, -15, -25, -35 - }; - uint8_t adjustMap26[40] = { - 0, 0, 0, 8, 0, 0, 0, 8, - 248, 0, 0, 8, 248, 0, 0, 8, - 248, 0, 0, 8, 248, 0, 0, 8, - 248, 0, 0, 8, 248, 0, 0, 8, - 248, 0, 0, 0, 248, 0, 0, 0 - }; - - int8_t scaleMap2[24] = { - 0, 1, 0, -1, 1, 3, -1, -3, - 2, 6, -2, -6, 4, 12, -4, -12, - 8, 24, -8, -24, 6, 48, -16, -48 - }; - uint8_t adjustMap2[24] = { - 0, 4, 0, 4, - 252, 4, 252, 4, 252, 4, 252, 4, - 252, 4, 252, 4, 252, 4, 252, 4, - 252, 0, 252, 0 - }; - - -int sb_freq; - -int sbtype=0; - -int writebusy=0; /*Needed for Amnesia*/ - -int16_t sbdatl=0,sbdatr=0; -int16_t sb16datl=0,sb16datr=0; - -int16_t sbdat; -uint8_t sbref; -int sbdacmode,sbdacpos,sbdat2; -int8_t sbstep; -int sbleftright=0; -int sbinput=0; -int sbreadstat,sbwritestat; -int sbreset; -uint8_t sbreaddat; -uint8_t sb_command,sbdata; -int sbcommandnext=1; -uint8_t sb_test; -int sb_timei,sb_timeo; -int sbcommandstat; -int sbhalted; -int adpcmstat=0; -int sbautolen; -int sbautoinit=0; -uint8_t sbcurcommand,sbdmacommand; -float SBCONST; -int sbstereo=0; - -int sbsamprate; -uint8_t sb_transfertype; -int sb_newtransfer; -int sb_dma16; -int sb_uart; -int sb_irq8,sb_irq16; -int sb_16_exit; - -uint8_t mixerindex; -uint8_t sb_mixer[256]; -uint8_t sb_asp_regs[256]; - - -int sb_att[]= -{ - 310,368,437,520,618,735,873,1038,1234,1467,1743,2072,2463,2927,3479, - 4134,4914,5840,6941,8250,9805,11653,13850,16461,19564,23252,27635,32845, - 39036,46395,55140,65535 -}; - -void sb_irq(int irq8) -{ -// pclog("IRQ %i %02X\n",irq8,pic.mask); - if (irq8) sb_irq8=1; - else sb_irq16=1; - picint(1 << sb_irqnum); -} -void sb_irqc(int irq8) -{ - if (irq8) sb_irq8=0; - else sb_irq16=0; - picintc(1 << sb_irqnum); -} - -void sb_mixer_set() -{ - if (sbtype==SB16) - { - mixer.master_l=sb_att[sb_mixer[0x30]>>3]; - mixer.master_r=sb_att[sb_mixer[0x31]>>3]; - mixer.voice_l =sb_att[sb_mixer[0x32]>>3]; - mixer.voice_r =sb_att[sb_mixer[0x33]>>3]; - mixer.fm_l =sb_att[sb_mixer[0x34]>>3]; - mixer.fm_r =sb_att[sb_mixer[0x35]>>3]; - mixer.bass_l =sb_mixer[0x46]>>4; - mixer.bass_r =sb_mixer[0x47]>>4; - mixer.treble_l=sb_mixer[0x44]>>4; - mixer.treble_r=sb_mixer[0x45]>>4; - mixer.filter=0; - pclog("%02X %02X %02X %02X %02X %02X\n",sb_mixer[0x30],sb_mixer[0x31],sb_mixer[0x32],sb_mixer[0x33],sb_mixer[0x34],sb_mixer[0x35]); - pclog("Mixer - %04X %04X %04X %04X %04X %04X\n",mixer.master_l,mixer.master_r,mixer.voice_l,mixer.voice_r,mixer.fm_l,mixer.fm_r); - } - else if (sbtype==SBPRO || sbtype==SBPRO2) - { - mixer.master_l=sb_att[(sb_mixer[0x22]>>4)|0x11]; - mixer.master_r=sb_att[(sb_mixer[0x22]&0xF)|0x11]; - mixer.voice_l =sb_att[(sb_mixer[0x04]>>4)|0x11]; - mixer.voice_r =sb_att[(sb_mixer[0x04]&0xF)|0x11]; - mixer.fm_l =sb_att[(sb_mixer[0x26]>>4)|0x11]; - mixer.fm_r =sb_att[(sb_mixer[0x26]&0xF)|0x11]; - mixer.filter =!(sb_mixer[0xE]&0x20); - mixer.bass_l =mixer.bass_r =8; - mixer.treble_l=mixer.treble_r=8; - pclog("%02X %02X %02X\n",sb_mixer[0x04],sb_mixer[0x22],sb_mixer[0x26]); - pclog("Mixer - %04X %04X %04X %04X %04X %04X\n",mixer.master_l,mixer.master_r,mixer.voice_l,mixer.voice_r,mixer.fm_l,mixer.fm_r); - } - else - { - mixer.master_l=mixer.master_r=65535; - mixer.voice_l =mixer.voice_r =65535; - mixer.fm_l =mixer.fm_r =65535; - mixer.bass_l =mixer.bass_r =8; - mixer.treble_l=mixer.treble_r=8; - mixer.filter=1; - } -} - -void sb_mixer_reset() -{ - pclog("Mixer reset\n"); - if (sbtype==SB16) - { - sb_mixer[0x30]=31<<3; - sb_mixer[0x31]=31<<3; - sb_mixer[0x32]=31<<3; - sb_mixer[0x33]=31<<3; - sb_mixer[0x34]=31<<3; - sb_mixer[0x35]=31<<3; - sb_mixer[0x44]=8<<4; - sb_mixer[0x45]=8<<4; - sb_mixer[0x46]=8<<4; - sb_mixer[0x47]=8<<4; - sb_mixer[0x22]=(sb_mixer[0x30]&0xF0)|(sb_mixer[0x31]>>4); - sb_mixer[0x04]=(sb_mixer[0x32]&0xF0)|(sb_mixer[0x33]>>4); - sb_mixer[0x26]=(sb_mixer[0x34]&0xF0)|(sb_mixer[0x35]>>4); - } - if (sbtype==SBPRO || sbtype==SBPRO2) - { - sb_mixer[0x22]=0xFF; - sb_mixer[0x04]=0xFF; - sb_mixer[0x26]=0xFF; - sb_mixer[0xE]=0; - } -} - -void sb_dsp_reset() -{ - sbenable = sb_enable_i = 0; - sb_command = 0; - - sb_uart = 0; - sb_8_length = sbautolen = 0xFFFF; - - sb_irqc(0); - sb_irqc(1); - sb_16_pause = 0; - sb_read_wp = sb_read_rp = 0; - sb_data_stat = -1; - sb_speaker = 0; - sb_pausetime = -1; - sbe2 = 0xAA; - sbe2count = 0; - - sbreset = 0; - sbenable = sb_enable_i = sb_count_i = 0; - sbhalted = 0; - sbdmacommand = 0; - sbstereo = 0; - - picintc(1 << sb_irqnum); -} - -void sb_reset() -{ - int c; - - sb_dsp_reset(); - sb_mixer_reset(); - sb_mixer_set(); - - if (sbtype==SB16) sb_commands[8]=1; - else sb_commands[8]=-1; - - for (c = 0; c < 256; c++) - sb_asp_regs[c] = 0; - sb_asp_regs[5] = 0x01; - sb_asp_regs[9] = 0xf8; -} - -void setsbclock(float clock) -{ - SBCONST=clock/1000000.0f; - printf("SBCONST %f %f\n",SBCONST,clock); - if (sb_timeo>255) sblatcho=(int)(SBCONST*(1000000.0f/(float)(sb_timeo-256))); - else sblatcho=SBCONST*(256-sb_timeo); - if (sb_timei>255) sblatchi=(int)(SBCONST*(1000000.0f/(float)(sb_timei-256))); - else sblatchi=SBCONST*(256-sb_timei); -} - -void outmidi(uint8_t v) -{ - printf("Write MIDI %02X\n",v); -} - -void setsbtype(int type) -{ - sbtype=type; - sbstereo=0; - sb_mixer_set(); - if (sbtype==SB16) sb_commands[8]=1; - else sb_commands[8]=-1; -} - - - - - - - -void sb_add_data(uint8_t v) -{ - sb_read_data[sb_read_wp++]=v; - sb_read_wp&=0xFF; -} - -#define ADPCM_4 1 -#define ADPCM_26 2 -#define ADPCM_2 3 - -void sb_start_dma(int dma8, int autoinit, uint8_t format, int len) -{ - if (dma8) - { - sb_8_length=len; - sb_8_format=format; - sb_8_autoinit=autoinit; - sb_8_pause=0; - sb_8_enable=1; - if (sb_16_enable && sb_16_output) sb_16_enable = 0; - sb_8_output=1; - sbenable=sb_8_enable; - sbleftright=0; - sbdacpos=0; -// pclog("Start 8-bit DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len); - } - else - { - sb_16_length=len; - sb_16_format=format; - sb_16_autoinit=autoinit; - sb_16_pause=0; - sb_16_enable=1; - if (sb_8_enable && sb_8_output) sb_8_enable = 0; - sb_16_output=1; - sbenable=sb_16_enable; -// pclog("Start 16-bit DMA addr %06X len %04X\n",dma16.ac[1]+(dma16.page[1]<<16),len); - } -} - -void sb_start_dma_i(int dma8, int autoinit, uint8_t format, int len) -{ - if (dma8) - { - sb_8_length=len; - sb_8_format=format; - sb_8_autoinit=autoinit; - sb_8_pause=0; - sb_8_enable=1; - if (sb_16_enable && !sb_16_output) sb_16_enable = 0; - sb_8_output=0; - sb_enable_i=sb_8_enable; -// pclog("Start 8-bit input DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len); - } - else - { - sb_16_length=len; - sb_16_format=format; - sb_16_autoinit=autoinit; - sb_16_pause=0; - sb_16_enable=1; - if (sb_8_enable && !sb_8_output) sb_8_enable = 0; - sb_16_output=0; - sb_enable_i=sb_16_enable; -// pclog("Start 16-bit input DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len); - } -} - -uint8_t sb_8_read_dma() -{ - return readdma1(); -} -void sb_8_write_dma(uint8_t val) -{ - writedma1(val); -} -uint16_t sb_16_read_dma() -{ - return readdma5(); -} -void sb_16_write_dma(uint16_t val) -{ - writedma5(val); -} - -void sb_exec_command() -{ - int temp,c; -// pclog("SB command %02X\n",sb_command); - switch (sb_command) - { - case 0x10: /*8-bit direct mode*/ - sbdat=sbdatl=sbdatr=(sb_data[0]^0x80)<<8; - break; - case 0x14: /*8-bit single cycle DMA output*/ - sb_start_dma(1,0,0,sb_data[0]+(sb_data[1]<<8)); - break; - case 0x17: /*2-bit ADPCM output with reference*/ - sbref=sb_8_read_dma(); - sbstep=0; -// pclog("Ref byte 2 %02X\n",sbref); - case 0x16: /*2-bit ADPCM output*/ - sb_start_dma(1,0,ADPCM_2,sb_data[0]+(sb_data[1]<<8)); - sbdat2=sb_8_read_dma(); - sb_8_length--; - break; - case 0x1C: /*8-bit autoinit DMA output*/ - if (sbtype>8); - sb_add_data(sb_dsp_versions[sbtype]&0xFF); - break; - case 0xE2: /*Stupid ID/protection*/ - for (c=0;c<8;c++) - if (sb_data[0]&(1<>4,pc,sb_command); - switch (a&0xF) - { - case 0: case 1: case 2: case 3: /*OPL or Gameblaster*/ - if (GAMEBLASTER && sbtype < SBPRO) - writecms(a, v); - else if (sbtype >= SBPRO) - adlib_write(a,v); - return; - case 4: mixerindex=v; return; - case 5: - sb_mixer[mixerindex]=v; -// pclog("Write mixer data %02X %02X\n",mixerindex,sb_mixer[mixerindex]); - if (sbtype==SB16) - { - switch (mixerindex) - { - case 0x22: - sb_mixer[0x30]=((sb_mixer[0x22]>>4)|0x11)<<3; - sb_mixer[0x31]=((sb_mixer[0x22]&0xF)|0x11)<<3; - break; - case 0x04: - sb_mixer[0x32]=((sb_mixer[0x04]>>4)|0x11)<<3; - sb_mixer[0x33]=((sb_mixer[0x04]&0xF)|0x11)<<3; - break; - case 0x26: - sb_mixer[0x34]=((sb_mixer[0x26]>>4)|0x11)<<3; - sb_mixer[0x35]=((sb_mixer[0x26]&0xF)|0x11)<<3; - break; - case 0x80: - if (v & 1) sb_irqnum = 2; - if (v & 2) sb_irqnum = 5; - if (v & 4) sb_irqnum = 7; - if (v & 8) sb_irqnum = 10; - break; - } - } -// if (!mixerindex) sb_mixer_reset(); - sb_mixer_set(); - return; - case 6: /*Reset*/ - if (!(v&1) && (sbreset&1)) - { - sb_dsp_reset(); - sb_add_data(0xAA); - } - sbreset=v; - return; - case 8: case 9: adlib_write(a,v); return; /*OPL*/ - case 0xC: /*Command/data write*/ - if (sb_uart) return; - if (sb_data_stat==-1) - { - sb_command=v; -// if (sb_commands[v]==-1) -// fatal("Bad SB command %02X\n",v); - sb_data_stat++; - } - else - sb_data[sb_data_stat++]=v; - if (sb_data_stat==sb_commands[sb_command] || sb_commands[sb_command]==-1) - { - sb_exec_command(); - sb_data_stat=-1; - } - break; - } -} - -uint8_t sb_read(uint16_t a) -{ - uint8_t temp; -// if (a==0x224) output=1; -// printf("Read soundblaster %04X %04X:%04X\n",a,cs,pc); - switch (a&0xF) - { - case 0: case 1: case 2: case 3: /*OPL or GameBlaster*/ - if (GAMEBLASTER && sbtype < SBPRO) - return readcms(a); - return adlib_read(a); - break; - case 5: - if (sbtype=SB16) - { - switch (sb_irqnum) - { - case 2: return 1; /*IRQ 7*/ - case 5: return 2; /*IRQ 7*/ - case 7: return 4; /*IRQ 7*/ - case 10: return 8; /*IRQ 7*/ - } - } - if (mixerindex==0x81 && sbtype>=SB16) return 0x22; /*DMA 1 and 5*/ - if (mixerindex==0x82 && sbtype>=SB16) return ((sb_irq8)?1:0)|((sb_irq16)?2:0); - return sb_mixer[mixerindex]; - case 8: case 9: return adlib_read(a); /*OPL*/ - case 0xA: /*Read data*/ - if (sb_uart) return; - sbreaddat=sb_read_data[sb_read_rp]; - if (sb_read_rp!=sb_read_wp) - { - sb_read_rp++; - sb_read_rp&=0xFF; - } -// pclog("SB read %02X\n",sbreaddat); - return sbreaddat; - case 0xC: /*Write data ready*/ - cycles-=100; - writebusy++; - if (writebusy&8) return 0xFF; - return 0x7F; - case 0xE: /*Read data ready*/ - picintc(1 << sb_irqnum); - sb_irq8=sb_irq16=0; - return (sb_read_rp==sb_read_wp)?0x7f:0xff; - case 0xF: /*16-bit ack*/ - sb_irq16=0; - if (!sb_irq8) picintc(1 << sb_irqnum); - return 0xff; - } - return 0; -} - -void sb_init() -{ - int c; - - sb_reset(); - - io_sethandler(0x0220, 0x0010, sb_read, NULL, NULL, sb_write, NULL, NULL); -} - - -int sbshift4[8]={-2,-1,0,0,1,1,1,1}; -void pollsb() -{ - int tempi,ref; -// pclog("PollSB %i %i %i %i\n",sb_8_enable,sb_8_pause,sb_pausetime,sb_8_output); - if (sb_8_enable && !sb_8_pause && sb_pausetime<0 && sb_8_output) - { -// pclog("Dopoll %i %02X %i\n", sb_8_length, sb_8_format, sblatcho); - switch (sb_8_format) - { - case 0x00: /*Mono unsigned*/ - sbdat=(sb_8_read_dma()^0x80)<<8; - if (sbtype>=SBPRO && sbtype=SBPRO && sbtype>4)+sbstep; - if (tempi<0) tempi=0; - if (tempi>63) tempi=63; - - ref = sbref + scaleMap4[tempi]; - if (ref > 0xff) sbref = 0xff; - else if (ref < 0x00) sbref = 0x00; - else sbref = ref; - - sbstep = (sbstep + adjustMap4[tempi]) & 0xff; - - sbdat=(sbref^0x80)<<8; - - sbdacpos++; - if (sbdacpos>=2) - { - sbdacpos=0; - sbdat2=sb_8_read_dma(); - sb_8_length--; - } - - if (sbtype>=SBPRO && sbtype>5)+sbstep; - else if (sbdacpos==1) tempi=((sbdat2>>2)&7)+sbstep; - else tempi=((sbdat2<<1)&7)+sbstep; - - if (tempi<0) tempi=0; - if (tempi>39) tempi=39; - - ref = sbref + scaleMap26[tempi]; - if (ref > 0xff) sbref = 0xff; - else if (ref < 0x00) sbref = 0x00; - else sbref = ref; - sbstep = (sbstep + adjustMap26[tempi]) & 0xff; - - sbdat=(sbref^0x80)<<8; - - sbdacpos++; - if (sbdacpos>=3) - { - sbdacpos=0; - sbdat2=readdma1(); - sb_8_length--; - } - - if (sbtype>=SBPRO && sbtype>((3-sbdacpos)*2))&3)+sbstep; - if (tempi<0) tempi=0; - if (tempi>23) tempi=23; - - ref = sbref + scaleMap2[tempi]; - if (ref > 0xff) sbref = 0xff; - else if (ref < 0x00) sbref = 0x00; - else sbref = ref; - sbstep = (sbstep + adjustMap2[tempi]) & 0xff; - - sbdat=(sbref^0x80)<<8; - - sbdacpos++; - if (sbdacpos>=4) - { - sbdacpos=0; - sbdat2=readdma1(); - } - - if (sbtype>=SBPRO && sbtype-1) - { - sb_pausetime--; - if (sb_pausetime<0) - { - sb_irq(1); - sbenable=sb_8_enable; - pclog("SB pause over\n"); - } - } -} - -void sb_poll_i() -{ -// pclog("PollSBi %i %i %i %i\n",sb_8_enable,sb_8_pause,sb_pausetime,sb_8_output); - if (sb_8_enable && !sb_8_pause && sb_pausetime<0 && !sb_8_output) - { - switch (sb_8_format) - { - case 0x00: /*Mono unsigned*/ - sb_8_write_dma(0x80); - sb_8_length--; - break; - case 0x10: /*Mono signed*/ - sb_8_write_dma(0x00); - sb_8_length--; - break; - case 0x20: /*Stereo unsigned*/ - sb_8_write_dma(0x80); - sb_8_write_dma(0x80); - sb_8_length-=2; - break; - case 0x30: /*Stereo signed*/ - sb_8_write_dma(0x00); - sb_8_write_dma(0x00); - sb_8_length-=2; - break; - -// default: -// fatal("Unrecognised SB 8-bit input format %02X\n",sb_8_format); - } - - if (sb_8_length<0) - { -// pclog("Input DMA over %i\n",sb_8_autoinit); - if (sb_8_autoinit) sb_8_length=sb_8_autolen; - else sb_8_enable=sbenable=0; - sb_irq(1); - } - } - if (sb_16_enable && !sb_16_pause && sb_pausetime<0 && !sb_16_output) - { - switch (sb_16_format) - { - case 0x00: /*Unsigned mono*/ - sb_16_write_dma(0x8000); - sb_16_length--; - break; - case 0x10: /*Signed mono*/ - sb_16_write_dma(0); - sb_16_length--; - break; - case 0x20: /*Unsigned stereo*/ - sb_16_write_dma(0x8000); - sb_16_write_dma(0x8000); - sb_16_length-=2; - break; - case 0x30: /*Signed stereo*/ - sb_16_write_dma(0); - sb_16_write_dma(0); - sb_16_length-=2; - break; - -// default: -// fatal("Unrecognised SB 16-bit input format %02X\n",sb_16_format); - } - - if (sb_16_length<0) - { -// pclog("16iDMA over %i\n",sb_16_autoinit); - if (sb_16_autoinit) sb_16_length=sb_16_autolen; - else sb_16_enable=sbenable=0; - sb_irq(0); - } - } -} - -int16_t sbbuffer[2][SOUNDBUFLEN+20]; -int sbbufferpos=0; -int _sampcnt=0; -int16_t sb_filtbuf[4]={0,0,0,0}; -void getsbsamp() -{ - int vocl=sbpmixer.vocl*sbpmixer.masl; - int vocr=sbpmixer.vocr*sbpmixer.masr; - int16_t sbdat[2]; - double t; - - vocl=256-vocl; - vocr=256-vocr; - if (!vocl) vocl=1; - if (!vocr) vocr=1; - if (sbbufferpos>=(SOUNDBUFLEN+20)) return; - - sbdat[0]=sbdatl; - sbdat[1]=sbdatr; - - if (mixer.filter) - { - /*3.2kHz output filter*/ - sbdat[0]=(int16_t)(sb_iir(0,(float)sbdat[0])/1.3); - sbdat[1]=(int16_t)(sb_iir(1,(float)sbdat[1])/1.3); - } - - sbbuffer[0][sbbufferpos]=sbdat[0]; - sbbuffer[1][sbbufferpos]=sbdat[1]; - sbbufferpos++; -} - -void addsb(int16_t *p) -{ - int c; - if (sbbufferpos>SOUNDBUFLEN) sbbufferpos=SOUNDBUFLEN; -// printf("Addsb - %i %04X\n",sbbufferpos,p[0]); - for (c=0;c>16); - p[(c<<1)+1]+=(((sbbuffer[1][c]/3)*mixer.voice_r)>>16); -// if (!c) pclog("V %04X %04X %04X\n",sbbuffer[0][c],p[c<<1],mixer.voice_l); - } - for (;c>16); - p[(c<<1)+1]+=(((sbbuffer[0][sbbufferpos-1]/3)*mixer.voice_l)>>16); - } - sbbufferpos=0; -} - diff --git a/src/sound_adlib.c b/src/sound_adlib.c new file mode 100644 index 0000000..cf383f1 --- /dev/null +++ b/src/sound_adlib.c @@ -0,0 +1,62 @@ +#include +#include "ibm.h" +#include "device.h" +#include "sound.h" + +#include "sound_adlib.h" +#include "sound_opl.h" + +typedef struct adlib_t +{ + opl_t opl; + int16_t buffer[SOUNDBUFLEN * 2]; + int pos; +} adlib_t; + +static void adlib_poll(void *p) +{ + adlib_t *adlib = (adlib_t *)p; + + if (adlib->pos >= SOUNDBUFLEN) return; + + opl2_poll(&adlib->opl, &adlib->buffer[adlib->pos * 2], &adlib->buffer[(adlib->pos * 2) + 1]); + adlib->pos++; +} + +static void adlib_get_buffer(int16_t *buffer, int len, void *p) +{ + adlib_t *adlib = (adlib_t *)p; + int c; + + for (c = 0; c < len * 2; c++) + buffer[c] += adlib->buffer[c]; + + adlib->pos = 0; +} + +void *adlib_init() +{ + adlib_t *adlib = malloc(sizeof(adlib_t)); + memset(adlib, 0, sizeof(adlib_t)); + + pclog("adlib_init\n"); + opl2_init(&adlib->opl); + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &adlib->opl); + sound_add_handler(adlib_poll, adlib_get_buffer, adlib); + return adlib; +} + +void adlib_close(void *p) +{ + adlib_t *adlib = (adlib_t *)p; + + free(adlib); +} + +device_t adlib_device = +{ + "AdLib", + adlib_init, + adlib_close, + NULL +}; diff --git a/src/sound_adlib.h b/src/sound_adlib.h new file mode 100644 index 0000000..dc0db0c --- /dev/null +++ b/src/sound_adlib.h @@ -0,0 +1 @@ +extern device_t adlib_device; diff --git a/src/sound_adlibgold.c b/src/sound_adlibgold.c new file mode 100644 index 0000000..17e646b --- /dev/null +++ b/src/sound_adlibgold.c @@ -0,0 +1,597 @@ +#include +#include +#include "ibm.h" +#include "device.h" + +#include "sound_opl.h" +#include "dma.h" +#include "io.h" +#include "pic.h" +#include "pit.h" +#include "timer.h" + +void adgold_timer_poll(); + +typedef struct adgold_t +{ + int adgold_irq_status; + + uint8_t adgold_eeprom[0x19]; + + uint8_t adgold_status; + int adgold_38x_state, adgold_38x_addr; + uint8_t adgold_38x_regs[0x19]; + + int adgold_mma_addr; + uint8_t adgold_mma_regs[2][0xe]; + + int adgold_mma_enable[2]; + uint8_t adgold_mma_fifo[2][256]; + int adgold_mma_fifo_start[2], adgold_mma_fifo_end[2]; + uint8_t adgold_mma_status; + + int16_t adgold_mma_out[2]; + int adgold_mma_intpos[2]; + + int adgold_mma_timer_count; + + struct + { + int timer0_latch, timer0_count; + int timerbase_latch, timerbase_count; + int timer1_latch, timer1_count; + int timer2_latch, timer2_count, timer2_read; + + int voice_count[2], voice_latch[2]; + } adgold_mma; + + opl_t opl; + + int16_t opl_buffer[SOUNDBUFLEN * 2]; + int16_t mma_buffer[2][SOUNDBUFLEN]; + + int pos; +} adgold_t; + +void adgold_update_irq_status(adgold_t *adgold) +{ + uint8_t temp = 0xf; + + if (!(adgold->adgold_mma_regs[0][8] & 0x10) && (adgold->adgold_mma_status & 0x10)) /*Timer 0*/ + temp &= ~2; + if (!(adgold->adgold_mma_regs[0][8] & 0x20) && (adgold->adgold_mma_status & 0x20)) /*Timer 1*/ + temp &= ~2; + if (!(adgold->adgold_mma_regs[0][8] & 0x40) && (adgold->adgold_mma_status & 0x40)) /*Timer 2*/ + temp &= ~2; + + if ((adgold->adgold_mma_status & 0x01) && !(adgold->adgold_mma_regs[0][0xc] & 2)) + temp &= ~2; + if ((adgold->adgold_mma_status & 0x02) && !(adgold->adgold_mma_regs[1][0xc] & 2)) + temp &= ~2; + adgold->adgold_status = temp; + + if ((adgold->adgold_status ^ 0xf) && !adgold->adgold_irq_status) + { + pclog("adgold irq %02X\n", adgold->adgold_status); + picint(0x80); + } + + adgold->adgold_irq_status = adgold->adgold_status ^ 0xf; +} + +void adgold_getsamp_dma(adgold_t *adgold, int channel) +{ + int temp; + + if ((adgold->adgold_mma_regs[channel][0xc] & 0x60) && (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) >= 127)) + return; + + temp = readdma1(); +// pclog("adgold DMA1 return %02X %i L\n", temp, channel); + if (temp == -1) return; + adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_end[channel]] = temp; + adgold->adgold_mma_fifo_end[channel] = (adgold->adgold_mma_fifo_end[channel] + 1) & 255; + if (adgold->adgold_mma_regs[channel][0xc] & 0x60) + { + temp = readdma1(); +// pclog("adgold DMA1 return %02X %i H\n", temp, channel); + adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_end[channel]] = temp; + adgold->adgold_mma_fifo_end[channel] = (adgold->adgold_mma_fifo_end[channel] + 1) & 255; + } + if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) >= adgold->adgold_mma_intpos[channel]) + { + adgold->adgold_mma_status &= ~(0x01 << channel); + adgold_update_irq_status(adgold); + } +} + +void adgold_write(uint16_t addr, uint8_t val, void *p) +{ + adgold_t *adgold = (adgold_t *)p; + if (addr > 0x389) pclog("adgold_write : addr %04X val %02X %04X:%04X\n", addr, val, CS, pc); + switch (addr & 7) + { + case 0: case 1: + opl3_write(addr, val, &adgold->opl); + break; + + case 2: + if (val == 0xff) + { + adgold->adgold_38x_state = 1; + return; + } + if (val == 0xfe) + { + adgold->adgold_38x_state = 0; + return; + } + if (adgold->adgold_38x_state) /*Write to control chip*/ + adgold->adgold_38x_addr = val; + else + opl3_write(addr, val, &adgold->opl); + break; + case 3: + if (adgold->adgold_38x_state) + { + if (adgold->adgold_38x_addr >= 0x19) break; + switch (adgold->adgold_38x_addr) + { + case 0x00: /*Control/ID*/ + if (val & 1) + memcpy(adgold->adgold_38x_regs, adgold->adgold_eeprom, 0x19); + if (val & 2) + memcpy(adgold->adgold_eeprom, adgold->adgold_38x_regs, 0x19); + break; + + default: + adgold->adgold_38x_regs[adgold->adgold_38x_addr] = val; + break; + } + } + else + opl3_write(addr, val, &adgold->opl); + break; + case 4: case 6: + adgold->adgold_mma_addr = val; + break; + case 5: + if (adgold->adgold_mma_addr >= 0xf) break; + switch (adgold->adgold_mma_addr) + { + case 0x2: + adgold->adgold_mma.timer0_latch = (adgold->adgold_mma.timer0_latch & 0xff00) | val; + break; + case 0x3: + adgold->adgold_mma.timer0_latch = (adgold->adgold_mma.timer0_latch & 0xff) | (val << 8); + break; + case 0x4: + adgold->adgold_mma.timerbase_latch = (adgold->adgold_mma.timerbase_latch & 0xf00) | val; + break; + case 0x5: + adgold->adgold_mma.timerbase_latch = (adgold->adgold_mma.timerbase_latch & 0xff) | ((val & 0xf) << 8); + adgold->adgold_mma.timer1_latch = val >> 4; + break; + case 0x6: + adgold->adgold_mma.timer2_latch = (adgold->adgold_mma.timer2_latch & 0xff00) | val; + break; + case 0x7: + adgold->adgold_mma.timer2_latch = (adgold->adgold_mma.timer2_latch & 0xff) | (val << 8); + break; + + case 0x8: + if ((val & 1) && !(adgold->adgold_mma_regs[0][8] & 1)) /*Reload timer 0*/ + adgold->adgold_mma.timer0_count = adgold->adgold_mma.timer0_latch; + + if ((val & 2) && !(adgold->adgold_mma_regs[0][8] & 2)) /*Reload timer 1*/ + adgold->adgold_mma.timer1_count = adgold->adgold_mma.timer1_latch; + + if ((val & 4) && !(adgold->adgold_mma_regs[0][8] & 4)) /*Reload timer 2*/ + adgold->adgold_mma.timer2_count = adgold->adgold_mma.timer2_latch; + + if ((val & 8) && !(adgold->adgold_mma_regs[0][8] & 8)) /*Reload base timer*/ + adgold->adgold_mma.timerbase_count = adgold->adgold_mma.timerbase_latch; + break; + + case 0x9: + switch (val & 0x18) + { + case 0x00: adgold->adgold_mma.voice_latch[0] = 12; break; /*44100 Hz*/ + case 0x08: adgold->adgold_mma.voice_latch[0] = 24; break; /*22050 Hz*/ + case 0x10: adgold->adgold_mma.voice_latch[0] = 48; break; /*11025 Hz*/ + case 0x18: adgold->adgold_mma.voice_latch[0] = 72; break; /* 7350 Hz*/ + } + if (val & 0x80) + { + adgold->adgold_mma_enable[0] = 0; + adgold->adgold_mma_fifo_end[0] = adgold->adgold_mma_fifo_start[0] = 0; + adgold->adgold_mma_status &= ~0x01; + adgold_update_irq_status(adgold); + } + if ((val & 0x01)) /*Start playback*/ + { + if (!(adgold->adgold_mma_regs[0][0x9] & 1)) + adgold->adgold_mma.voice_count[0] = adgold->adgold_mma.voice_latch[0]; + + pclog("adgold start! FIFO fill %i %i %i %02X\n", (adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255, adgold->adgold_mma_fifo_end[0], adgold->adgold_mma_fifo_start[0], adgold->adgold_mma_regs[0][0xc]); + if (adgold->adgold_mma_regs[0][0xc] & 1) + { + if (adgold->adgold_mma_regs[0][0xc] & 0x80) + { +// pclog("adgold start interleaved %i %i + adgold->adgold_mma_enable[1] = 1; + adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; + + while (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128) + { + adgold_getsamp_dma(adgold, 0); + adgold_getsamp_dma(adgold, 1); + } + if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0]) + { + adgold->adgold_mma_status &= ~0x01; + adgold_update_irq_status(adgold); + } + if (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) >= adgold->adgold_mma_intpos[1]) + { + adgold->adgold_mma_status &= ~0x02; + adgold_update_irq_status(adgold); + } + } + else + { + while (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128) + { + adgold_getsamp_dma(adgold, 0); + } + if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0]) + { + adgold->adgold_mma_status &= ~0x01; + adgold_update_irq_status(adgold); + } + } + } + pclog("adgold end\n"); + } + adgold->adgold_mma_enable[0] = val & 0x01; + break; + + case 0xb: + if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128) + { + adgold->adgold_mma_fifo[0][adgold->adgold_mma_fifo_end[0]] = val; + adgold->adgold_mma_fifo_end[0] = (adgold->adgold_mma_fifo_end[0] + 1) & 255; + if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0]) + { + adgold->adgold_mma_status &= ~0x01; + adgold_update_irq_status(adgold); + } + } + break; + + case 0xc: + adgold->adgold_mma_intpos[0] = (7 - ((val >> 2) & 7)) * 8; + break; + } + adgold->adgold_mma_regs[0][adgold->adgold_mma_addr] = val; + break; + case 7: + if (adgold->adgold_mma_addr >= 0xf) break; + switch (adgold->adgold_mma_addr) + { + case 0x9: + switch (val & 0x18) + { + case 0x00: adgold->adgold_mma.voice_latch[1] = 12; break; /*44100 Hz*/ + case 0x08: adgold->adgold_mma.voice_latch[1] = 24; break; /*22050 Hz*/ + case 0x10: adgold->adgold_mma.voice_latch[1] = 48; break; /*11025 Hz*/ + case 0x18: adgold->adgold_mma.voice_latch[1] = 72; break; /* 7350 Hz*/ + } + if (val & 0x80) + { + adgold->adgold_mma_enable[1] = 0; + adgold->adgold_mma_fifo_end[1] = adgold->adgold_mma_fifo_start[1] = 0; + adgold->adgold_mma_status &= ~0x02; + adgold_update_irq_status(adgold); + } + if ((val & 0x01)) /*Start playback*/ + { + if (!(adgold->adgold_mma_regs[1][0x9] & 1)) + adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; + + pclog("adgold start! FIFO fill %i %i %i %02X\n", (adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255, adgold->adgold_mma_fifo_end[1], adgold->adgold_mma_fifo_start[1], adgold->adgold_mma_regs[1][0xc]); + if (adgold->adgold_mma_regs[1][0xc] & 1) + { + while (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) < 128) + { + adgold_getsamp_dma(adgold, 1); + } + } + pclog("adgold end\n"); + } + adgold->adgold_mma_enable[1] = val & 0x01; + break; + + case 0xb: + if (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) < 128) + { + adgold->adgold_mma_fifo[1][adgold->adgold_mma_fifo_end[1]] = val; + adgold->adgold_mma_fifo_end[1] = (adgold->adgold_mma_fifo_end[1] + 1) & 255; + if (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) >= adgold->adgold_mma_intpos[1]) + { + adgold->adgold_mma_status &= ~0x02; + adgold_update_irq_status(adgold); + } + } + break; + + case 0xc: + adgold->adgold_mma_intpos[1] = (7 - ((val >> 2) & 7)) * 8; + break; + } + adgold->adgold_mma_regs[1][adgold->adgold_mma_addr] = val; + break; + } +} + +uint8_t adgold_read(uint16_t addr, void *p) +{ + adgold_t *adgold = (adgold_t *)p; + uint8_t temp; + + switch (addr & 7) + { + case 0: case 1: + temp = opl3_read(addr, &adgold->opl); + break; + + case 2: + if (adgold->adgold_38x_state) /*Read from control chip*/ + temp = adgold->adgold_status; + else + temp = opl3_read(addr, &adgold->opl); + break; + + case 3: + if (adgold->adgold_38x_state) + { + if (adgold->adgold_38x_addr >= 0x19) temp = 0xff; + switch (adgold->adgold_38x_addr) + { + case 0x00: /*Control/ID*/ + temp = 0x70; /*16-bit ISA, no telephone/surround/CD-ROM*/ + break; + + default: + temp = adgold->adgold_38x_regs[adgold->adgold_38x_addr]; + } + } + else + temp = opl3_read(addr, &adgold->opl); + break; + + case 4: case 6: + temp = adgold->adgold_mma_status; + adgold->adgold_mma_status = 0; /*JUKEGOLD expects timer status flags to auto-clear*/ + adgold_update_irq_status(adgold); + break; + case 5: + if (adgold->adgold_mma_addr >= 0xf) temp = 0xff; + switch (adgold->adgold_mma_addr) + { + case 6: /*Timer 2 low*/ + adgold->adgold_mma.timer2_read = adgold->adgold_mma.timer2_count; + temp = adgold->adgold_mma.timer2_read & 0xff; + break; + case 7: /*Timer 2 high*/ + temp = adgold->adgold_mma.timer2_read >> 8; + break; + + default: + temp = adgold->adgold_mma_regs[0][adgold->adgold_mma_addr]; + break; + } + break; + case 7: + if (adgold->adgold_mma_addr >= 0xf) temp = 0xff; + temp = adgold->adgold_mma_regs[1][adgold->adgold_mma_addr]; + break; + } + if (addr > 0x389) pclog("adgold_read : addr %04X %02X\n", addr, temp); + return temp; +} + +void adgold_mma_poll(adgold_t *adgold, int channel) +{ + int16_t dat; + + if (adgold->adgold_mma_fifo_start[channel] != adgold->adgold_mma_fifo_end[channel]) + { + switch (adgold->adgold_mma_regs[channel][0xc] & 0x60) + { + case 0x00: /*8-bit*/ + dat = adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_start[channel]] * 256; + adgold->adgold_mma_out[channel] = dat; + adgold->adgold_mma_fifo_start[channel] = (adgold->adgold_mma_fifo_start[channel] + 1) & 255; + break; + + case 0x40: /*12-bit sensible format*/ + if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) < 2) + return; + + dat = adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_start[channel]] & 0xf0; + adgold->adgold_mma_fifo_start[channel] = (adgold->adgold_mma_fifo_start[channel] + 1) & 255; + dat |= (adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_start[channel]] << 8); + adgold->adgold_mma_fifo_start[channel] = (adgold->adgold_mma_fifo_start[channel] + 1) & 255; + adgold->adgold_mma_out[channel] = dat; + break; + } + + if (adgold->adgold_mma_regs[channel][0xc] & 1) + { + adgold_getsamp_dma(adgold, channel); + } + if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) < adgold->adgold_mma_intpos[channel] && !(adgold->adgold_mma_status & 0x01)) + { +// pclog("adgold_mma_poll - IRQ! %i\n", channel); + adgold->adgold_mma_status |= 1 << channel; + adgold_update_irq_status(adgold); + } + } + if (adgold->adgold_mma_fifo_start[channel] == adgold->adgold_mma_fifo_end[channel]) + { + adgold->adgold_mma_enable[channel] = 0; + } +} + +void adgold_timer_poll(void *p) +{ + adgold_t *adgold = (adgold_t *)p; + + while (adgold->adgold_mma_timer_count <= 0) + { + adgold->adgold_mma_timer_count += (int)((double)TIMER_USEC * 1.88964); + if (adgold->adgold_mma_regs[0][8] & 0x01) /*Timer 0*/ + { + adgold->adgold_mma.timer0_count--; + if (!adgold->adgold_mma.timer0_count) + { + adgold->adgold_mma.timer0_count = adgold->adgold_mma.timer0_latch; + pclog("Timer 0 interrupt\n"); + adgold->adgold_mma_status |= 0x10; + adgold_update_irq_status(adgold); + } + } + if (adgold->adgold_mma_regs[0][8] & 0x08) /*Base timer*/ + { + adgold->adgold_mma.timerbase_count--; + if (!adgold->adgold_mma.timerbase_count) + { + adgold->adgold_mma.timerbase_count = adgold->adgold_mma.timerbase_latch; + if (adgold->adgold_mma_regs[0][8] & 0x02) /*Timer 1*/ + { + adgold->adgold_mma.timer1_count--; + if (!adgold->adgold_mma.timer1_count) + { + adgold->adgold_mma.timer1_count = adgold->adgold_mma.timer1_latch; + pclog("Timer 1 interrupt\n"); + adgold->adgold_mma_status |= 0x20; + adgold_update_irq_status(adgold); + } + } + if (adgold->adgold_mma_regs[0][8] & 0x04) /*Timer 2*/ + { + adgold->adgold_mma.timer2_count--; + if (!adgold->adgold_mma.timer2_count) + { + adgold->adgold_mma.timer2_count = adgold->adgold_mma.timer2_latch; + pclog("Timer 2 interrupt\n"); + adgold->adgold_mma_status |= 0x40; + adgold_update_irq_status(adgold); + } + } + } + } + + if (adgold->adgold_mma_enable[0]) + { + adgold->adgold_mma.voice_count[0]--; + if (!adgold->adgold_mma.voice_count[0]) + { + adgold->adgold_mma.voice_count[0] = adgold->adgold_mma.voice_latch[0]; + adgold_mma_poll(adgold, 0); + } + } + if (adgold->adgold_mma_enable[1]) + { + adgold->adgold_mma.voice_count[1]--; + if (!adgold->adgold_mma.voice_count[1]) + { + adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; + adgold_mma_poll(adgold, 1); + } + } + } +} + +void adgold_poll(void *p) +{ + adgold_t *adgold = (adgold_t *)p; + + if (adgold->pos >= SOUNDBUFLEN) + return; + + opl3_poll(&adgold->opl, &adgold->opl_buffer[adgold->pos * 2], &adgold->opl_buffer[(adgold->pos * 2) + 1]); + adgold->mma_buffer[0][adgold->pos] = adgold->mma_buffer[1][adgold->pos] = 0; + + if (adgold->adgold_mma_regs[0][9] & 0x20) + adgold->mma_buffer[0][adgold->pos] += adgold->adgold_mma_out[0] / 2; + if (adgold->adgold_mma_regs[0][9] & 0x40) + adgold->mma_buffer[1][adgold->pos] += adgold->adgold_mma_out[0] / 2; + + if (adgold->adgold_mma_regs[1][9] & 0x20) + adgold->mma_buffer[0][adgold->pos] += adgold->adgold_mma_out[1] / 2; + if (adgold->adgold_mma_regs[1][9] & 0x40) + adgold->mma_buffer[1][adgold->pos] += adgold->adgold_mma_out[1] / 2; + + adgold->pos++; +} + +static void adgold_get_buffer(int16_t *buffer, int len, void *p) +{ + adgold_t *adgold = (adgold_t *)p; + + int c; + + for (c = 0; c < len * 2; c++) + { + buffer[c] += adgold->opl_buffer[c]; + buffer[c] += adgold->mma_buffer[c & 1][c >> 1] / 2; + } + + adgold->pos = 0; +} + + +void *adgold_init() +{ + adgold_t *adgold = malloc(sizeof(adgold_t)); + memset(adgold, 0, sizeof(adgold_t)); + + opl3_init(&adgold->opl); + + adgold->adgold_status = 0xf; + adgold->adgold_38x_addr = 0; + adgold->adgold_eeprom[0x09] = adgold->adgold_eeprom[0x0a] = 255; + adgold->adgold_eeprom[0x13] = 3 | (1 << 4); /*IRQ 7, DMA 1*/ + adgold->adgold_eeprom[0x14] = 3 << 4; /*DMA 3*/ + adgold->adgold_eeprom[0x15] = 0x388 / 8; /*Present at 388-38f*/ + memcpy(adgold->adgold_38x_regs, adgold->adgold_eeprom, 0x19); + + adgold->adgold_mma_enable[0] = 0; + adgold->adgold_mma_fifo_start[0] = adgold->adgold_mma_fifo_end[0] = 0; + + /*388/389 are handled by adlib_init*/ + io_sethandler(0x0388, 0x0008, adgold_read, NULL, NULL, adgold_write, NULL, NULL, adgold); + + timer_add(adgold_timer_poll, &adgold->adgold_mma_timer_count, TIMER_ALWAYS_ENABLED, adgold); + + sound_add_handler(adgold_poll, adgold_get_buffer, adgold); + + return adgold; +} + +void adgold_close(void *p) +{ + adgold_t *adgold = (adgold_t *)p; + + free(adgold); +} + +device_t adgold_device = +{ + "AdLib Gold", + adgold_init, + adgold_close, + NULL +}; diff --git a/src/sound_adlibgold.h b/src/sound_adlibgold.h new file mode 100644 index 0000000..e37d292 --- /dev/null +++ b/src/sound_adlibgold.h @@ -0,0 +1 @@ +extern device_t adgold_device; diff --git a/src/sound_cms.c b/src/sound_cms.c new file mode 100644 index 0000000..59a0a30 --- /dev/null +++ b/src/sound_cms.c @@ -0,0 +1,179 @@ +#include +#include +#include "ibm.h" + +#include "device.h" +#include "io.h" +#include "sound.h" +#include "sound_cms.h" + +typedef struct cms_t +{ + int addrs[2]; + uint8_t regs[2][32]; + uint16_t latch[2][6]; + int freq[2][6]; + float count[2][6]; + int vol[2][6][2]; + int stat[2][6]; + uint16_t noise[2][2]; + uint16_t noisefreq[2][2]; + int noisecount[2][2]; + int noisetype[2][2]; + + int16_t buffer[SOUNDBUFLEN * 2]; + + int pos; +} cms_t; + +void cms_poll(void *p) +{ + cms_t *cms = (cms_t *)p; + int c, d; + int16_t out_l = 0, out_r = 0; + + if (cms->pos >= SOUNDBUFLEN) + return; + + for (c = 0; c < 4; c++) + { + switch (cms->noisetype[c >> 1][c & 1]) + { + case 0: cms->noisefreq[c >> 1][c & 1] = 31250; break; + case 1: cms->noisefreq[c >> 1][c & 1] = 15625; break; + case 2: cms->noisefreq[c >> 1][c & 1] = 7812; break; + case 3: cms->noisefreq[c >> 1][c & 1] = cms->freq[c >> 1][(c & 1) * 3]; break; + } + } + for (c = 0; c < 2; c ++) + { + if (cms->regs[c][0x1C] & 1) + { + for (d = 0; d < 6; d++) + { + if (cms->regs[c][0x14] & (1 << d)) + { + if (cms->stat[c][d]) out_l += (cms->vol[c][d][0] * 90); + if (cms->stat[c][d]) out_r += (cms->vol[c][d][1] * 90); + cms->count[c][d] += cms->freq[c][d]; + if (cms->count[c][d] >= 24000) + { + cms->count[c][d] -= 24000; + cms->stat[c][d] ^= 1; + } + } + else if (cms->regs[c][0x15] & (1 << d)) + { + if (cms->noise[c][d / 3] & 1) out_l += (cms->vol[c][d][0] * 90); + if (cms->noise[c][d / 3] & 1) out_r += (cms->vol[c][d][0] * 90); + } + } + for (d = 0; d < 2; d++) + { + cms->noisecount[c][d] += cms->noisefreq[c][d]; + while (cms->noisecount[c][d] >= 24000) + { + cms->noisecount[c][d] -= 24000; + cms->noise[c][d] <<= 1; + if (!(((cms->noise[c][d] & 0x4000) >> 8) ^ (cms->noise[c][d] & 0x40))) + cms->noise[c][d] |= 1; + } + } + } + } + cms->buffer[(cms->pos << 1)] = out_l; + cms->buffer[(cms->pos << 1) + 1] = out_r; + + cms->pos++; +} + +void cms_get_buffer(int16_t *buffer, int len, void *p) +{ + cms_t *cms = (cms_t *)p; + + int c; + + for (c = 0; c < len * 2; c++) + buffer[c] += cms->buffer[c]; + + cms->pos = 0; +} + +void cms_write(uint16_t addr, uint8_t val, void *p) +{ + cms_t *cms = (cms_t *)p; + int voice; + int chip = (addr & 2) >> 1; + + pclog("cms_write : addr %04X val %02X\n", addr, val); + + if (addr & 1) + cms->addrs[chip] = val & 31; + else + { + cms->regs[chip][cms->addrs[chip] & 31] = val; + switch (cms->addrs[chip] & 31) + { + case 0x00: case 0x01: case 0x02: /*Volume*/ + case 0x03: case 0x04: case 0x05: + voice = cms->addrs[chip] & 7; + cms->vol[chip][voice][0] = val & 0xf; + cms->vol[chip][voice][1] = val >> 4; + break; + case 0x08: case 0x09: case 0x0A: /*Frequency*/ + case 0x0B: case 0x0C: case 0x0D: + voice = cms->addrs[chip] & 7; + cms->latch[chip][voice] = (cms->latch[chip][voice] & 0x700) | val; + cms->freq[chip][voice] = (15625 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255)); + break; + case 0x10: case 0x11: case 0x12: /*Octave*/ + voice = (cms->addrs[chip] & 3) << 1; + cms->latch[chip][voice] = (cms->latch[chip][voice] & 0xFF) | ((val & 7) << 8); + cms->latch[chip][voice + 1] = (cms->latch[chip][voice + 1] & 0xFF) | ((val & 0x70) << 4); + cms->freq[chip][voice] = (15625 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255)); + cms->freq[chip][voice + 1] = (15625 << (cms->latch[chip][voice + 1] >> 8)) / (511 - (cms->latch[chip][voice + 1] & 255)); + break; + case 0x16: /*Noise*/ + cms->noisetype[chip][0] = val & 3; + cms->noisetype[chip][1] = (val >> 4) & 3; + break; + } + } +} + +uint8_t cms_read(uint16_t addr, void *p) +{ + cms_t *cms = (cms_t *)p; + int chip = (addr & 2) >> 1; + + if (addr & 1) + return cms->addrs[chip]; + + return cms->regs[chip][cms->addrs[chip] & 31]; +} + +void *cms_init() +{ + cms_t *cms = malloc(sizeof(cms_t)); + memset(cms, 0, sizeof(cms_t)); + + pclog("cms_init\n"); + io_sethandler(0x0220, 0x0004, cms_read, NULL, NULL, cms_write, NULL, NULL, cms); + sound_add_handler(cms_poll, cms_get_buffer, cms); + return cms; +} + +void cms_close(void *p) +{ + cms_t *cms = (cms_t *)p; + + free(cms); +} + +device_t cms_device = +{ + "Creative Music System / Game Blaster", + cms_init, + cms_close, + NULL +}; diff --git a/src/sound_cms.h b/src/sound_cms.h new file mode 100644 index 0000000..582afae --- /dev/null +++ b/src/sound_cms.h @@ -0,0 +1 @@ +extern device_t cms_device; diff --git a/src/sound_gus.c b/src/sound_gus.c new file mode 100644 index 0000000..b27f6c6 --- /dev/null +++ b/src/sound_gus.c @@ -0,0 +1,1107 @@ +#include +#include +#include +#include "ibm.h" + +#include "device.h" +#include "dma.h" +#include "io.h" +#include "pic.h" +#include "sound.h" +#include "sound_gus.h" +#include "timer.h" + +typedef struct gus_t +{ + int reset; + + int global; + uint32_t addr,dmaaddr; + int voice; + uint32_t start[32],end[32],cur[32]; + uint32_t startx[32],endx[32],curx[32]; + int rstart[32],rend[32]; + int rcur[32]; + uint16_t freq[32]; + uint16_t rfreq[32]; + uint8_t ctrl[32]; + uint8_t rctrl[32]; + int curvol[32]; + int t1on,t2on; + uint8_t tctrl; + uint16_t t1,t2,t1l,t2l; + uint8_t irqstatus,irqstatus2; + uint8_t adcommand; + int waveirqs[32],rampirqs[32]; + int voices; + uint8_t dmactrl; + + int16_t out_l, out_r; + + int16_t buffer[2][SOUNDBUFLEN]; + int pos; + + int samp_timer, samp_latch; + + uint8_t *ram; + + int irqnext; + + int timer_1, timer_2; + + int irq, dma, irq_midi; + int latch_enable; + + uint8_t sb_2xa, sb_2xc, sb_2xe; + uint8_t sb_ctrl; + int sb_nmi; + + uint8_t reg_ctrl; + + uint8_t ad_status, ad_data; + uint8_t ad_timer_ctrl; + + uint8_t midi_ctrl, midi_status; + uint8_t midi_data; + int midi_loopback; + + uint8_t gp1, gp2; + uint16_t gp1_addr, gp2_addr; + + uint8_t usrr; +} gus_t; + +static int gus_irqs[8] = {-1, 2, 5, 3, 7, 11, 12, 15}; +static int gus_irqs_midi[8] = {-1, 2, 5, 3, 7, 11, 12, 15}; +static int gus_dmas[8] = {-1, 1, 3, 5, 6, 7, -1, -1}; + +int gusfreqs[]= +{ + 44100,41160,38587,36317,34300,32494,30870,29400,28063,26843,25725,24696, + 23746,22866,22050,21289,20580,19916,19293 +}; + +double vol16bit[4096]; + +void pollgusirqs(gus_t *gus) +{ + int c; + + gus->irqstatus&=~0x60; + for (c=0;c<32;c++) + { + if (gus->waveirqs[c]) + { +// gus->waveirqs[c]=0; + gus->irqstatus2=0x60|c; + if (gus->rampirqs[c]) gus->irqstatus2 |= 0x80; + gus->irqstatus|=0x20; +// printf("Voice IRQ %i %02X %i\n",c,gus->irqstatus2,ins); + if (gus->irq != -1) + picint(1 << gus->irq); + return; + } + if (gus->rampirqs[c]) + { +// gus->rampirqs[c]=0; + gus->irqstatus2=0xA0|c; + gus->irqstatus|=0x40; +// printf("Ramp IRQ %i %02X %i\n",c,gus->irqstatus2,ins); + if (gus->irq != -1) + picint(1 << gus->irq); + return; + } + } + gus->irqstatus2=0xE0; +// gus->irqstatus&=~0x20; + if (!gus->irqstatus && gus->irq != -1) picintc(1 << gus->irq); +} + +enum +{ + MIDI_INT_RECEIVE = 0x01, + MIDI_INT_TRANSMIT = 0x02, + MIDI_INT_MASTER = 0x80 +}; + +enum +{ + MIDI_CTRL_TRANSMIT_MASK = 0x60, + MIDI_CTRL_TRANSMIT = 0x20, + MIDI_CTRL_RECEIVE = 0x80 +}; + +enum +{ + GUS_INT_MIDI_TRANSMIT = 0x01, + GUS_INT_MIDI_RECEIVE = 0x02 +}; + +enum +{ + GUS_TIMER_CTRL_AUTO = 0x01 +}; + +void gus_midi_update_int_status(gus_t *gus) +{ + gus->midi_status &= ~MIDI_INT_MASTER; + if ((gus->midi_ctrl & MIDI_CTRL_TRANSMIT_MASK) == MIDI_CTRL_TRANSMIT && (gus->midi_status & MIDI_INT_TRANSMIT)) + { + gus->midi_status |= MIDI_INT_MASTER; + gus->irqstatus |= GUS_INT_MIDI_TRANSMIT; + } + else + gus->irqstatus &= ~GUS_INT_MIDI_TRANSMIT; + + if ((gus->midi_ctrl & MIDI_CTRL_RECEIVE) && (gus->midi_status & MIDI_INT_RECEIVE)) + { + gus->midi_status |= MIDI_INT_MASTER; + gus->irqstatus |= GUS_INT_MIDI_RECEIVE; + } + else + gus->irqstatus &= ~GUS_INT_MIDI_RECEIVE; + + if ((gus->midi_status & MIDI_INT_MASTER) && (gus->irq_midi != -1)) + { +// pclog("Take MIDI IRQ\n"); + picint(1 << gus->irq_midi); + } +} + +void writegus(uint16_t addr, uint8_t val, void *p) +{ + gus_t *gus = (gus_t *)p; + int c, d; + int old; +// pclog("Write GUS %04X %02X %04X:%04X\n",addr,val,CS,pc); + if (gus->latch_enable && addr != 0x24b) + gus->latch_enable = 0; + switch (addr) + { + case 0x340: /*MIDI control*/ + old = gus->midi_ctrl; + gus->midi_ctrl = val; + + if ((val & 3) == 3) + gus->midi_status = 0; + else if ((old & 3) == 3) + { + gus->midi_status |= MIDI_INT_TRANSMIT; +// pclog("MIDI_INT_TRANSMIT\n"); + } + gus_midi_update_int_status(gus); + break; + + case 0x341: /*MIDI data*/ + if (gus->midi_loopback) + { + gus->midi_status |= MIDI_INT_RECEIVE; + gus->midi_data = val; + } + else + gus->midi_status |= MIDI_INT_TRANSMIT; + break; + + case 0x342: /*Voice select*/ + gus->voice=val&31; + break; + case 0x343: /*Global select*/ + gus->global=val; + break; + case 0x344: /*Global low*/ +// if (gus->global!=0x43 && gus->global!=0x44) printf("Writing register %02X %02X %02X %i\n",gus->global,gus->voice,val, ins); + switch (gus->global) + { + case 0: /*Voice control*/ +// if (val&1 && !(gus->ctrl[gus->voice]&1)) printf("Voice on %i\n",gus->voice); + gus->ctrl[gus->voice]=val; + break; + case 1: /*Frequency control*/ + gus->freq[gus->voice]=(gus->freq[gus->voice]&0xFF00)|val; + break; + case 2: /*Start addr high*/ + gus->startx[gus->voice]=(gus->startx[gus->voice]&0xF807F)|(val<<7); + gus->start[gus->voice]=(gus->start[gus->voice]&0x1F00FFFF)|(val<<16); +// printf("Write %i start %08X %08X\n",gus->voice,gus->start[gus->voice],gus->startx[gus->voice]); + break; + case 3: /*Start addr low*/ + gus->start[gus->voice]=(gus->start[gus->voice]&0x1FFFFF00)|val; +// printf("Write %i start %08X %08X\n",gus->voice,gus->start[gus->voice],gus->startx[gus->voice]); + break; + case 4: /*End addr high*/ + gus->endx[gus->voice]=(gus->endx[gus->voice]&0xF807F)|(val<<7); + gus->end[gus->voice]=(gus->end[gus->voice]&0x1F00FFFF)|(val<<16); +// printf("Write %i end %08X %08X\n",gus->voice,gus->end[gus->voice],gus->endx[gus->voice]); + break; + case 5: /*End addr low*/ + gus->end[gus->voice]=(gus->end[gus->voice]&0x1FFFFF00)|val; +// printf("Write %i end %08X %08X\n",gus->voice,gus->end[gus->voice],gus->endx[gus->voice]); + break; + + case 0x6: /*Ramp frequency*/ + gus->rfreq[gus->voice] = (int)( (double)((val & 63)*512)/(double)(1 << (3*(val >> 6)))); +// printf("RFREQ %02X %i %i %f\n",val,gus->voice,gus->rfreq[gus->voice],(double)(val & 63)/(double)(1 << (3*(val >> 6)))); + break; + + case 0x9: /*Current volume*/ + gus->curvol[gus->voice] = gus->rcur[gus->voice] = (gus->rcur[gus->voice] & ~(0xff << 6)) | (val << 6); +// printf("Vol %i is %04X\n",gus->voice,gus->curvol[gus->voice]); + break; + + case 0xA: /*Current addr high*/ + gus->cur[gus->voice]=(gus->cur[gus->voice]&0x1F00FFFF)|(val<<16); +gus->curx[gus->voice]=(gus->curx[gus->voice]&0xF807F00)|((val<<7)<<8); +// gus->cur[gus->voice]=(gus->cur[gus->voice]&0x0F807F00)|((val<<7)<<8); +// printf("Write %i cur %08X\n",gus->voice,gus->cur[gus->voice],gus->curx[gus->voice]); + break; + case 0xB: /*Current addr low*/ + gus->cur[gus->voice]=(gus->cur[gus->voice]&0x1FFFFF00)|val; +// printf("Write %i cur %08X\n",gus->voice,gus->cur[gus->voice],gus->curx[gus->voice]); + break; + + case 0x42: /*DMA address low*/ + gus->dmaaddr=(gus->dmaaddr&0xFF000)|(val<<4); + break; + + case 0x43: /*Address low*/ + gus->addr=(gus->addr&0xFFF00)|val; + break; + case 0x45: /*Timer control*/ +// printf("Timer control %02X\n",val); + gus->tctrl=val; + break; + } + break; + case 0x345: /*Global high*/ +// if (gus->global!=0x43 && gus->global!=0x44) printf("HWriting register %02X %02X %02X %04X:%04X %i %X\n",gus->global,gus->voice,val,CS,pc, ins, gus->rcur[1] >> 10); + switch (gus->global) + { + case 0: /*Voice control*/ + if (!(val&1) && gus->ctrl[gus->voice]&1) + { +// printf("Voice on %i - start %05X end %05X freq %04X\n",gus->voice,gus->start[gus->voice],gus->end[gus->voice],gus->freq[gus->voice]); +// if (val&0x40) gus->cur[gus->voice]=gus->end[gus->voice]<<8; +// else gus->cur[gus->voice]=gus->start[gus->voice]<<8; + } + + gus->ctrl[gus->voice] = val & 0x7f; + + old = gus->waveirqs[gus->voice]; + gus->waveirqs[gus->voice] = ((val & 0xa0) == 0xa0) ? 1 : 0; + if (gus->waveirqs[gus->voice] != old) + pollgusirqs(gus); + break; + case 1: /*Frequency control*/ + gus->freq[gus->voice]=(gus->freq[gus->voice]&0xFF)|(val<<8); + break; + case 2: /*Start addr high*/ + gus->startx[gus->voice]=(gus->startx[gus->voice]&0x07FFF)|(val<<15); + gus->start[gus->voice]=(gus->start[gus->voice]&0x00FFFFFF)|((val&0x1F)<<24); +// printf("Write %i start %08X %08X %02X\n",gus->voice,gus->start[gus->voice],gus->startx[gus->voice],val); + break; + case 3: /*Start addr low*/ + gus->startx[gus->voice]=(gus->startx[gus->voice]&0xFFF80)|(val&0x7F); + gus->start[gus->voice]=(gus->start[gus->voice]&0x1FFF00FF)|(val<<8); +// printf("Write %i start %08X %08X\n",gus->voice,gus->start[gus->voice],gus->startx[gus->voice]); + break; + case 4: /*End addr high*/ + gus->endx[gus->voice]=(gus->endx[gus->voice]&0x07FFF)|(val<<15); + gus->end[gus->voice]=(gus->end[gus->voice]&0x00FFFFFF)|((val&0x1F)<<24); +// printf("Write %i end %08X %08X %02X\n",gus->voice,gus->end[gus->voice],gus->endx[gus->voice],val); + break; + case 5: /*End addr low*/ + gus->endx[gus->voice]=(gus->endx[gus->voice]&0xFFF80)|(val&0x7F); + gus->end[gus->voice]=(gus->end[gus->voice]&0x1FFF00FF)|(val<<8); +// printf("Write %i end %08X %08X\n",gus->voice,gus->end[gus->voice],gus->endx[gus->voice]); + break; + + case 0x6: /*Ramp frequency*/ + gus->rfreq[gus->voice] = (int)( (double)((val & 63) * (1 << 10))/(double)(1 << (3 * (val >> 6)))); +// pclog("Ramp freq %02X %i %i %f %i\n", val, gus->voice, gus->rfreq[gus->voice], (double)(val & 63)/(double)(1 << (3*(val >> 6))), ins); + break; + case 0x7: /*Ramp start*/ + gus->rstart[gus->voice] = val << 14; +// pclog("Ramp start %04X\n", gus->rstart[gus->voice] >> 10); + break; + case 0x8: /*Ramp end*/ + gus->rend[gus->voice] = val << 14; +// pclog("Ramp end %04X\n", gus->rend[gus->voice] >> 10); + break; + case 0x9: /*Current volume*/ + gus->curvol[gus->voice] = gus->rcur[gus->voice] = (gus->rcur[gus->voice] & ~(0xff << 14)) | (val << 14); +// printf("Vol %i is %04X\n",gus->voice,gus->curvol[gus->voice]); + break; + + case 0xA: /*Current addr high*/ + gus->cur[gus->voice]=(gus->cur[gus->voice]&0x00FFFFFF)|((val&0x1F)<<24); + gus->curx[gus->voice]=(gus->curx[gus->voice]&0x07FFF00)|((val<<15)<<8); +// printf("Write %i cur %08X %08X %02X\n",gus->voice,gus->cur[gus->voice],gus->curx[gus->voice],val); +// gus->cur[gus->voice]=(gus->cur[gus->voice]&0x007FFF00)|((val<<15)<<8); + break; + case 0xB: /*Current addr low*/ + gus->cur[gus->voice]=(gus->cur[gus->voice]&0x1FFF00FF)|(val<<8); +gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); +// gus->cur[gus->voice]=(gus->cur[gus->voice]&0x0FFF8000)|((val&0x7F)<<8); +// printf("Write %i cur %08X %08X\n",gus->voice,gus->cur[gus->voice],gus->curx[gus->voice]); + break; + case 0xD: /*Ramp control*/ + old = gus->rampirqs[gus->voice]; + gus->rctrl[gus->voice] = val & 0x7F; + gus->rampirqs[gus->voice] = ((val & 0xa0) == 0xa0) ? 1 : 0; + if (gus->rampirqs[gus->voice] != old) + pollgusirqs(gus); +// printf("Ramp control %02i %02X %02X %i\n",gus->voice,val,gus->rampirqs[gus->voice],ins); + break; + + case 0xE: + gus->voices=(val&63)+1; + if (gus->voices>32) gus->voices=32; + if (gus->voices<14) gus->voices=14; + gus->global=val; +// printf("GUS voices %i\n",val&31); + if (gus->voices < 14) + gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / 44100.0)); + else + gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / gusfreqs[gus->voices - 14])); + break; + + case 0x41: /*DMA*/ + if (val&1 && gus->dma != -1) + { +// printf("DMA start! %05X %02X\n",gus->dmaaddr,val); + if (val & 2) + { + c=0; + while (c<65536) + { + d = gus->ram[gus->dmaaddr]; + if (val & 0x80) d ^= 0x80; + if (dma_channel_write(gus->dma, d) == DMA_NODATA) break; + gus->dmaaddr++; + gus->dmaaddr&=0xFFFFF; + c++; + } +// printf("GUS->MEM Transferred %i bytes\n",c); + gus->dmactrl=val&~0x40; + if (val&0x20) gus->irqnext=1; + } + else + { + c=0; + while (c<65536) + { + d = dma_channel_read(gus->dma); + if (d == DMA_NODATA) break; + if (val&0x80) d^=0x80; + gus->ram[gus->dmaaddr]=d; + gus->dmaaddr++; + gus->dmaaddr&=0xFFFFF; + c++; + } +// printf("MEM->GUS Transferred %i bytes\n",c); + gus->dmactrl=val&~0x40; + if (val&0x20) gus->irqnext=1; + } +// exit(-1); + } + break; + + case 0x42: /*DMA address low*/ + gus->dmaaddr=(gus->dmaaddr&0xFF0)|(val<<12); + break; + + case 0x43: /*Address low*/ + gus->addr=(gus->addr&0xF00FF)|(val<<8); + break; + case 0x44: /*Address high*/ + gus->addr=(gus->addr&0xFFFF)|((val<<16)&0xF0000); + break; + case 0x45: /*Timer control*/ + if (!(val&4)) gus->irqstatus&=~4; + if (!(val&8)) gus->irqstatus&=~8; + if (!(val & 0x20)) + { + gus->ad_status &= ~0x18; + nmi = 0; + } + if (!(val & 0x02)) + { + gus->ad_status &= ~0x01; + nmi = 0; + } +// printf("Timer control %02X\n",val); +/* if ((val&4) && !(gus->tctrl&4)) + { + gus->t1=gus->t1l; + gus->t1on=1; + }*/ + gus->tctrl=val; + gus->sb_ctrl = val; + break; + case 0x46: /*Timer 1*/ + gus->t1 = gus->t1l = val; + gus->t1on = 1; +// printf("GUS timer 1 %i\n",val); + break; + case 0x47: /*Timer 2*/ + gus->t2 = gus->t2l = val; + gus->t2on = 1; +// printf("GUS timer 2 %i\n",val); + break; + + case 0x4c: /*Reset*/ + gus->reset = val; + break; + } + break; + case 0x347: /*DRAM access*/ + gus->ram[gus->addr]=val; +// pclog("GUS RAM write %05X %02X\n",gus->addr,val); + gus->addr&=0xFFFFF; + break; + case 0x248: case 0x388: + gus->adcommand = val; +// pclog("Setting ad command %02X %02X %p\n", val, gus->adcommand, &gus->adcommand); + break; + + case 0x389: + if ((gus->tctrl & GUS_TIMER_CTRL_AUTO) || gus->adcommand != 4) + { + gus->ad_data = val; + gus->ad_status |= 0x01; + if (gus->sb_ctrl & 0x02) + { + if (gus->sb_nmi) + nmi = 1; + else if (gus->irq != -1) + picint(1 << gus->irq); + } + } + else if (!(gus->tctrl & GUS_TIMER_CTRL_AUTO) && gus->adcommand == 4) + { + if (val & 0x80) + { + gus->ad_status &= ~0x60; + } + else + { + gus->ad_timer_ctrl = val; + + if (val & 0x01) + gus->t1on = 1; + else + gus->t1 = gus->t1l; + + if (val & 0x02) + gus->t2on = 1; + else + gus->t2 = gus->t2l; + } + } + break; + + case 0x240: + gus->midi_loopback = val & 0x20; + gus->latch_enable = (val & 0x40) ? 2 : 1; + break; + + case 0x24b: + switch (gus->reg_ctrl & 0x07) + { + case 0: + if (gus->latch_enable == 1) + gus->dma = gus_dmas[val & 7]; + if (gus->latch_enable == 2) + { + gus->irq = gus_irqs[val & 7]; + if (val & 0x40) + gus->irq_midi = gus->irq; + else + gus->irq_midi = gus_irqs_midi[(val >> 3) & 7]; + + gus->sb_nmi = val & 0x80; + } + gus->latch_enable = 0; +// pclog("IRQ %i DMA %i\n", gus->irq, gus->dma); + break; + case 1: + gus->gp1 = val; + break; + case 2: + gus->gp2 = val; + break; + case 3: + gus->gp1_addr = val; + break; + case 4: + gus->gp2_addr = val; + break; + case 5: + gus->usrr = 0; + break; + case 6: + break; + } + break; + + case 0x246: + gus->ad_status |= 0x08; + if (gus->sb_ctrl & 0x20) + { + if (gus->sb_nmi) + nmi = 1; + else if (gus->irq != -1) + picint(1 << gus->irq); + } + break; + case 0x24a: + gus->sb_2xa = val; + break; + case 0x24c: + gus->ad_status |= 0x10; + if (gus->sb_ctrl & 0x20) + { + if (gus->sb_nmi) + nmi = 1; + else if (gus->irq != -1) + picint(1 << gus->irq); + } + case 0x24d: + gus->sb_2xc = val; + break; + case 0x24e: + gus->sb_2xe = val; + break; + case 0x24f: + gus->reg_ctrl = val; + break; + } +} + +uint8_t readgus(uint16_t addr, void *p) +{ + gus_t *gus = (gus_t *)p; + uint8_t val; +// /*if (addr!=0x246) */printf("Read GUS %04X %04X(%06X):%04X %02X\n",addr,CS,cs,pc,gus->global); + switch (addr) + { + case 0x340: /*MIDI status*/ + val = gus->midi_status; +// pclog("Read MIDI status %02X\n", val); + break; + + case 0x341: /*MIDI data*/ + val = gus->midi_data; + gus->midi_status &= ~MIDI_INT_RECEIVE; + gus_midi_update_int_status(gus); + break; + + case 0x240: return 0; + case 0x246: /*IRQ status*/ + val = gus->irqstatus & ~0x10; + if (gus->ad_status & 0x19) + val |= 0x10; +// pclog("Read IRQ status %02X\n", val); + return val; + + case 0x24F: return 0; + case 0x342: return gus->voice; + case 0x343: return gus->global; + case 0x344: /*Global low*/ +// /*if (gus->global!=0x43 && gus->global!=0x44) */printf("Reading register %02X %02X\n",gus->global,gus->voice); + switch (gus->global) + { + case 0x82: /*Start addr high*/ + return gus->start[gus->voice]>>16; + case 0x83: /*Start addr low*/ + return gus->start[gus->voice]&0xFF; + + case 0x89: /*Current volume*/ + return gus->rcur[gus->voice]>>6; + case 0x8A: /*Current addr high*/ + return gus->cur[gus->voice]>>16; + case 0x8B: /*Current addr low*/ + return gus->cur[gus->voice]&0xFF; + + case 0x8F: /*IRQ status*/ + val=gus->irqstatus2; +// pclog("Read IRQ status - %02X\n",val); + gus->rampirqs[gus->irqstatus2&0x1F]=0; + gus->waveirqs[gus->irqstatus2&0x1F]=0; + pollgusirqs(gus); + return val; + + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + val = 0xff; + break; + + default: + fatal("Bad GUS global low read %02X\n",gus->global); + } + break; + case 0x345: /*Global high*/ +// /*if (gus->global!=0x43 && gus->global!=0x44) */printf("HReading register %02X %02X\n",gus->global,gus->voice); + switch (gus->global) + { + case 0x80: /*Voice control*/ +// pclog("Read voice control %02i %02X\n", gus->voice, gus->ctrl[gus->voice]|(gus->waveirqs[gus->voice]?0x80:0)); + return gus->ctrl[gus->voice]|(gus->waveirqs[gus->voice]?0x80:0); + + case 0x82: /*Start addr high*/ + return gus->start[gus->voice]>>24; + case 0x83: /*Start addr low*/ + return gus->start[gus->voice]>>8; + + case 0x89: /*Current volume*/ +// pclog("Read current volume %i\n", gus->rcur[gus->voice] >> 14); + return gus->rcur[gus->voice]>>14; + + case 0x8A: /*Current addr high*/ + return gus->cur[gus->voice]>>24; + case 0x8B: /*Current addr low*/ + return gus->cur[gus->voice]>>8; + + case 0x8D: +// pclog("Read ramp control %02X %04X %08X %08X %08X\n",gus->rctrl[gus->voice]|(gus->rampirqs[gus->voice]?0x80:0),gus->rcur[gus->voice] >> 14,gus->rfreq[gus->voice],gus->rstart[gus->voice],gus->rend[gus->voice]); + return gus->rctrl[gus->voice]|(gus->rampirqs[gus->voice]?0x80:0); + + case 0x8F: /*IRQ status*/ +// pclog("Read IRQ 1\n"); + val=gus->irqstatus2; + gus->rampirqs[gus->irqstatus2&0x1F]=0; + gus->waveirqs[gus->irqstatus2&0x1F]=0; + pollgusirqs(gus); +// pclog("Read IRQ status - %02X %i %i\n",val, gus->waveirqs[gus->irqstatus2&0x1F], gus->rampirqs[gus->irqstatus2&0x1F]); + return val; + + case 0x41: /*DMA control*/ + val=gus->dmactrl|((gus->irqstatus&0x80)?0x40:0); + gus->irqstatus&=~0x80; + return val; + case 0x45: /*Timer control*/ + return gus->tctrl; + case 0x49: /*Sampling control*/ + return 0; + + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + val = 0xff; + break; + + default: + fatal("Bad GUS global high read %02X\n",gus->global); + } + break; + case 0x346: return 0xff; + case 0x347: /*DRAM access*/ + val=gus->ram[gus->addr]; +// pclog("GUS RAM read %05X %02X\n",gus->addr,val); + gus->addr&=0xFFFFF; + return val; + case 0x349: return 0; + case 0x746: /*Revision level*/ + return 0xff; /*Pre 3.7 - no mixer*/ + + case 0x24b: + switch (gus->reg_ctrl & 0x07) + { + case 1: + val = gus->gp1; + break; + case 2: + val = gus->gp2; + break; + case 3: + val = gus->gp1_addr; + break; + case 4: + val = gus->gp2_addr; + break; + } + break; + + case 0x24c: + val = gus->sb_2xc; + if (gus->reg_ctrl & 0x20) + gus->sb_2xc &= 0x80; + break; + case 0x24e: +/* gus->ad_status |= 0x10; + if (gus->reg_ctrl & 0x80) + { + gus->reg_ctrl_r |= 0x80; + if (gus->sb_nmi) + nmi = 1; + else + picint(1 << gus->irq); + }*/ + return gus->sb_2xe; + + case 0x248: case 0x388: +// pclog("Read ad_status %02X\n", gus->ad_status); + if (gus->tctrl & GUS_TIMER_CTRL_AUTO) + val = gus->sb_2xa; + else + { + val = gus->ad_status & ~(gus->ad_timer_ctrl & 0x60); + if (val & 0x60) + val |= 0x80; + } + break; + + case 0x249: + gus->ad_status &= ~0x01; + nmi = 0; + case 0x389: + val = gus->ad_data; + break; + + case 0x24A: + val = gus->adcommand; +// pclog("Read ad command %02X %02X %p\n", gus->adcommand, val, &gus->adcommand); + break; + + } +// printf("Bad GUS read %04X! %02X\n",addr,gus->global); +// exit(-1); + return val; +} + +void gus_poll_timer_1(void *p) +{ + gus_t *gus = (gus_t *)p; + + gus->timer_1 += (TIMER_USEC * 80); +// pclog("gus_poll_timer_1 %i %i %i %i %02X\n", gustime, gus->t1on, gus->t1, gus->t1l, gus->tctrl); + if (gus->t1on) + { + gus->t1++; + if (gus->t1 > 0xFF) + { +// gus->t1on=0; + gus->t1=gus->t1l; + gus->ad_status |= 0x40; + if (gus->tctrl&4) + { + if (gus->irq != -1) + picint(1 << gus->irq); + gus->ad_status |= 0x04; + gus->irqstatus |= 0x04; +// pclog("GUS T1 IRQ!\n"); + } + } + } + if (gus->irqnext) + { +// pclog("Take IRQ\n"); + gus->irqnext=0; + gus->irqstatus|=0x80; + if (gus->irq != -1) + picint(1 << gus->irq); + } + gus_midi_update_int_status(gus); +} + +void gus_poll_timer_2(void *p) +{ + gus_t *gus = (gus_t *)p; + + gus->timer_2 += (TIMER_USEC * 320); +// pclog("pollgus2 %i %i %i %i %02X\n", gustime, gus->t2on, gus->t2, gus->t2l, gus->tctrl); + if (gus->t2on) + { + gus->t2++; + if (gus->t2 > 0xFF) + { +// gus->t2on=0; + gus->t2=gus->t2l; + gus->ad_status |= 0x20; + if (gus->tctrl&8) + { + if (gus->irq != -1) + picint(1 << gus->irq); + gus->ad_status |= 0x02; + gus->irqstatus |= 0x08; +// pclog("GUS T2 IRQ!\n"); + } + } + } + if (gus->irqnext) + { +// pclog("Take IRQ\n"); + gus->irqnext=0; + gus->irqstatus|=0x80; + if (gus->irq != -1) + picint(1 << gus->irq); + } +} + +void gus_poll_wave(void *p) +{ + gus_t *gus = (gus_t *)p; + uint32_t addr; + int d; + int16_t v; + int32_t vl; + int update_irqs = 0; + + gus->samp_timer += gus->samp_latch; + + gus->out_l = gus->out_r = 0; + + if ((gus->reset & 3) != 3) + return; +//pclog("gus_poll_wave\n"); + for (d=0;d<32;d++) + { + if (!(gus->ctrl[d] & 3)) + { + if (gus->ctrl[d] & 4) + { + addr = gus->cur[d] >> 9; + addr = (addr & 0xC0000) | ((addr << 1) & 0x3FFFE); + if (!(gus->freq[d] >> 10)) /*Interpolate*/ + { + vl = (int16_t)(int8_t)((gus->ram[(addr + 1) & 0xFFFFF] ^ 0x80) - 0x80) * (511 - (gus->cur[d] & 511)); + vl += (int16_t)(int8_t)((gus->ram[(addr + 3) & 0xFFFFF] ^ 0x80) - 0x80) * (gus->cur[d] & 511); + v = vl >> 9; + } + else + v = (int16_t)(int8_t)((gus->ram[(addr + 1) & 0xFFFFF] ^ 0x80) - 0x80); + } + else + { + if (!(gus->freq[d] >> 10)) /*Interpolate*/ + { + vl = ((int8_t)((gus->ram[(gus->cur[d] >> 9) & 0xFFFFF] ^ 0x80) - 0x80)) * (511 - (gus->cur[d] & 511)); + vl += ((int8_t)((gus->ram[((gus->cur[d] >> 9) + 1) & 0xFFFFF] ^ 0x80) - 0x80)) * (gus->cur[d] & 511); + v = vl >> 9; + } + else + v = (int16_t)(int8_t)((gus->ram[(gus->cur[d] >> 9) & 0xFFFFF] ^ 0x80) - 0x80); + } + +// pclog("Voice %i : %04X %05X %04X ", d, v, gus->cur[d] >> 9, gus->rcur[d] >> 10); + if ((gus->rcur[d] >> 14) > 4095) v = (int16_t)(float)(v) * 24.0 * vol16bit[4095]; + else v = (int16_t)(float)(v) * 24.0 * vol16bit[(gus->rcur[d]>>10) & 4095]; +// pclog("%f %04X\n", vol16bit[(gus->rcur[d]>>10) & 4095], v); + + gus->out_l += v; + gus->out_r += v; + + if (gus->ctrl[d]&0x40) + { + gus->cur[d] -= (gus->freq[d] >> 1); + if (gus->cur[d] <= gus->start[d]) + { + int diff = gus->start[d] - gus->cur[d]; + if (!(gus->rctrl[d]&4)) + { + if (!(gus->ctrl[d]&8)) + { + gus->ctrl[d] |= 1; + gus->cur[d] = (gus->ctrl[d] & 0x40) ? gus->end[d] : gus->start[d]; + } + else + { + if (gus->ctrl[d]&0x10) gus->ctrl[d]^=0x40; + gus->cur[d] = (gus->ctrl[d] & 0x40) ? (gus->end[d] - diff) : (gus->start[d] + diff); + } + } + if ((gus->ctrl[d] & 0x20) && !gus->waveirqs[d]) + { + gus->waveirqs[d] = 1; + update_irqs = 1; +// pclog("Causing wave IRQ %02X %i\n", gus->ctrl[d], d); + } + } + } + else + { + gus->cur[d] += (gus->freq[d] >> 1); + + if (gus->cur[d] >= gus->end[d]) + { + int diff = gus->cur[d] - gus->end[d]; + if (!(gus->rctrl[d]&4)) + { + if (!(gus->ctrl[d]&8)) + { + gus->ctrl[d] |= 1; + gus->cur[d] = (gus->ctrl[d] & 0x40) ? gus->end[d] : gus->start[d]; + } + else + { + if (gus->ctrl[d]&0x10) gus->ctrl[d]^=0x40; + gus->cur[d] = (gus->ctrl[d] & 0x40) ? (gus->end[d] - diff) : (gus->start[d] + diff); + } + } + if ((gus->ctrl[d] & 0x20) && !gus->waveirqs[d]) + { + gus->waveirqs[d] = 1; + update_irqs = 1; +// pclog("Causing wave IRQ %02X %i\n", gus->ctrl[d], d); + } + } + } + } + if (!(gus->rctrl[d] & 3)) + { + if (gus->rctrl[d] & 0x40) + { + gus->rcur[d] -= gus->rfreq[d]; + if (gus->rcur[d] <= gus->rstart[d]) + { + int diff = gus->rstart[d] - gus->rcur[d]; + if (!(gus->rctrl[d] & 8)) + { + gus->rctrl[d] |= 1; + gus->rcur[d] = (gus->rctrl[d] & 0x40) ? gus->rstart[d] : gus->rend[d]; + } + else + { + if (gus->rctrl[d] & 0x10) gus->rctrl[d] ^= 0x40; + gus->rcur[d] = (gus->rctrl[d] & 0x40) ? (gus->rend[d] - diff) : (gus->rstart[d] + diff); + } + + if ((gus->rctrl[d] & 0x20) && !gus->rampirqs[d]) + { + gus->rampirqs[d] = 1; + update_irqs = 1; +// pclog("Causing ramp IRQ %02X %i\n",gus->rctrl[d], d); + } + } + } + else + { + gus->rcur[d] += gus->rfreq[d]; +// if (d == 1) printf("RCUR+ %i %08X %08X %08X %08X\n",d,gus->rfreq[d],gus->rcur[d],gus->rstart[d],gus->rend[d]); + if (gus->rcur[d] >= gus->rend[d]) + { + int diff = gus->rcur[d] - gus->rend[d]; + if (!(gus->rctrl[d] & 8)) + { + gus->rctrl[d] |= 1; + gus->rcur[d] = (gus->rctrl[d] & 0x40) ? gus->rstart[d] : gus->rend[d]; + } + else + { + if (gus->rctrl[d] & 0x10) gus->rctrl[d] ^= 0x40; + gus->rcur[d] = (gus->rctrl[d] & 0x40) ? (gus->rend[d] - diff) : (gus->rstart[d] + diff); + } + + if ((gus->rctrl[d] & 0x20) && !gus->rampirqs[d]) + { + gus->rampirqs[d] = 1; + update_irqs = 1; +// pclog("Causing ramp IRQ %02X %i\n",gus->rctrl[d], d); + } + } + } + } + } + + if (update_irqs) + pollgusirqs(gus); +} + +void gus_poll(void *p) +{ + gus_t *gus = (gus_t *)p; + + if (gus->pos >= SOUNDBUFLEN) + return; + + //pclog("gus_poll\n"); + gus->buffer[0][gus->pos] = gus->out_l; + gus->buffer[1][gus->pos] = gus->out_r; + + gus->pos++; +} + +static void gus_get_buffer(int16_t *buffer, int len, void *p) +{ + gus_t *gus = (gus_t *)p; + int c; + + for (c = 0; c < len * 2; c++) + { + buffer[c] += gus->buffer[c & 1][c >> 1]; + } + + gus->pos = 0; +} + + +void *gus_init() +{ + int c; + double out = 1.0; + gus_t *gus = malloc(sizeof(gus_t)); + memset(gus, 0, sizeof(gus_t)); + + gus->ram = malloc(1 << 20); + memset(gus->ram, 0, 1 << 20); + + pclog("gus_init\n"); + + for (c=0;c<32;c++) + { + gus->ctrl[c]=1; + gus->rctrl[c]=1; + gus->rfreq[c]=63*512; + } + + for (c=4095;c>=0;c--) { + vol16bit[c]=out;//(float)c/4095.0;//out; + out/=1.002709201; /* 0.0235 dB Steps */ + } + + printf("Top volume %f %f %f %f\n",vol16bit[4095],vol16bit[3800],vol16bit[3000],vol16bit[2048]); + gus->voices=14; + + gus->samp_timer = gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / 44100.0)); + + io_sethandler(0x0240, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); + io_sethandler(0x0340, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); + io_sethandler(0x0746, 0x0001, readgus, NULL, NULL, writegus, NULL, NULL, gus); + io_sethandler(0x0388, 0x0002, readgus, NULL, NULL, writegus, NULL, NULL, gus); + timer_add(gus_poll_wave, &gus->samp_timer, TIMER_ALWAYS_ENABLED, gus); + timer_add(gus_poll_timer_1, &gus->timer_1, TIMER_ALWAYS_ENABLED, gus); + timer_add(gus_poll_timer_2, &gus->timer_2, TIMER_ALWAYS_ENABLED, gus); + + sound_add_handler(gus_poll, gus_get_buffer, gus); + + return gus; +} + +void gus_close(void *p) +{ + gus_t *gus = (gus_t *)p; + + free(gus->ram); + free(gus); +} + +void gus_speed_changed(void *p) +{ + gus_t *gus = (gus_t *)p; + + if (gus->voices < 14) + gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / 44100.0)); + else + gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / gusfreqs[gus->voices - 14])); +} + +device_t gus_device = +{ + "Gravis UltraSound", + gus_init, + gus_close, + gus_speed_changed +}; diff --git a/src/sound_gus.h b/src/sound_gus.h new file mode 100644 index 0000000..b0de59b --- /dev/null +++ b/src/sound_gus.h @@ -0,0 +1 @@ +extern device_t gus_device; diff --git a/src/sound_opl.c b/src/sound_opl.c new file mode 100644 index 0000000..95f1d98 --- /dev/null +++ b/src/sound_opl.c @@ -0,0 +1,195 @@ +#include +#include +#include "ibm.h" +#include "io.h" +#include "sound_opl.h" + +/*Interfaces between PCem and the actual OPL emulator*/ + + +uint8_t opl2_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + cycles -= (int)(isa_timing * 8); + return ym3812_read(opl->YM3812[0], a); +} +void opl2_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + ym3812_write(opl->YM3812[0],a,v); + ym3812_write(opl->YM3812[1],a,v); +} + +uint8_t opl2_l_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + cycles -= (int)(isa_timing * 8); + return ym3812_read(opl->YM3812[0], a); +} +void opl2_l_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + ym3812_write(opl->YM3812[0],a,v); +} + +uint8_t opl2_r_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + cycles -= (int)(isa_timing * 8); + return ym3812_read(opl->YM3812[1], a); +} +void opl2_r_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + ym3812_write(opl->YM3812[1],a,v); +} + +uint8_t opl3_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + cycles -= (int)(isa_timing * 8); + return ymf262_read(opl->YMF262, a); +} +void opl3_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + ymf262_write(opl->YMF262, a, v); +} + + +void opl2_poll(opl_t *opl, int16_t *bufl, int16_t *bufr) +{ + ym3812_update_one(opl->YM3812[0], bufl, 1); + ym3812_update_one(opl->YM3812[1], bufr, 1); + + opl->filtbuf[0] = *bufl = ((*bufl) / 4) + ((opl->filtbuf[0] * 11) / 16); + opl->filtbuf[1] = *bufr = ((*bufr) / 4) + ((opl->filtbuf[1] * 11) / 16); + + if (opl->timers_enable[0][0]) + { + opl->timers[0][0]--; + if (opl->timers[0][0] < 0) ym3812_timer_over(opl->YM3812[0], 0); + } + if (opl->timers_enable[0][1]) + { + opl->timers[0][1]--; + if (opl->timers[0][1] < 0) ym3812_timer_over(opl->YM3812[0], 1); + } + if (opl->timers_enable[1][0]) + { + opl->timers[1][0]--; + if (opl->timers[1][0] < 0) ym3812_timer_over(opl->YM3812[1], 0); + } + if (opl->timers_enable[1][1]) + { + opl->timers[1][1]--; + if (opl->timers[1][1] < 0) ym3812_timer_over(opl->YM3812[1], 1); + } +} + +void opl3_poll(opl_t *opl, int16_t *bufl, int16_t *bufr) +{ + ymf262_update_one(opl->YMF262, opl->bufs, 1); + + opl->filtbuf[0] = *bufl = ((opl->bufs[0][0]) / 4) + ((opl->filtbuf[0] * 11) / 16); + opl->filtbuf[1] = *bufr = ((opl->bufs[1][0]) / 4) + ((opl->filtbuf[1] * 11) / 16); + + if (opl->timers_enable[0][0]) + { + opl->timers[0][0]--; + if (opl->timers[0][0] < 0) + { + opl->timers_enable[0][0] = 0; + ymf262_timer_over(opl->YMF262, 0); + } + } + if (opl->timers_enable[0][1]) + { + opl->timers[0][1]--; + if (opl->timers[0][1] < 0) + { + opl->timers_enable[0][1] = 0; + ymf262_timer_over(opl->YMF262, 1); + } + } +} + +void ym3812_timer_set_0(void *param, int timer, attotime period) +{ + opl_t *opl = (opl_t *)param; + + opl->timers[0][timer] = period / 20833; + if (!opl->timers[0][timer]) opl->timers[0][timer] = 1; + opl->timers_enable[0][timer] = period ? 1 : 0; +} +void ym3812_timer_set_1(void *param, int timer, attotime period) +{ + opl_t *opl = (opl_t *)param; + + opl->timers[1][timer] = period / 20833; + if (!opl->timers[1][timer]) opl->timers[1][timer] = 1; + opl->timers_enable[1][timer] = period ? 1 : 0; +} + +void ymf262_timer_set(void *param, int timer, attotime period) +{ + opl_t *opl = (opl_t *)param; + + opl->timers[0][timer] = period / 20833; + if (!opl->timers[0][timer]) opl->timers[0][timer] = 1; + opl->timers_enable[0][timer] = period ? 1 : 0; +} + +void opl2_init(opl_t *opl) +{ + opl->bufs[0] = (int16_t *)malloc(4); + opl->bufs[1] = (int16_t *)malloc(4); + opl->bufs[2] = (int16_t *)malloc(4); + opl->bufs[3] = (int16_t *)malloc(4); + + opl->YM3812[0] = ym3812_init(NULL, 3579545, 48000); + ym3812_reset_chip(opl->YM3812[0]); + ym3812_set_timer_handler(opl->YM3812[0], ym3812_timer_set_0, opl); + + opl->YM3812[1] = ym3812_init(NULL, 3579545, 48000); + ym3812_reset_chip(opl->YM3812[1]); + ym3812_set_timer_handler(opl->YM3812[1], ym3812_timer_set_1, opl); +} + +void opl3_init(opl_t *opl) +{ + opl->bufs[0] = (int16_t *)malloc(4); + opl->bufs[1] = (int16_t *)malloc(4); + opl->bufs[2] = (int16_t *)malloc(4); + opl->bufs[3] = (int16_t *)malloc(4); + + opl->YMF262 = ymf262_init(NULL, 3579545 * 4, 48000); + ymf262_reset_chip(opl->YMF262); + ymf262_set_timer_handler(opl->YMF262, ymf262_timer_set, opl); +} + +void opl2_close(opl_t *opl) +{ + free(opl->bufs[0]); + free(opl->bufs[1]); + + ym3812_shutdown(opl->YM3812[0]); + ym3812_shutdown(opl->YM3812[1]); +} + +void opl3_close(opl_t *opl) +{ + free(opl->bufs[0]); + free(opl->bufs[1]); + + ym3812_shutdown(opl->YM3812[0]); + ymf262_shutdown(opl->YMF262); +} diff --git a/src/sound_opl.h b/src/sound_opl.h new file mode 100644 index 0000000..43d2acb --- /dev/null +++ b/src/sound_opl.h @@ -0,0 +1,35 @@ +#include "mame/fmopl.h" +#include "mame/ymf262.h" + +typedef struct opl_t +{ + void *YM3812[2]; + void *YMF262; + + int timers[2][2]; + int timers_enable[2][2]; + + int16_t *bufs[4]; + int16_t filtbuf[2]; +} opl_t; + +uint8_t opl_read(uint16_t a, void *priv); +void opl_write(uint16_t a, uint8_t v, void *priv); + +uint8_t opl2_read(uint16_t a, void *priv); +void opl2_write(uint16_t a, uint8_t v, void *priv); +uint8_t opl2_l_read(uint16_t a, void *priv); +void opl2_l_write(uint16_t a, uint8_t v, void *priv); +uint8_t opl2_r_read(uint16_t a, void *priv); +void opl2_r_write(uint16_t a, uint8_t v, void *priv); +uint8_t opl3_read(uint16_t a, void *priv); +void opl3_write(uint16_t a, uint8_t v, void *priv); + +void opl2_poll(opl_t *opl, int16_t *bufl, int16_t *bufr); +void opl3_poll(opl_t *opl, int16_t *bufl, int16_t *bufr); + +void opl2_init(opl_t *opl); +void opl3_init(opl_t *opl); + +void opl2_close(opl_t *opl); +void opl3_close(opl_t *opl); diff --git a/src/sound_pas16.c b/src/sound_pas16.c new file mode 100644 index 0000000..5b5b412 --- /dev/null +++ b/src/sound_pas16.c @@ -0,0 +1,753 @@ +#include +#include "ibm.h" + +#include "device.h" +#include "dma.h" +#include "filters.h" +#include "io.h" +#include "pic.h" +#include "pit.h" +#include "sound_opl.h" +#include "sound_pas16.h" +#include "sound_sb_dsp.h" +#include "timer.h" + +/* Original PAS uses + 2 x OPL2 + PIT - sample rate/count + LMC835N/LMC1982 - mixer + YM3802 - MIDI Control System + + + 9A01 - IO base + base >> 2 + + All below + IO base + + B89 - interrupt status / clear + bit 2 - sample rate + bit 3 - PCM + bit 4 - MIDI + + B88 - Audio mixer control register + + B8A - Audio filter control + bit 5 - mute? + + B8B - interrupt mask / board ID + bits 5-7 - board ID (read only on PAS16) + + F88 - PCM data (low) + + F89 - PCM data (high) + + F8A - PCM control? + bit 4 - input/output select (1 = output) + bit 5 - mono/stereo select + bit 6 - PCM enable + + 1388-138b - PIT clocked at 1193180 Hz + 1388 - sample rate + 1389 - sample count + + 178b - + 2789 - board revision + + 8389 - + bit 2 - 8/16 bit + + BF88 - wait states + + EF8B - + bit 3 - 16 bits okay ? + + F388 - + bit 6 - joystick enable + + F389 - + bits 0-2 - DMA + + F38A - + bits 0-3 - IRQ + + F788 - + bit 1 - SB emulation + bit 0 - MPU401 emulation + + F789 - SB base addr + bits 0-3 - addr bits 4-7 + + FB8A - SB IRQ/DMA + bits 3-5 - IRQ + bits 6-7 - DMA + + FF88 - board model + 3 = PAS16 +*/ + +static uint8_t pas16_pit_in(uint16_t port, void *priv); +static void pas16_pit_out(uint16_t port, uint8_t val, void *priv); +//static void pas16_update_irqs(); + +typedef struct pas16_t +{ + uint16_t base; + + int irq, dma; + + uint8_t audiofilt; + + uint8_t audio_mixer; + + uint8_t compat, compat_base; + + uint8_t enhancedscsi; + + uint8_t io_conf_1, io_conf_2, io_conf_3, io_conf_4; + + uint8_t irq_stat, irq_ena; + + uint8_t pcm_ctrl; + uint16_t pcm_dat; + + uint16_t pcm_dat_l, pcm_dat_r; + + uint8_t sb_irqdma; + + int stereo_lr; + + uint8_t sys_conf_1, sys_conf_2, sys_conf_3, sys_conf_4; + + struct + { + uint32_t l[3]; + int c[3]; + uint8_t m[3]; + uint8_t ctrl, ctrls[2]; + int wp, rm[3], wm[3]; + uint16_t rl[3]; + int thit[3]; + int delay[3]; + int rereadlatch[3]; + int enable[3]; + } pit; + + opl_t opl; + sb_dsp_t dsp; + + int16_t opl_buffer[SOUNDBUFLEN * 2]; + int16_t pcm_buffer[2][SOUNDBUFLEN]; + int16_t dsp_buffer[SOUNDBUFLEN * 2]; + + int pos; +} pas16_t; + +static int pas16_dmas[8] = {4, 1, 2, 3, 0, 5, 6, 7}; +static int pas16_irqs[16] = {0, 2, 3, 4, 5, 6, 7, 10, 11, 12, 14, 15, 0, 0, 0, 0}; +static int pas16_sb_irqs[8] = {0, 2, 3, 5, 7, 10, 11, 12}; +static int pas16_sb_dmas[8] = {0, 1, 2, 3}; + +enum +{ + PAS16_INT_SAMP = 0x04, + PAS16_INT_PCM = 0x08, +}; + +enum +{ + PAS16_PCM_MONO = 0x20, + PAS16_PCM_ENA = 0x40 +}; + +enum +{ + PAS16_SC2_16BIT = 0x04, + PAS16_SC2_MSBINV = 0x10 +}; + +enum +{ + PAS16_FILT_MUTE = 0x20 +}; + +static uint8_t pas16_in(uint16_t port, void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + uint8_t temp; +/* if (CS == 0xCA53 && pc == 0x3AFC) + fatal("here");*/ + switch ((port - pas16->base) + 0x388) + { + case 0x388: case 0x389: case 0x38a: case 0x38b: + temp = opl3_read((port - pas16->base) + 0x388, &pas16->opl); + break; + + case 0xb88: + temp = pas16->audio_mixer; + break; + + case 0xb89: + temp = pas16->irq_stat; + break; + + case 0xb8a: + temp = pas16->audiofilt; + break; + + case 0xb8b: + temp = (pas16->irq_ena & ~0xe0) | 0x20; + break; + + case 0xf8a: + temp = pas16->pcm_ctrl; + break; + + case 0x1388: case 0x1389: case 0x138a: case 0x138b: + temp = pas16_pit_in(port, pas16); + break; + + case 0x2789: /*Board revision*/ + temp = 0; + break; + + case 0x7f89: + temp = pas16->enhancedscsi & ~1; + break; + + case 0x8388: + temp = pas16->sys_conf_1; + break; + case 0x8389: + temp = pas16->sys_conf_2; + break; + case 0x838b: + temp = pas16->sys_conf_3; + break; + case 0x838c: + temp = pas16->sys_conf_4; + break; + + case 0xef8b: + temp = 0x0c; + break; + + case 0xf388: + temp = pas16->io_conf_1; + break; + case 0xf389: + temp = pas16->io_conf_2; + break; + case 0xf38b: + temp = pas16->io_conf_3; + break; + case 0xf38c: + temp = pas16->io_conf_4; + break; + + case 0xf788: + temp = pas16->compat; + break; + case 0xf789: + temp = pas16->compat_base; + break; + + case 0xfb8a: + temp = pas16->sb_irqdma; + break; + + case 0xff88: /*Board model*/ + temp = 4; /*PAS16*/ + break; + case 0xff8b: /*Master mode read*/ + temp = 0x20 | 0x10 | 0x01; /*AT bus, XT/AT timing*/ + break; + } +/* if (port != 0x388 && port != 0x389 && port != 0xb8b) */pclog("pas16_in : port %04X return %02X %04X:%04X\n", port, temp, CS,pc); +/* if (CS == 0x1FF4 && pc == 0x0585) + { + if (output) + fatal("here"); + output = 3; + }*/ + return temp; +} + +static void pas16_out(uint16_t port, uint8_t val, void *p) +{ + pas16_t *pas16 = (pas16_t *)p; +/* if (port != 0x388 && port != 0x389) */pclog("pas16_out : port %04X val %02X %04X:%04X\n", port, val, CS,pc); +/* if (CS == 0x369 && pc == 0x2AC5) + fatal("here\n");*/ + switch ((port - pas16->base) + 0x388) + { + case 0x388: case 0x389: case 0x38a: case 0x38b: + opl3_write((port - pas16->base) + 0x388, val, &pas16->opl); + break; + + case 0xb88: + pas16->audio_mixer = val; + break; + + case 0xb89: + pas16->irq_stat &= ~val; +// pas16_update_irqs(); + break; + + case 0xb8a: + pas16->audiofilt = val; + break; + + case 0xb8b: + pas16->irq_ena = val; +// pas16_update_irqs(); + break; + + case 0xf88: + pas16->pcm_dat = (pas16->pcm_dat & 0xff00) | val; + break; + case 0xf89: + pas16->pcm_dat = (pas16->pcm_dat & 0x00ff) | (val << 8); + break; + case 0xf8a: + if ((val & PAS16_PCM_ENA) && !(pas16->pcm_ctrl & PAS16_PCM_ENA)) /*Guess*/ + pas16->stereo_lr = 0; + pas16->pcm_ctrl = val; + break; + + case 0x1388: case 0x1389: case 0x138a: case 0x138b: + pas16_pit_out(port, val, pas16); + break; + + case 0x7f89: + pas16->enhancedscsi = val; + break; + + case 0x8388: + pas16->sys_conf_1 = val; + break; + case 0x8389: + pas16->sys_conf_2 = val; + break; + case 0x838a: + pas16->sys_conf_3 = val; + break; + case 0x838b: + pas16->sys_conf_4 = val; + break; + + case 0xf388: + pas16->io_conf_1 = val; + break; + case 0xf389: + pas16->io_conf_2 = val; + pas16->dma = pas16_dmas[val & 0x7]; + pclog("pas16_out : set PAS DMA %i\n", pas16->dma); + break; + case 0xf38a: + pas16->io_conf_3 = val; + pas16->irq = pas16_irqs[val & 0xf]; + pclog("pas16_out : set PAS IRQ %i\n", pas16->irq); + break; + case 0xf38b: + pas16->io_conf_4 = val; + break; + + case 0xf788: + pas16->compat = val; + if (pas16->compat & 0x02) + sb_dsp_setaddr(&pas16->dsp, ((pas16->compat_base & 0xf) << 4) | 0x200); + else + sb_dsp_setaddr(&pas16->dsp, 0); + break; + case 0xf789: + pas16->compat_base = val; + if (pas16->compat & 0x02) + sb_dsp_setaddr(&pas16->dsp, ((pas16->compat_base & 0xf) << 4) | 0x200); + break; + + case 0xfb8a: + pas16->sb_irqdma = val; + sb_dsp_setirq(&pas16->dsp, pas16_sb_irqs[(val >> 3) & 7]); + sb_dsp_setdma8(&pas16->dsp, pas16_sb_dmas[(val >> 6) & 3]); + pclog("pas16_out : set SB IRQ %i DMA %i\n", pas16_sb_irqs[(val >> 3) & 7], pas16_sb_dmas[(val >> 6) & 3]); + break; + + default: + pclog("pas16_out : unknown %04X\n", port); + } + if (pc == 0x80048CF3) + { + if (output) + fatal("here\n"); + output = 3; + } +/* if (CS == 0x1FF4 && pc == 0x0431) + output = 3;*/ +} + +static void pas16_pit_out(uint16_t port, uint8_t val, void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + int t; + switch (port & 3) + { + case 3: /*CTRL*/ + if ((val & 0xC0) == 0xC0) + { + if (!(val & 0x20)) + { + if (val & 2) pas16->pit.rl[0] = pas16->pit.c[0] / (PITCONST * (1 << TIMER_SHIFT)); + if (val & 4) pas16->pit.rl[1] = pas16->pit.c[1]; + if (val & 8) pas16->pit.rl[2] = pas16->pit.c[2]; + } + return; + } + t = val >> 6; + pas16->pit.ctrls[t] = pas16->pit.ctrl = val; + if (t == 3) + { + printf("Bad PIT reg select\n"); + return; + } + if (!(pas16->pit.ctrl & 0x30)) + { + pas16->pit.rl[t] = pas16->pit.c[t]; + if (!t) + pas16->pit.rl[t] /= (PITCONST * (1 << TIMER_SHIFT)); + if (pas16->pit.c[t] < 0) + pas16->pit.rl[t] = 0; + pas16->pit.ctrl |= 0x30; + pas16->pit.rereadlatch[t] = 0; + pas16->pit.rm[t] = 3; + } + else + { + pas16->pit.rm[t] = pas16->pit.wm[t] = (pas16->pit.ctrl >> 4) & 3; + pas16->pit.m[t] = (val >> 1) & 7; + if (pas16->pit.m[t] > 5) + pas16->pit.m[t] &= 3; + if (!pas16->pit.rm[t]) + { + pas16->pit.rm[t] = 3; + pas16->pit.rl[t] = pit.c[t]; + if (!t) + pas16->pit.rl[t] /= (PITCONST * (1 << TIMER_SHIFT)); + } + pas16->pit.rereadlatch[t] = 1; + } + pas16->pit.wp = 0; + pas16->pit.thit[t] = 0; + break; + case 0: case 1: case 2: /*Timers*/ + t = port & 3; + switch (pas16->pit.wm[t]) + { + case 1: + pas16->pit.l[t] = val; + pas16->pit.thit[t] = 0; + pas16->pit.c[t] = pas16->pit.l[t]; + if (!t) + pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT); + pas16->pit.enable[t] = 1; + break; + case 2: + pas16->pit.l[t] = val << 8; + pas16->pit.thit[t] = 0; + pas16->pit.c[t] = pas16->pit.l[t]; + if (!t) + pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT); + pas16->pit.enable[t] = 1; + break; + case 0: + pas16->pit.l[t] &= 0xFF; + pas16->pit.l[t] |= (val << 8); + pas16->pit.c[t] = pas16->pit.l[t]; + if (!t) + pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT); + pas16->pit.thit[t] = 0; + pas16->pit.wm[t] = 3; + pas16->pit.enable[t] = 1; + break; + case 3: + pas16->pit.l[t] &= 0xFF00; + pas16->pit.l[t] |= val; + pas16->pit.wm[t] = 0; + break; + } + if (!pas16->pit.l[t]) + { + pas16->pit.l[t] |= 0x10000; + pas16->pit.c[t] = pas16->pit.l[t]; + if (!t) + pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT); + } + break; + } +} + +static uint8_t pas16_pit_in(uint16_t port, void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + uint8_t temp; + int t = port & 3; +// printf("Read PIT %04X ",addr); + switch (port & 3) + { + case 0: case 1: case 2: /*Timers*/ + if (pas16->pit.rereadlatch[t]) + { + pas16->pit.rereadlatch[t] = 0; + if (!t) + { + pas16->pit.rl[t] = pas16->pit.c[t] / (PITCONST * (1 << TIMER_SHIFT)); + if ((pas16->pit.c[t] / (PITCONST * (1 << TIMER_SHIFT))) > 65536) + pas16->pit.rl[t] = 0xFFFF; + } + else + { + pas16->pit.rl[t] = pas16->pit.c[t]; + if (pas16->pit.c[t] > 65536) + pas16->pit.rl[t] = 0xFFFF; + } + } + switch (pas16->pit.rm[t]) + { + case 0: + temp = pas16->pit.rl[t] >> 8; + pas16->pit.rm[t] = 3; + pas16->pit.rereadlatch[t] = 1; + break; + case 1: + temp = (pas16->pit.rl[t]) & 0xFF; + pas16->pit.rereadlatch[t] = 1; + break; + case 2: + temp = (pas16->pit.rl[t]) >> 8; + pas16->pit.rereadlatch[t] = 1; + break; + case 3: + temp = (pas16->pit.rl[t]) & 0xFF; + if (pas16->pit.m[t] & 0x80) pas16->pit.m[t] &= 7; + else pas16->pit.rm[t] = 0; + break; + } + break; + case 3: /*Control*/ + temp = pas16->pit.ctrl; + break; + } +// printf("%02X %i %i %04X:%04X\n",temp,pit.rm[addr&3],pit.wp,cs>>4,pc); + return temp; +} + +static uint8_t pas16_readdma(pas16_t *pas16) +{ + return dma_channel_read(pas16->dma); +} + +static void pas16_pcm_poll(void *p) +{ + pas16_t *pas16 = (pas16_t *)p; +// if (pas16->pcm_ctrl & PAS16_PCM_ENA) +// pclog("pas16_pcm_poll : poll %i %i ", pas16->pit.c[0], pas16->pit.l[0]); + if (pas16->pit.m[0] & 2) + { + if (pas16->pit.l[0]) + pas16->pit.c[0] += (pas16->pit.l[0] * PITCONST * (1 << TIMER_SHIFT)); + else + pas16->pit.c[0] += (0x10000 * PITCONST * (1 << TIMER_SHIFT)); + } + else + { + pas16->pit.c[0] = -1; + pas16->pit.enable[0] = 0; + } +// if (pas16->pcm_ctrl & PAS16_PCM_ENA) +// pclog(" %i\n", pas16->pit.c[0]); + + pas16->irq_stat |= PAS16_INT_SAMP; + if (pas16->irq_ena & PAS16_INT_SAMP) + picint(1 << pas16->irq); +// pas16_update_irqs(); + + /*Update sample rate counter*/ + if (pas16->pit.enable[1]) + { + if (pas16->pcm_ctrl & PAS16_PCM_ENA) + { + uint16_t temp; + + if (pas16->sys_conf_2 & PAS16_SC2_16BIT) + { + temp = pas16_readdma(pas16) << 8; + temp |= pas16_readdma(pas16); + } + else + temp = (pas16_readdma(pas16) ^ 0x80) << 8; + + if (pas16->sys_conf_2 & PAS16_SC2_MSBINV) + temp ^= 0x8000; + if (pas16->pcm_ctrl & PAS16_PCM_MONO) + pas16->pcm_dat_l = pas16->pcm_dat_r = temp; + else + { + if (pas16->stereo_lr) + pas16->pcm_dat_r = temp; + else + pas16->pcm_dat_l = temp; + + pas16->stereo_lr = !pas16->stereo_lr; + } +// pclog("pas16_pcm_poll : %04X %i\n", temp, pas16->stereo_lr); +// pclog("pas16_pcm_poll : %i %02X %i\n", pas16->pit.c[1], temp, pas16->pit.c[0]); +/* if (!pas16_pcm) + pas16_pcm=fopen("pas16->pcm", "wb"); + putc(temp, pas16_pcm);*/ + } + if (pas16->sys_conf_2 & PAS16_SC2_16BIT) + pas16->pit.c[1] -= 2; + else + pas16->pit.c[1]--; + if (pas16->pit.c[1] == 0) + { +// if (pas16->pcm_ctrl & PAS16_PCM_ENA) +// pclog("pas16_pcm_poll : buffer over\n"); + if (pas16->pit.m[1] & 2) + { + if (pas16->pit.l[1]) + pas16->pit.c[1] += pas16->pit.l[1]; + else + pas16->pit.c[1] += 0x10000; + } + else + { + pas16->pit.c[1] = -1; + pas16->pit.enable[1] = 0; + } + + pas16->irq_stat |= PAS16_INT_PCM; + if (pas16->irq_ena & PAS16_INT_PCM) + { + pclog("pas16_pcm_poll : cause IRQ %i %02X\n", pas16->irq, 1 << pas16->irq); + picint(1 << pas16->irq); + } + } + } +} + +static void pas16_out_base(uint16_t port, uint8_t val, void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + + io_removehandler((pas16->base - 0x388) + 0x0388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x0788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x0b88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x0f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x1388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x1788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x2788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x7f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x8388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xbf88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xe388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xe788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xeb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xef88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xf388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xf788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xfb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xff88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + + pas16->base = val << 2; + pclog("pas16_write_base : PAS16 base now at %04X\n", pas16->base); + + io_sethandler((pas16->base - 0x388) + 0x0388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x0788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x0b88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x0f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x1388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x1788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x2788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x7f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x8388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xbf88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xe388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xe788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xeb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xef88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xf388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xf788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xfb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xff88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); +} + + +void pas16_poll(void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + + if (pas16->pos >= SOUNDBUFLEN) + return; + + opl3_poll(&pas16->opl, &pas16->opl_buffer[pas16->pos * 2], &pas16->opl_buffer[(pas16->pos * 2) + 1]); + sb_dsp_poll(&pas16->dsp, &pas16->dsp_buffer[pas16->pos * 2], &pas16->dsp_buffer[(pas16->pos * 2) + 1]); + + if (!(pas16->audiofilt & PAS16_FILT_MUTE)) + { + pas16->pcm_buffer[0][pas16->pos] = 0; + pas16->pcm_buffer[1][pas16->pos] = 0; + } + else + { + pas16->pcm_buffer[0][pas16->pos] = (int16_t)pas16->pcm_dat_l; + pas16->pcm_buffer[1][pas16->pos] = (int16_t)pas16->pcm_dat_r; + } + pas16->pos++; +} + +void pas16_get_buffer(int16_t *buffer, int len, void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + int c; + + for (c = 0; c < len * 2; c++) + { + buffer[c] += pas16->opl_buffer[c]; + buffer[c] += (int16_t)(sb_iir(c & 1, (float)pas16->dsp_buffer[c]) / 1.3) / 2; + buffer[c] += (pas16->pcm_buffer[c & 1][c >> 1] / 2); + } + + pas16->pos = 0; +} + +void *pas16_init() +{ + pas16_t *pas16 = malloc(sizeof(pas16_t)); + memset(pas16, 0, sizeof(pas16_t)); + + opl3_init(&pas16->opl); + sb_dsp_init(&pas16->dsp, SB2); + + io_sethandler(0x9a01, 0x0001, NULL, NULL, NULL, pas16_out_base, NULL, NULL, pas16); + + timer_add(pas16_pcm_poll, &pas16->pit.c[0], &pas16->pit.enable[0], pas16); + + sound_add_handler(pas16_poll, pas16_get_buffer, pas16); + + return pas16; +} + +void pas16_close(void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + + free(pas16); +} + +device_t pas16_device = +{ + "Pro Audio Spectrum 16", + pas16_init, + pas16_close, + NULL +}; diff --git a/src/sound_pas16.h b/src/sound_pas16.h new file mode 100644 index 0000000..a7ee7c6 --- /dev/null +++ b/src/sound_pas16.h @@ -0,0 +1 @@ +extern device_t pas16_device; diff --git a/src/sound_sb.c b/src/sound_sb.c new file mode 100644 index 0000000..1d19da8 --- /dev/null +++ b/src/sound_sb.c @@ -0,0 +1,412 @@ +#include +#include "ibm.h" +#include "device.h" +#include "sound_sb.h" +#include "sound_sb_dsp.h" +#include "sound_opl.h" + +#include "filters.h" + +typedef struct sb_mixer_t +{ + int master_l, master_r; + int voice_l, voice_r; + int fm_l, fm_r; + int bass_l, bass_r; + int treble_l, treble_r; + int filter; + + int index; + uint8_t regs[256]; +} sb_mixer_t; + +typedef struct sb_t +{ + opl_t opl; + sb_dsp_t dsp; + sb_mixer_t mixer; + + int16_t opl_buffer[SOUNDBUFLEN * 2]; + int16_t dsp_buffer[SOUNDBUFLEN * 2]; + + int pos; +} sb_t; + +static int sb_att[]= +{ + 310,368,437,520,618,735,873,1038,1234,1467,1743,2072,2463,2927,3479, + 4134,4914,5840,6941,8250,9805,11653,13850,16461,19564,23252,27635,32845, + 39036,46395,55140,65535 +}; + + + +static void sb_opl2_poll(void *p) +{ + sb_t *sb = (sb_t *)p; + + if (sb->pos >= SOUNDBUFLEN) return; + + opl2_poll(&sb->opl, &sb->opl_buffer[sb->pos * 2], &sb->opl_buffer[(sb->pos * 2) + 1]); + sb_dsp_poll(&sb->dsp, &sb->dsp_buffer[sb->pos * 2], &sb->dsp_buffer[(sb->pos * 2) + 1]); + sb->pos++; +} + +static void sb_opl3_poll(void *p) +{ + sb_t *sb = (sb_t *)p; + + if (sb->pos >= SOUNDBUFLEN) return; + + opl3_poll(&sb->opl, &sb->opl_buffer[sb->pos * 2], &sb->opl_buffer[(sb->pos * 2) + 1]); + sb_dsp_poll(&sb->dsp, &sb->dsp_buffer[sb->pos * 2], &sb->dsp_buffer[(sb->pos * 2) + 1]); + sb->pos++; +} + +static void sb_get_buffer(int16_t *buffer, int len, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_mixer_t *mixer = &sb->mixer; + + int c; + + for (c = 0; c < len * 2; c += 2) + { + int16_t out_l, out_r; + + out_l = ((sb->opl_buffer[c] * mixer->fm_l) >> 16); + out_r = ((sb->opl_buffer[c + 1] * mixer->fm_r) >> 16); + if (sb->mixer.filter) + { + out_l += (int)(((sb_iir(0, (float)sb->dsp_buffer[c]) / 1.3) * mixer->voice_l) / 3) >> 16; + out_r += (int)(((sb_iir(1, (float)sb->dsp_buffer[c + 1]) / 1.3) * mixer->voice_r) / 3) >> 16; + } + else + { + out_l += ((sb->dsp_buffer[c] * mixer->voice_l) / 3) >> 16; + out_r += ((sb->dsp_buffer[c + 1] * mixer->voice_r) / 3) >> 16; + } + + out_l = (out_l * mixer->master_l) >> 16; + out_r = (out_r * mixer->master_r) >> 16; + + if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8) + { + if (mixer->bass_l>8) out_l = (out_l + (((int16_t) low_iir(0, (float)out_l) * (mixer->bass_l - 8)) >> 1)) * ((15 - mixer->bass_l) + 16) >> 5; + if (mixer->bass_r>8) out_r = (out_r + (((int16_t) low_iir(1, (float)out_r) * (mixer->bass_r - 8)) >> 1)) * ((15 - mixer->bass_r) + 16) >> 5; + if (mixer->treble_l>8) out_l = (out_l + (((int16_t) high_iir(0, (float)out_l) * (mixer->treble_l - 8)) >> 1)) * ((15 - mixer->treble_l) + 16) >> 5; + if (mixer->treble_r>8) out_r = (out_r + (((int16_t) high_iir(1, (float)out_r) * (mixer->treble_r - 8)) >> 1)) * ((15 - mixer->treble_r) + 16) >> 5; + if (mixer->bass_l<8) out_l = (out_l + (((int16_t) low_cut_iir(0, (float)out_l) * (8 - mixer->bass_l)) >> 1)) * (mixer->bass_l + 16) >> 5; + if (mixer->bass_r<8) out_r = (out_r + (((int16_t) low_cut_iir(1, (float)out_r) * (8 - mixer->bass_r)) >> 1)) * (mixer->bass_r + 16) >> 5; + if (mixer->treble_l<8) out_l = (out_l + (((int16_t)high_cut_iir(0, (float)out_l) * (8 - mixer->treble_l)) >> 1)) * (mixer->treble_l + 16) >> 5; + if (mixer->treble_r<8) out_r = (out_r + (((int16_t)high_cut_iir(1, (float)out_r) * (8 - mixer->treble_r)) >> 1)) * (mixer->treble_r + 16) >> 5; + } + + buffer[c] += out_l; + buffer[c + 1] += out_r; + } + + sb->pos = 0; +} + + +void sb_pro_mixer_write(uint16_t addr, uint8_t val, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_mixer_t *mixer = &sb->mixer; + + if (!(addr & 1)) + mixer->index = val & 0xff; + else + { + mixer->regs[mixer->index] = val; + + mixer->master_l = sb_att[(mixer->regs[0x22] >> 4) | 0x11]; + mixer->master_r = sb_att[(mixer->regs[0x22] & 0xf) | 0x11]; + mixer->voice_l = sb_att[(mixer->regs[0x04] >> 4) | 0x11]; + mixer->voice_r = sb_att[(mixer->regs[0x04] & 0xf) | 0x11]; + mixer->fm_l = sb_att[(mixer->regs[0x26] >> 4) | 0x11]; + mixer->fm_r = sb_att[(mixer->regs[0x26] & 0xf) | 0x11]; + mixer->filter = !(mixer->regs[0xe] & 0x20); + mixer->bass_l = mixer->bass_r = 8; + mixer->treble_l = mixer->treble_r = 8; + pclog("%02X %02X %02X\n", mixer->regs[0x04], mixer->regs[0x22], mixer->regs[0x26]); + pclog("Mixer - %04X %04X %04X %04X %04X %04X\n", mixer->master_l, mixer->master_r, mixer->voice_l, mixer->voice_r, mixer->fm_l, mixer->fm_r); + if (mixer->index == 0xe) + sb_dsp_set_stereo(&sb->dsp, val & 2); + } +} + +uint8_t sb_pro_mixer_read(uint16_t addr, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_mixer_t *mixer = &sb->mixer; + + if (!(addr & 1)) + return mixer->index; + + return mixer->regs[mixer->index]; +} + +void sb_16_mixer_write(uint16_t addr, uint8_t val, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_mixer_t *mixer = &sb->mixer; + + if (!(addr & 1)) + mixer->index = val; + else + { + mixer->regs[mixer->index] = val; + switch (mixer->index) + { + case 0x22: + mixer->regs[0x30] = ((mixer->regs[0x22] >> 4) | 0x11) << 3; + mixer->regs[0x31] = ((mixer->regs[0x22] & 0xf) | 0x11) << 3; + break; + case 0x04: + mixer->regs[0x32] = ((mixer->regs[0x04] >> 4) | 0x11) << 3; + mixer->regs[0x33] = ((mixer->regs[0x04] & 0xf) | 0x11) << 3; + break; + case 0x26: + mixer->regs[0x34] = ((mixer->regs[0x26] >> 4) | 0x11) << 3; + mixer->regs[0x35] = ((mixer->regs[0x26] & 0xf) | 0x11) << 3; + break; + case 0x80: + if (val & 1) sb->dsp.sb_irqnum = 2; + if (val & 2) sb->dsp.sb_irqnum = 5; + if (val & 4) sb->dsp.sb_irqnum = 7; + if (val & 8) sb->dsp.sb_irqnum = 10; + break; + } + mixer->master_l = sb_att[mixer->regs[0x30] >> 3]; + mixer->master_r = sb_att[mixer->regs[0x31] >> 3]; + mixer->voice_l = sb_att[mixer->regs[0x32] >> 3]; + mixer->voice_r = sb_att[mixer->regs[0x33] >> 3]; + mixer->fm_l = sb_att[mixer->regs[0x34] >> 3]; + mixer->fm_r = sb_att[mixer->regs[0x35] >> 3]; + mixer->bass_l = mixer->regs[0x46] >> 4; + mixer->bass_r = mixer->regs[0x47] >> 4; + mixer->treble_l = mixer->regs[0x44] >> 4; + mixer->treble_r = mixer->regs[0x45] >> 4; + mixer->filter = 0; + pclog("%02X %02X %02X %02X %02X %02X\n", mixer->regs[0x30], mixer->regs[0x31], mixer->regs[0x32], mixer->regs[0x33], mixer->regs[0x34], mixer->regs[0x35]); + pclog("Mixer - %04X %04X %04X %04X %04X %04X\n", mixer->master_l, mixer->master_r, mixer->voice_l, mixer->voice_r, mixer->fm_l, mixer->fm_r); + } +} + +uint8_t sb_16_mixer_read(uint16_t addr, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_mixer_t *mixer = &sb->mixer; + + if (!(addr & 1)) + return mixer->index; + + switch (mixer->index) + { + case 0x80: + switch (sb->dsp.sb_irqnum) + { + case 2: return 1; /*IRQ 7*/ + case 5: return 2; /*IRQ 7*/ + case 7: return 4; /*IRQ 7*/ + case 10: return 8; /*IRQ 7*/ + } + break; + case 0x81: + return 0x22; /*DMA 1 and 5*/ + case 0x82: + return ((sb->dsp.sb_irq8) ? 1 : 0) | ((sb->dsp.sb_irq16) ? 2 : 0); + } + return mixer->regs[mixer->index]; +} + +void sb_mixer_init(sb_mixer_t *mixer) +{ + mixer->master_l = mixer->master_r = 65535; + mixer->voice_l = mixer->voice_r = 65535; + mixer->fm_l = mixer->fm_r = 65535; + mixer->bass_l = mixer->bass_r = 8; + mixer->treble_l = mixer->treble_r = 8; + mixer->filter = 1; +} + +void *sb_1_init() +{ + sb_t *sb = malloc(sizeof(sb_t)); + memset(sb, 0, sizeof(sb_t)); + + opl2_init(&sb->opl); + sb_dsp_init(&sb->dsp, SB1); + sb_dsp_setaddr(&sb->dsp, 0x0220); + sb_mixer_init(&sb->mixer); + io_sethandler(0x0228, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + sound_add_handler(sb_opl2_poll, sb_get_buffer, sb); + return sb; +} +void *sb_15_init() +{ + sb_t *sb = malloc(sizeof(sb_t)); + memset(sb, 0, sizeof(sb_t)); + + opl2_init(&sb->opl); + sb_dsp_init(&sb->dsp, SB15); + sb_dsp_setaddr(&sb->dsp, 0x0220); + sb_mixer_init(&sb->mixer); + io_sethandler(0x0228, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + sound_add_handler(sb_opl2_poll, sb_get_buffer, sb); + return sb; +} +void *sb_2_init() +{ + sb_t *sb = malloc(sizeof(sb_t)); + memset(sb, 0, sizeof(sb_t)); + + opl2_init(&sb->opl); + sb_dsp_init(&sb->dsp, SB2); + sb_dsp_setaddr(&sb->dsp, 0x0220); + sb_mixer_init(&sb->mixer); + io_sethandler(0x0228, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + sound_add_handler(sb_opl2_poll, sb_get_buffer, sb); + return sb; +} + +void *sb_pro_v1_init() +{ + sb_t *sb = malloc(sizeof(sb_t)); + memset(sb, 0, sizeof(sb_t)); + + opl2_init(&sb->opl); + sb_dsp_init(&sb->dsp, SBPRO); + sb_dsp_setaddr(&sb->dsp, 0x0220); + sb_mixer_init(&sb->mixer); + io_sethandler(0x0220, 0x0002, opl2_l_read, NULL, NULL, opl2_l_write, NULL, NULL, &sb->opl); + io_sethandler(0x0222, 0x0002, opl2_r_read, NULL, NULL, opl2_r_write, NULL, NULL, &sb->opl); + io_sethandler(0x0228, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_sethandler(0x0224, 0x0002, sb_pro_mixer_read, NULL, NULL, sb_pro_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_opl2_poll, sb_get_buffer, sb); + + sb->mixer.regs[0x22] = 0xff; + sb->mixer.regs[0x04] = 0xff; + sb->mixer.regs[0x26] = 0xff; + sb->mixer.regs[0xe] = 0; + + return sb; +} + +void *sb_pro_v2_init() +{ + sb_t *sb = malloc(sizeof(sb_t)); + memset(sb, 0, sizeof(sb_t)); + + opl3_init(&sb->opl); + sb_dsp_init(&sb->dsp, SBPRO2); + sb_dsp_setaddr(&sb->dsp, 0x0220); + sb_mixer_init(&sb->mixer); + io_sethandler(0x0220, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0228, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0224, 0x0002, sb_pro_mixer_read, NULL, NULL, sb_pro_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_opl3_poll, sb_get_buffer, sb); + + sb->mixer.regs[0x22] = 0xff; + sb->mixer.regs[0x04] = 0xff; + sb->mixer.regs[0x26] = 0xff; + sb->mixer.regs[0xe] = 0; + + return sb; +} + +void *sb_16_init() +{ + sb_t *sb = malloc(sizeof(sb_t)); + memset(sb, 0, sizeof(sb_t)); + + opl3_init(&sb->opl); + sb_dsp_init(&sb->dsp, SB16); + sb_dsp_setaddr(&sb->dsp, 0x0220); + sb_mixer_init(&sb->mixer); + io_sethandler(0x0220, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0228, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0224, 0x0002, sb_16_mixer_read, NULL, NULL, sb_16_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_opl3_poll, sb_get_buffer, sb); + + sb->mixer.regs[0x30] = 31 << 3; + sb->mixer.regs[0x31] = 31 << 3; + sb->mixer.regs[0x32] = 31 << 3; + sb->mixer.regs[0x33] = 31 << 3; + sb->mixer.regs[0x34] = 31 << 3; + sb->mixer.regs[0x35] = 31 << 3; + sb->mixer.regs[0x44] = 8 << 4; + sb->mixer.regs[0x45] = 8 << 4; + sb->mixer.regs[0x46] = 8 << 4; + sb->mixer.regs[0x47] = 8 << 4; + sb->mixer.regs[0x22] = (sb->mixer.regs[0x30] & 0xf0) | (sb->mixer.regs[0x31] >> 4); + sb->mixer.regs[0x04] = (sb->mixer.regs[0x32] & 0xf0) | (sb->mixer.regs[0x33] >> 4); + sb->mixer.regs[0x26] = (sb->mixer.regs[0x34] & 0xf0) | (sb->mixer.regs[0x35] >> 4); + + return sb; +} + +void sb_close(void *p) +{ + sb_t *sb = (sb_t *)p; + + free(sb); +} + +void sb_speed_changed(void *p) +{ + sb_t *sb = (sb_t *)p; + + sb_dsp_speed_changed(&sb->dsp); +} + +device_t sb_1_device = +{ + "Sound Blaster v1.0", + sb_1_init, + sb_close, + sb_speed_changed +}; +device_t sb_15_device = +{ + "Sound Blaster v1.5", + sb_15_init, + sb_close, + sb_speed_changed +}; +device_t sb_2_device = +{ + "Sound Blaster v2.0", + sb_2_init, + sb_close, + sb_speed_changed +}; +device_t sb_pro_v1_device = +{ + "Sound Blaster Pro v1", + sb_pro_v1_init, + sb_close, + sb_speed_changed +}; +device_t sb_pro_v2_device = +{ + "Sound Blaster Pro v2", + sb_pro_v2_init, + sb_close, + sb_speed_changed +}; +device_t sb_16_device = +{ + "Sound Blaster 16", + sb_16_init, + sb_close, + sb_speed_changed +}; diff --git a/src/sound_sb.h b/src/sound_sb.h new file mode 100644 index 0000000..087d362 --- /dev/null +++ b/src/sound_sb.h @@ -0,0 +1,6 @@ +extern device_t sb_1_device; +extern device_t sb_15_device; +extern device_t sb_2_device; +extern device_t sb_pro_v1_device; +extern device_t sb_pro_v2_device; +extern device_t sb_16_device; diff --git a/src/sound_sb_dsp.c b/src/sound_sb_dsp.c new file mode 100644 index 0000000..05b657a --- /dev/null +++ b/src/sound_sb_dsp.c @@ -0,0 +1,908 @@ +/*Jazz sample rates : + 386-33 - 12kHz + 486-33 - 20kHz + 486-50 - 32kHz + Pentium - 45kHz*/ + +#include +#include +#include "ibm.h" + + +#include "dma.h" +#include "io.h" +#include "pic.h" +#include "sound.h" +#include "sound_sb_dsp.h" +#include "timer.h" + +void pollsb(void *p); +void sb_poll_i(void *p); + + + +static int sbe2dat[4][9] = { + { 0x01, -0x02, -0x04, 0x08, -0x10, 0x20, 0x40, -0x80, -106 }, + { -0x01, 0x02, -0x04, 0x08, 0x10, -0x20, 0x40, -0x80, 165 }, + { -0x01, 0x02, 0x04, -0x08, 0x10, -0x20, -0x40, 0x80, -151 }, + { 0x01, -0x02, 0x04, -0x08, -0x10, 0x20, -0x40, 0x80, 90 } +}; + +static int sb_commands[256]= +{ + -1,-1,-1,-1, 1, 2,-1, 0, 1,-1,-1,-1,-1,-1, 2, 1, + 1,-1,-1,-1, 2,-1, 2, 2,-1,-1,-1,-1, 0,-1,-1, 0, + 0,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1,-1, 0,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 1, 2, 2,-1,-1,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1, 2, 2, 2, 2,-1,-1,-1,-1,-1, 0,-1, 0, + 2, 2,-1,-1,-1,-1,-1,-1, 2, 2,-1,-1,-1,-1,-1,-1, + 0,-1,-1,-1,-1,-1,-1,-1, 0,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 0, 0,-1, 0, 0, 0, 0,-1, 0, 0, 0,-1,-1,-1,-1,-1, + 1, 0, 1, 0, 1,-1,-1, 0, 0,-1,-1,-1,-1,-1,-1,-1, + -1,-1, 0,-1,-1,-1,-1,-1,-1, 1, 2,-1,-1,-1,-1, 0 +}; + +char sb16_copyright[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992."; +uint16_t sb_dsp_versions[] = {0, 0, 0x105, 0x200, 0x201, 0x300, 0x302, 0x405}; + +/*These tables were 'borrowed' from DOSBox*/ + int8_t scaleMap4[64] = { + 0, 1, 2, 3, 4, 5, 6, 7, 0, -1, -2, -3, -4, -5, -6, -7, + 1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, -11, -13, -15, + 2, 6, 10, 14, 18, 22, 26, 30, -2, -6, -10, -14, -18, -22, -26, -30, + 4, 12, 20, 28, 36, 44, 52, 60, -4, -12, -20, -28, -36, -44, -52, -60 + }; + uint8_t adjustMap4[64] = { + 0, 0, 0, 0, 0, 16, 16, 16, + 0, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 0, 0, 0, + 240, 0, 0, 0, 0, 0, 0, 0 + }; + + int8_t scaleMap26[40] = { + 0, 1, 2, 3, 0, -1, -2, -3, + 1, 3, 5, 7, -1, -3, -5, -7, + 2, 6, 10, 14, -2, -6, -10, -14, + 4, 12, 20, 28, -4, -12, -20, -28, + 5, 15, 25, 35, -5, -15, -25, -35 + }; + uint8_t adjustMap26[40] = { + 0, 0, 0, 8, 0, 0, 0, 8, + 248, 0, 0, 8, 248, 0, 0, 8, + 248, 0, 0, 8, 248, 0, 0, 8, + 248, 0, 0, 8, 248, 0, 0, 8, + 248, 0, 0, 0, 248, 0, 0, 0 + }; + + int8_t scaleMap2[24] = { + 0, 1, 0, -1, 1, 3, -1, -3, + 2, 6, -2, -6, 4, 12, -4, -12, + 8, 24, -8, -24, 6, 48, -16, -48 + }; + uint8_t adjustMap2[24] = { + 0, 4, 0, 4, + 252, 4, 252, 4, 252, 4, 252, 4, + 252, 4, 252, 4, 252, 4, 252, 4, + 252, 0, 252, 0 + }; + + + +void sb_irq(sb_dsp_t *dsp, int irq8) +{ +// pclog("IRQ %i %02X\n",irq8,pic.mask); + if (irq8) dsp->sb_irq8 = 1; + else dsp->sb_irq16 = 1; + picint(1 << dsp->sb_irqnum); +} +void sb_irqc(sb_dsp_t *dsp, int irq8) +{ + if (irq8) dsp->sb_irq8 = 0; + else dsp->sb_irq16 = 0; + picintc(1 << dsp->sb_irqnum); +} + +void sb_dsp_reset(sb_dsp_t *dsp) +{ + dsp->sbenable = dsp->sb_enable_i = 0; + dsp->sb_command = 0; + + dsp->sb_8_length = 0xffff; + + sb_irqc(dsp, 0); + sb_irqc(dsp, 1); + dsp->sb_16_pause = 0; + dsp->sb_read_wp = dsp->sb_read_rp = 0; + dsp->sb_data_stat = -1; + dsp->sb_speaker = 0; + dsp->sb_pausetime = -1; + dsp->sbe2 = 0xAA; + dsp->sbe2count = 0; + + dsp->sbreset = 0; + dsp->sbenable = dsp->sb_enable_i = dsp->sb_count_i = 0; + + picintc(1 << dsp->sb_irqnum); +} + +void sb_doreset(sb_dsp_t *dsp) +{ + int c; + + sb_dsp_reset(dsp); + + if (dsp->sb_type==SB16) sb_commands[8] = 1; + else sb_commands[8] = -1; + + for (c = 0; c < 256; c++) + dsp->sb_asp_regs[c] = 0; + dsp->sb_asp_regs[5] = 0x01; + dsp->sb_asp_regs[9] = 0xf8; +} + +void sb_dsp_speed_changed(sb_dsp_t *dsp) +{ + if (dsp->sb_timeo < 256) + dsp->sblatcho = TIMER_USEC * (256 - dsp->sb_timeo); + else + dsp->sblatcho = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timeo - 256))); + + if (dsp->sb_timei < 256) + dsp->sblatchi = TIMER_USEC * (256 - dsp->sb_timei); + else + dsp->sblatchi = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timei - 256))); +} + +void sb_add_data(sb_dsp_t *dsp, uint8_t v) +{ + dsp->sb_read_data[dsp->sb_read_wp++] = v; + dsp->sb_read_wp &= 0xff; +} + +#define ADPCM_4 1 +#define ADPCM_26 2 +#define ADPCM_2 3 + +void sb_start_dma(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len) +{ + if (dma8) + { + dsp->sb_8_length = len; + dsp->sb_8_format = format; + dsp->sb_8_autoinit = autoinit; + dsp->sb_8_pause = 0; + dsp->sb_8_enable = 1; + if (dsp->sb_16_enable && dsp->sb_16_output) dsp->sb_16_enable = 0; + dsp->sb_8_output = 1; + timer_process(); + dsp->sbenable = dsp->sb_8_enable; + timer_update_outstanding(); + dsp->sbleftright = 0; + dsp->sbdacpos = 0; +// pclog("Start 8-bit DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len); + } + else + { + dsp->sb_16_length = len; + dsp->sb_16_format = format; + dsp->sb_16_autoinit = autoinit; + dsp->sb_16_pause = 0; + dsp->sb_16_enable = 1; + if (dsp->sb_8_enable && dsp->sb_8_output) dsp->sb_8_enable = 0; + dsp->sb_16_output = 1; + timer_process(); + dsp->sbenable = dsp->sb_16_enable; + timer_update_outstanding(); +// pclog("Start 16-bit DMA addr %06X len %04X\n",dma16.ac[1]+(dma16.page[1]<<16),len); + } +} + +void sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len) +{ + if (dma8) + { + dsp->sb_8_length = len; + dsp->sb_8_format = format; + dsp->sb_8_autoinit = autoinit; + dsp->sb_8_pause = 0; + dsp->sb_8_enable = 1; + if (dsp->sb_16_enable && !dsp->sb_16_output) dsp->sb_16_enable = 0; + dsp->sb_8_output = 0; + timer_process(); + dsp->sb_enable_i = dsp->sb_8_enable; + timer_update_outstanding(); +// pclog("Start 8-bit input DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len); + } + else + { + dsp->sb_16_length = len; + dsp->sb_16_format = format; + dsp->sb_16_autoinit = autoinit; + dsp->sb_16_pause = 0; + dsp->sb_16_enable = 1; + if (dsp->sb_8_enable && !dsp->sb_8_output) dsp->sb_8_enable = 0; + dsp->sb_16_output = 0; + timer_process(); + dsp->sb_enable_i = dsp->sb_16_enable; + timer_update_outstanding(); +// pclog("Start 16-bit input DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len); + } +} + +int sb_8_read_dma(sb_dsp_t *dsp) +{ + return dma_channel_read(dsp->sb_8_dmanum); +} +void sb_8_write_dma(sb_dsp_t *dsp, uint8_t val) +{ + dma_channel_write(dsp->sb_8_dmanum, val); +} +uint16_t sb_16_read_dma(sb_dsp_t *dsp) +{ + return dma_channel_read(5); +} +void sb_16_write_dma(sb_dsp_t *dsp, uint16_t val) +{ + dma_channel_write(5, val); +} + +void sb_dsp_setirq(sb_dsp_t *dsp, int irq) +{ + dsp->sb_irqnum = irq; +} + +void sb_dsp_setdma8(sb_dsp_t *dsp, int dma) +{ + dsp->sb_8_dmanum = dma; +} + +void sb_exec_command(sb_dsp_t *dsp) +{ + int temp,c; + pclog("sb_exec_command : SB command %02X\n", dsp->sb_command); + switch (dsp->sb_command) + { + case 0x10: /*8-bit direct mode*/ + dsp->sbdat = dsp->sbdatl = dsp->sbdatr = (dsp->sb_data[0] ^ 0x80) << 8; + break; + case 0x14: /*8-bit single cycle DMA output*/ + sb_start_dma(dsp, 1, 0, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + break; + case 0x17: /*2-bit ADPCM output with reference*/ + dsp->sbref = sb_8_read_dma(dsp); + dsp->sbstep = 0; +// pclog("Ref byte 2 %02X\n",sbref); + case 0x16: /*2-bit ADPCM output*/ + sb_start_dma(dsp, 1, 0, ADPCM_2, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + break; + case 0x1C: /*8-bit autoinit DMA output*/ + if (dsp->sb_type < SB15) break; + sb_start_dma(dsp, 1, 1, 0, dsp->sb_8_autolen); + break; + case 0x1F: /*2-bit ADPCM autoinit output*/ + if (dsp->sb_type < SB15) break; + sb_start_dma(dsp, 1, 1, ADPCM_2, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + break; + case 0x20: /*8-bit direct input*/ + sb_add_data(dsp, 0); + break; + case 0x24: /*8-bit single cycle DMA input*/ + sb_start_dma_i(dsp, 1, 0, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + break; + case 0x2C: /*8-bit autoinit DMA input*/ + if (dsp->sb_type < SB15) break; + sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + break; + case 0x40: /*Set time constant*/ + dsp->sb_timei = dsp->sb_timeo = dsp->sb_data[0]; + dsp->sblatcho = dsp->sblatchi = TIMER_USEC * (256 - dsp->sb_data[0]); + temp = 256 - dsp->sb_data[0]; + temp = 1000000 / temp; +// printf("Sample rate - %ihz (%i)\n",temp, sblatcho); + dsp->sb_freq = temp; + break; + case 0x41: /*Set output sampling rate*/ + if (dsp->sb_type < SB16) break; + dsp->sblatcho = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_data[1] + (dsp->sb_data[0] << 8)))); +// printf("Sample rate - %ihz (%i)\n",sb_data[1]+(sb_data[0]<<8), sblatcho); + dsp->sb_freq = dsp->sb_data[1] + (dsp->sb_data[0] << 8); + dsp->sb_timeo = 256 + dsp->sb_freq; + break; + case 0x42: /*Set input sampling rate*/ + if (dsp->sb_type < SB16) break; + dsp->sblatchi = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_data[1] + (dsp->sb_data[0] << 8)))); +// printf("iample rate - %ihz\n",sb_data[1]+(sb_data[0]<<8)); + dsp->sb_timei = 256 + dsp->sb_data[1] + (dsp->sb_data[0] << 8); + break; + case 0x48: /*Set DSP block transfer size*/ + dsp->sb_8_autolen = dsp->sb_data[0] + (dsp->sb_data[1] << 8); + break; + case 0x75: /*4-bit ADPCM output with reference*/ + dsp->sbref = sb_8_read_dma(dsp); + dsp->sbstep = 0; +// pclog("Ref byte 4 %02X\n",sbref); + case 0x74: /*4-bit ADPCM output*/ + sb_start_dma(dsp, 1, 0, ADPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + break; + case 0x77: /*2.6-bit ADPCM output with reference*/ + dsp->sbref = sb_8_read_dma(dsp); + dsp->sbstep = 0; +// pclog("Ref byte 26 %02X\n",sbref); + case 0x76: /*2.6-bit ADPCM output*/ + sb_start_dma(dsp, 1, 0, ADPCM_26, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + break; + case 0x7D: /*4-bit ADPCM autoinit output*/ + if (dsp->sb_type < SB15) break; + sb_start_dma(dsp, 1, 1, ADPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + break; + case 0x7F: /*2.6-bit ADPCM autoinit output*/ + if (dsp->sb_type < SB15) break; + sb_start_dma(dsp, 1, 1, ADPCM_26, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + break; + case 0x80: /*Pause DAC*/ + dsp->sb_pausetime = dsp->sb_data[0] + (dsp->sb_data[1] << 8); +// pclog("SB pause %04X\n",sb_pausetime); + timer_process(); + dsp->sbenable = 1; + timer_update_outstanding(); + break; + case 0x90: /*High speed 8-bit autoinit DMA output*/ + if (dsp->sb_type < SB2) break; + sb_start_dma(dsp, 1, 1, 0, dsp->sb_8_autolen); + break; + case 0x91: /*High speed 8-bit single cycle DMA output*/ + if (dsp->sb_type < SB2) break; + sb_start_dma(dsp, 1, 0, 0, dsp->sb_8_autolen); + break; + case 0x98: /*High speed 8-bit autoinit DMA input*/ + if (dsp->sb_type < SB2) break; + sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_8_autolen); + break; + case 0x99: /*High speed 8-bit single cycle DMA input*/ + if (dsp->sb_type < SB2) break; + sb_start_dma_i(dsp, 1, 0, 0, dsp->sb_8_autolen); + break; + case 0xA0: /*Set input mode to mono*/ + case 0xA8: /*Set input mode to stereo*/ + break; + case 0xB0: case 0xB1: case 0xB2: case 0xB3: + case 0xB4: case 0xB5: case 0xB6: case 0xB7: /*16-bit DMA output*/ + if (dsp->sb_type < SB16) break; + sb_start_dma(dsp, 0, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); + dsp->sb_16_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); + break; + case 0xB8: case 0xB9: case 0xBA: case 0xBB: + case 0xBC: case 0xBD: case 0xBE: case 0xBF: /*16-bit DMA input*/ + if (dsp->sb_type < SB16) break; + sb_start_dma_i(dsp, 0, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); + dsp->sb_16_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); + break; + case 0xC0: case 0xC1: case 0xC2: case 0xC3: + case 0xC4: case 0xC5: case 0xC6: case 0xC7: /*8-bit DMA output*/ + if (dsp->sb_type < SB16) break; + sb_start_dma(dsp, 1, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); + dsp->sb_8_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); + break; + case 0xC8: case 0xC9: case 0xCA: case 0xCB: + case 0xCC: case 0xCD: case 0xCE: case 0xCF: /*8-bit DMA input*/ + if (dsp->sb_type < SB16) break; + sb_start_dma_i(dsp, 1, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); + dsp->sb_8_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); + break; + case 0xD0: /*Pause 8-bit DMA*/ + dsp->sb_8_pause = 1; + break; + case 0xD1: /*Speaker on*/ + dsp->sb_speaker = 1; + break; + case 0xD3: /*Speaker off*/ + dsp->sb_speaker = 0; + break; + case 0xD4: /*Continue 8-bit DMA*/ + dsp->sb_8_pause = 0; + break; + case 0xD5: /*Pause 16-bit DMA*/ + if (dsp->sb_type < SB16) break; + dsp->sb_16_pause = 1; + break; + case 0xD6: /*Continue 16-bit DMA*/ + if (dsp->sb_type < SB16) break; + dsp->sb_16_pause = 0; + break; + case 0xD8: /*Get speaker status*/ + sb_add_data(dsp, dsp->sb_speaker ? 0xff : 0); + break; + case 0xD9: /*Exit 16-bit auto-init mode*/ + if (dsp->sb_type < SB16) break; + dsp->sb_16_autoinit = 0; + break; + case 0xDA: /*Exit 8-bit auto-init mode*/ + dsp->sb_8_autoinit = 0; + break; + case 0xE0: /*DSP identification*/ + sb_add_data(dsp, ~dsp->sb_data[0]); + break; + case 0xE1: /*Get DSP version*/ + sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] >> 8); + sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] & 0xff); + break; + case 0xE2: /*Stupid ID/protection*/ + for (c = 0; c < 8; c++) + if (dsp->sb_data[0] & (1 << c)) dsp->sbe2 += sbe2dat[dsp->sbe2count & 3][c]; + dsp->sbe2 += sbe2dat[dsp->sbe2count & 3][8]; + dsp->sbe2count++; + sb_8_write_dma(dsp, dsp->sbe2); + break; + case 0xE3: /*DSP copyright*/ + if (dsp->sb_type < SB16) break; + c = 0; + while (sb16_copyright[c]) + sb_add_data(dsp, sb16_copyright[c++]); + sb_add_data(dsp, 0); + break; + case 0xE4: /*Write test register*/ + dsp->sb_test = dsp->sb_data[0]; + break; + case 0xE8: /*Read test register*/ + sb_add_data(dsp, dsp->sb_test); + break; + case 0xF2: /*Trigger 8-bit IRQ*/ +// pclog("Trigger IRQ\n"); + sb_irq(dsp, 1); + break; + case 0xE7: /*???*/ + case 0xFA: /*???*/ + break; + case 0x07: /*No, that's not how you program auto-init DMA*/ + case 0xFF: + break; + case 0x08: /*ASP get version*/ + if (dsp->sb_type < SB16) break; + sb_add_data(dsp, 0x18); + break; + case 0x0E: /*ASP set register*/ + if (dsp->sb_type < SB16) break; + dsp->sb_asp_regs[dsp->sb_data[0]] = dsp->sb_data[1]; +// pclog("ASP write reg %02X %02X\n", sb_data[0], sb_data[1]); + break; + case 0x0F: /*ASP get register*/ + if (dsp->sb_type < SB16) break; +// sb_add_data(0); + sb_add_data(dsp, dsp->sb_asp_regs[dsp->sb_data[0]]); +// pclog("ASP read reg %02X %02X\n", sb_data[0], sb_asp_regs[sb_data[0]]); + break; + case 0xF9: + if (dsp->sb_type < SB16) break; + if (dsp->sb_data[0] == 0x0e) sb_add_data(dsp, 0xff); + else if (dsp->sb_data[0] == 0x0f) sb_add_data(dsp, 0x07); + else if (dsp->sb_data[0] == 0x37) sb_add_data(dsp, 0x38); + else sb_add_data(dsp, 0x00); + case 0x04: + case 0x05: + break; +// default: +// fatal("Exec bad SB command %02X\n",sb_command); + } +} + +void sb_write(uint16_t a, uint8_t v, void *priv) +{ + sb_dsp_t *dsp = (sb_dsp_t *)priv; + printf("sb_write : Write soundblaster %04X %02X %04X:%04X %02X\n",a,v,CS,pc,dsp->sb_command); + switch (a&0xF) + { + case 6: /*Reset*/ + if (!(v & 1) && (dsp->sbreset & 1)) + { + sb_dsp_reset(dsp); + sb_add_data(dsp, 0xAA); + } + dsp->sbreset = v; + return; + case 0xC: /*Command/data write*/ + if (dsp->sb_data_stat == -1) + { + dsp->sb_command = v; +// if (sb_commands[v]==-1) +// fatal("Bad SB command %02X\n",v); + dsp->sb_data_stat++; + } + else + dsp->sb_data[dsp->sb_data_stat++] = v; + if (dsp->sb_data_stat == sb_commands[dsp->sb_command] || sb_commands[dsp->sb_command] == -1) + { + sb_exec_command(dsp); + dsp->sb_data_stat = -1; + } + break; + } +} + +uint8_t sb_read(uint16_t a, void *priv) +{ + sb_dsp_t *dsp = (sb_dsp_t *)priv; +// if (a==0x224) output=1; + pclog("sb_read : Read soundblaster %04X %04X:%04X\n",a,CS,pc); + switch (a & 0xf) + { + case 0xA: /*Read data*/ + dsp->sbreaddat = dsp->sb_read_data[dsp->sb_read_rp]; + if (dsp->sb_read_rp != dsp->sb_read_wp) + { + dsp->sb_read_rp++; + dsp->sb_read_rp &= 0xFF; + } +// pclog("SB read %02X\n",sbreaddat); + return dsp->sbreaddat; + case 0xC: /*Write data ready*/ + cycles -= 100; + dsp->writebusy++; + if (dsp->writebusy & 8) return 0xff; + return 0x7f; + case 0xE: /*Read data ready*/ + picintc(1 << dsp->sb_irqnum); + dsp->sb_irq8 = dsp->sb_irq16 = 0; + return (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7f : 0xff; + case 0xF: /*16-bit ack*/ + dsp->sb_irq16 = 0; + if (!dsp->sb_irq8) picintc(1 << dsp->sb_irqnum); + return 0xff; + } + return 0; +} + +void sb_dsp_init(sb_dsp_t *dsp, int type) +{ + dsp->sb_type = type; + + dsp->sb_irqnum = 7; + dsp->sb_8_dmanum = 1; + + sb_doreset(dsp); + + timer_add(pollsb, &dsp->sbcount, &dsp->sbenable, dsp); + timer_add(sb_poll_i, &dsp->sb_count_i, &dsp->sb_enable_i, dsp); +} + +void sb_dsp_setaddr(sb_dsp_t *dsp, uint16_t addr) +{ + pclog("sb_dsp_setaddr : %04X\n", addr); + io_removehandler(dsp->sb_addr + 6, 0x0002, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + io_removehandler(dsp->sb_addr + 0xa, 0x0006, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + dsp->sb_addr = addr; + if (dsp->sb_addr != 0) + { + io_sethandler(dsp->sb_addr + 6, 0x0002, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + io_sethandler(dsp->sb_addr + 0xa, 0x0006, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + } +} + +void sb_dsp_set_stereo(sb_dsp_t *dsp, int stereo) +{ + dsp->stereo = stereo; +} + +void pollsb(void *p) +{ + sb_dsp_t *dsp = (sb_dsp_t *)p; + int tempi,ref; + + dsp->sbcount += dsp->sblatcho; +// pclog("PollSB %i %i %i %i\n",sb_8_enable,sb_8_pause,sb_pausetime,sb_8_output); + if (dsp->sb_8_enable && !dsp->sb_8_pause && dsp->sb_pausetime < 0 && dsp->sb_8_output) + { + int data[2]; +// pclog("Dopoll %i %02X %i\n", sb_8_length, sb_8_format, sblatcho); + switch (dsp->sb_8_format) + { + case 0x00: /*Mono unsigned*/ + data[0] = sb_8_read_dma(dsp); + /*Needed to prevent clicking in Worms, which programs the DSP to + auto-init DMA but programs the DMA controller to single cycle*/ + if (data[0] == DMA_NODATA) + break; + dsp->sbdat = (data[0] ^ 0x80) << 8; + if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) + { + if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; + else dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } + else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + dsp->sb_8_length--; + break; + case 0x10: /*Mono signed*/ + data[0] = sb_8_read_dma(dsp); + if (data[0] == DMA_NODATA) + break; + dsp->sbdat = data[0] << 8; + if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) + { + if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; + else dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } + else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + dsp->sb_8_length--; + break; + case 0x20: /*Stereo unsigned*/ + data[0] = sb_8_read_dma(dsp); + data[1] = sb_8_read_dma(dsp); + if (data[0] == DMA_NODATA || data[1] == DMA_NODATA) + break; + dsp->sbdatl = (data[0] ^ 0x80) << 8; + dsp->sbdatr = (data[1] ^ 0x80) << 8; + dsp->sb_8_length -= 2; + break; + case 0x30: /*Stereo signed*/ + data[0] = sb_8_read_dma(dsp); + data[1] = sb_8_read_dma(dsp); + if (data[0] == DMA_NODATA || data[1] == DMA_NODATA) + break; + dsp->sbdatl = data[0] << 8; + dsp->sbdatr = data[1] << 8; + dsp->sb_8_length -= 2; + break; + + case ADPCM_4: + if (dsp->sbdacpos) tempi = (dsp->sbdat2 & 0xF) + dsp->sbstep; + else tempi = (dsp->sbdat2 >> 4) + dsp->sbstep; + if (tempi < 0) tempi = 0; + if (tempi > 63) tempi = 63; + + ref = dsp->sbref + scaleMap4[tempi]; + if (ref > 0xff) dsp->sbref = 0xff; + else if (ref < 0x00) dsp->sbref = 0x00; + else dsp->sbref = ref; + + dsp->sbstep = (dsp->sbstep + adjustMap4[tempi]) & 0xff; + + dsp->sbdat = (dsp->sbref ^ 0x80) << 8; + + dsp->sbdacpos++; + if (dsp->sbdacpos >= 2) + { + dsp->sbdacpos = 0; + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + } + + if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) + { + if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; + else dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } + else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + break; + + case ADPCM_26: + if (!dsp->sbdacpos) tempi = (dsp->sbdat2 >> 5) + dsp->sbstep; + else if (dsp->sbdacpos == 1) tempi = ((dsp->sbdat2 >> 2) & 7) + dsp->sbstep; + else tempi = ((dsp->sbdat2 << 1) & 7) + dsp->sbstep; + + if (tempi < 0) tempi = 0; + if (tempi > 39) tempi = 39; + + ref = dsp->sbref + scaleMap26[tempi]; + if (ref > 0xff) dsp->sbref = 0xff; + else if (ref < 0x00) dsp->sbref = 0x00; + else dsp->sbref = ref; + dsp->sbstep = (dsp->sbstep + adjustMap26[tempi]) & 0xff; + + dsp->sbdat = (dsp->sbref ^ 0x80) << 8; + + dsp->sbdacpos++; + if (dsp->sbdacpos>=3) + { + dsp->sbdacpos = 0; + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + } + + if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) + { + if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; + else dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } + else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + break; + + case ADPCM_2: + tempi = ((dsp->sbdat2 >> ((3 - dsp->sbdacpos) * 2)) & 3) + dsp->sbstep; + if (tempi < 0) tempi = 0; + if (tempi > 23) tempi = 23; + + ref = dsp->sbref + scaleMap2[tempi]; + if (ref > 0xff) dsp->sbref = 0xff; + else if (ref < 0x00) dsp->sbref = 0x00; + else dsp->sbref = ref; + dsp->sbstep = (dsp->sbstep + adjustMap2[tempi]) & 0xff; + + dsp->sbdat = (dsp->sbref ^ 0x80) << 8; + + dsp->sbdacpos++; + if (dsp->sbdacpos >= 4) + { + dsp->sbdacpos = 0; + dsp->sbdat2 = sb_8_read_dma(dsp); + } + + if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) + { + if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; + else dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } + else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + break; + +// default: + //fatal("Unrecognised SB 8-bit format %02X\n",sb_8_format); + } + + if (dsp->sb_8_length < 0) + { + if (dsp->sb_8_autoinit) dsp->sb_8_length = dsp->sb_8_autolen; + else dsp->sb_8_enable = dsp->sbenable=0; + sb_irq(dsp, 1); + } + } + if (dsp->sb_16_enable && !dsp->sb_16_pause && dsp->sb_pausetime < 0 && dsp->sb_16_output) + { + switch (dsp->sb_16_format) + { + case 0x00: /*Mono unsigned*/ + dsp->sbdatl = dsp->sbdatr = sb_16_read_dma(dsp) ^ 0x8000; + dsp->sb_16_length--; + break; + case 0x10: /*Mono signed*/ + dsp->sbdatl = dsp->sbdatr = sb_16_read_dma(dsp); + dsp->sb_16_length--; + break; + case 0x20: /*Stereo unsigned*/ + dsp->sbdatl = sb_16_read_dma(dsp) ^ 0x8000; + dsp->sbdatr = sb_16_read_dma(dsp) ^ 0x8000; + dsp->sb_16_length -= 2; + break; + case 0x30: /*Stereo signed*/ + dsp->sbdatl = sb_16_read_dma(dsp); + dsp->sbdatr = sb_16_read_dma(dsp); + dsp->sb_16_length -= 2; + break; + +// default: +// fatal("Unrecognised SB 16-bit format %02X\n",sb_16_format); + } + + if (dsp->sb_16_length < 0) + { +// pclog("16DMA over %i\n",sb_16_autoinit); + if (dsp->sb_16_autoinit) dsp->sb_16_length = dsp->sb_16_autolen; + else dsp->sb_16_enable = dsp->sbenable = 0; + sb_irq(dsp, 0); + } + } + if (dsp->sb_pausetime > -1) + { + dsp->sb_pausetime--; + if (dsp->sb_pausetime < 0) + { + sb_irq(dsp, 1); + dsp->sbenable = dsp->sb_8_enable; + pclog("SB pause over\n"); + } + } +} + +void sb_poll_i(void *p) +{ + sb_dsp_t *dsp = (sb_dsp_t *)p; + + dsp->sb_count_i += dsp->sblatchi; +// pclog("PollSBi %i %i %i %i\n",sb_8_enable,sb_8_pause,sb_pausetime,sb_8_output); + if (dsp->sb_8_enable && !dsp->sb_8_pause && dsp->sb_pausetime < 0 && !dsp->sb_8_output) + { + switch (dsp->sb_8_format) + { + case 0x00: /*Mono unsigned*/ + sb_8_write_dma(dsp, 0x80); + dsp->sb_8_length--; + break; + case 0x10: /*Mono signed*/ + sb_8_write_dma(dsp, 0x00); + dsp->sb_8_length--; + break; + case 0x20: /*Stereo unsigned*/ + sb_8_write_dma(dsp, 0x80); + sb_8_write_dma(dsp, 0x80); + dsp->sb_8_length -= 2; + break; + case 0x30: /*Stereo signed*/ + sb_8_write_dma(dsp, 0x00); + sb_8_write_dma(dsp, 0x00); + dsp->sb_8_length -= 2; + break; + +// default: +// fatal("Unrecognised SB 8-bit input format %02X\n",sb_8_format); + } + + if (dsp->sb_8_length < 0) + { +// pclog("Input DMA over %i\n",sb_8_autoinit); + if (dsp->sb_8_autoinit) dsp->sb_8_length = dsp->sb_8_autolen; + else dsp->sb_8_enable = dsp->sbenable = 0; + sb_irq(dsp, 1); + } + } + if (dsp->sb_16_enable && !dsp->sb_16_pause && dsp->sb_pausetime < 0 && !dsp->sb_16_output) + { + switch (dsp->sb_16_format) + { + case 0x00: /*Unsigned mono*/ + sb_16_write_dma(dsp, 0x8000); + dsp->sb_16_length--; + break; + case 0x10: /*Signed mono*/ + sb_16_write_dma(dsp, 0); + dsp->sb_16_length--; + break; + case 0x20: /*Unsigned stereo*/ + sb_16_write_dma(dsp, 0x8000); + sb_16_write_dma(dsp, 0x8000); + dsp->sb_16_length -= 2; + break; + case 0x30: /*Signed stereo*/ + sb_16_write_dma(dsp, 0); + sb_16_write_dma(dsp, 0); + dsp->sb_16_length -= 2; + break; + +// default: +// fatal("Unrecognised SB 16-bit input format %02X\n",sb_16_format); + } + + if (dsp->sb_16_length < 0) + { +// pclog("16iDMA over %i\n",sb_16_autoinit); + if (dsp->sb_16_autoinit) dsp->sb_16_length = dsp->sb_16_autolen; + else dsp->sb_16_enable = dsp->sbenable = 0; + sb_irq(dsp, 0); + } + } +} + +void sb_dsp_poll(sb_dsp_t *dsp, int16_t *l, int16_t *r) +{ + *l = dsp->sbdatl; + *r = dsp->sbdatr; +} diff --git a/src/sound_sb_dsp.h b/src/sound_sb_dsp.h new file mode 100644 index 0000000..a098d7f --- /dev/null +++ b/src/sound_sb_dsp.h @@ -0,0 +1,69 @@ +typedef struct sb_dsp_t +{ + int sb_type; + + int sb_8_length, sb_8_format, sb_8_autoinit, sb_8_pause, sb_8_enable, sb_8_autolen, sb_8_output; + int sb_8_dmanum; + int sb_16_length, sb_16_format, sb_16_autoinit, sb_16_pause, sb_16_enable, sb_16_autolen, sb_16_output; + int sb_pausetime; + + uint8_t sb_read_data[256]; + int sb_read_wp, sb_read_rp; + int sb_speaker; + + int sb_data_stat; + + int sb_irqnum; + + uint8_t sbe2; + int sbe2count; + + uint8_t sb_data[8]; + + int sb_freq; + + int writebusy; /*Needed for Amnesia*/ + + int16_t sbdat; + int sbdat2; + int16_t sbdatl, sbdatr; + + uint8_t sbref; + int8_t sbstep; + + int sbdacpos; + + int sbleftright; + + int sbreset; + uint8_t sbreaddat; + uint8_t sb_command; + uint8_t sb_test; + int sb_timei, sb_timeo; + + int sb_irq8, sb_irq16; + + uint8_t sb_asp_regs[256]; + + int sbenable, sb_enable_i; + + int sbcount, sb_count_i; + + int sblatcho, sblatchi; + + uint16_t sb_addr; + + int stereo; +} sb_dsp_t; + +void sb_dsp_init(sb_dsp_t *dsp, int type); + +void sb_dsp_setirq(sb_dsp_t *dsp, int irq); +void sb_dsp_setdma8(sb_dsp_t *dsp, int dma); +void sb_dsp_setaddr(sb_dsp_t *dsp, uint16_t addr); + +void sb_dsp_speed_changed(sb_dsp_t *dsp); + +void sb_dsp_poll(sb_dsp_t *dsp, int16_t *l, int16_t *r); + +void sb_dsp_set_stereo(sb_dsp_t *dsp, int stereo); diff --git a/src/sound_sn76489.c b/src/sound_sn76489.c new file mode 100644 index 0000000..88094bb --- /dev/null +++ b/src/sound_sn76489.c @@ -0,0 +1,198 @@ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "sound.h" +#include "sound_sn76489.h" + +static float volslog[16]= +{ + 0.00000f,0.59715f,0.75180f,0.94650f, + 1.19145f,1.50000f,1.88835f,2.37735f, + 2.99295f,3.76785f,4.74345f,5.97165f, + 7.51785f,9.46440f,11.9194f,15.0000f +}; + +typedef struct sn76489_t +{ + int stat[4]; + int latch[4], count[4]; + int freqlo[4], freqhi[4]; + int vol[4]; + uint32_t shift; + uint8_t noise; + int lasttone; + uint8_t firstdat; + + int16_t buffer[SOUNDBUFLEN]; + int pos; +} sn76489_t; + +#define PSGCONST ((3579545.0 / 64.0) / 48000.0) + +void sn76489_poll(void *p) +{ + sn76489_t *sn76489 = (sn76489_t *)p; + int c; + int16_t result = 0; + + if (sn76489->pos >= SOUNDBUFLEN) + return; + + for (c = 1; c < 4; c++) + { + if (sn76489->latch[c] > 256) result += (int16_t) (volslog[sn76489->vol[c]] * sn76489->stat[c]); + else result += (int16_t) (volslog[sn76489->vol[c]] * 127); + + sn76489->count[c] -= (256 * PSGCONST); + while ((int)sn76489->count[c] < 0 && sn76489->latch[c]) + { + sn76489->count[c] += sn76489->latch[c]; + sn76489->stat[c] = -sn76489->stat[c]; + } + } + result += (((sn76489->shift & 1) ^ 1) * 127 * volslog[sn76489->vol[0]] * 2); + + sn76489->count[0] -= (512 * PSGCONST); + while ((int)sn76489->count[0] < 0 && sn76489->latch[0]) + { + sn76489->count[0] += (sn76489->latch[0] * 2); + if (!(sn76489->noise & 4)) + { + if (sn76489->shift & 1) + sn76489->shift |= 0x8000; + sn76489->shift >>= 1; + } + else + { + if ((sn76489->shift & 1) ^ ((sn76489->shift >> 1) & 1)) + sn76489->shift |= 0x8000; + sn76489->shift >>= 1; + } + } + + sn76489->buffer[sn76489->pos++] = result; +} + +void sn76489_get_buffer(int16_t *buffer, int len, void *p) +{ + sn76489_t *sn76489 = (sn76489_t *)p; + + int c; + + for (c = 0; c < len * 2; c++) + buffer[c] += sn76489->buffer[c >> 1]; + + sn76489->pos = 0; +} + +void sn76489_write(uint16_t addr, uint8_t data, void *p) +{ + sn76489_t *sn76489 = (sn76489_t *)p; + int freq; + + if (data & 0x80) + { + sn76489->firstdat = data; + switch (data & 0x70) + { + case 0: + sn76489->freqlo[3] = data & 0xf; + sn76489->latch[3] = (sn76489->freqlo[3] | (sn76489->freqhi[3] << 4)) << 6; + sn76489->lasttone = 3; + break; + case 0x10: + data &= 0xf; + sn76489->vol[3] = 0xf - data; + break; + case 0x20: + sn76489->freqlo[2] = data & 0xf; + sn76489->latch[2] = (sn76489->freqlo[2] | (sn76489->freqhi[2] << 4)) << 6; + sn76489->lasttone = 2; + break; + case 0x30: + data &= 0xf; + sn76489->vol[2] = 0xf - data; + break; + case 0x40: + sn76489->freqlo[1] = data & 0xf; + sn76489->latch[1] = (sn76489->freqlo[1] | (sn76489->freqhi[1] << 4)) << 6; + sn76489->lasttone = 1; + break; + case 0x50: + data &= 0xf; + sn76489->vol[1] = 0xf - data; + break; + case 0x60: + sn76489->shift = 0x4000; + if ((data & 3) != (sn76489->noise & 3)) sn76489->count[0] = 0; + sn76489->noise = data & 0xf; + if ((data & 3) == 3) sn76489->latch[0] = sn76489->latch[1]; + else sn76489->latch[0] = 0x400 << (data & 3); + break; + case 0x70: + data &= 0xf; + sn76489->vol[0] = 0xf - data; + break; + } + } + else + { + if ((sn76489->firstdat & 0x70) == 0x60) + { + sn76489->shift = 0x4000; + if ((data & 3) != (sn76489->noise & 3)) + sn76489->count[0] = 0; + sn76489->noise = data & 0xf; + if ((data & 3) == 3) sn76489->latch[0] = sn76489->latch[1]; + else sn76489->latch[0] = 0x400 << (data & 3); + } + else + { + sn76489->freqhi[sn76489->lasttone] = data & 0x3F; + freq = sn76489->freqlo[sn76489->lasttone] | (sn76489->freqhi[sn76489->lasttone] << 4); + if ((sn76489->noise & 3) == 3 && sn76489->lasttone == 1) + sn76489->latch[0] = freq << 6; + sn76489->latch[sn76489->lasttone] = freq << 6; + } + } +} + +void *sn76489_init() +{ + sn76489_t *sn76489 = malloc(sizeof(sn76489_t)); + memset(sn76489, 0, sizeof(sn76489_t)); + + io_sethandler(0x00C0, 0x0001, NULL, NULL, NULL, sn76489_write, NULL, NULL, sn76489); + + sound_add_handler(sn76489_poll, sn76489_get_buffer, sn76489); + + sn76489->latch[0] = sn76489->latch[1] = sn76489->latch[2] = sn76489->latch[3] = 0x3FF << 6; + sn76489->vol[0] = 0; + sn76489->vol[1] = sn76489->vol[2] = sn76489->vol[3] = 8; + sn76489->stat[0] = sn76489->stat[1] = sn76489->stat[2] = sn76489->stat[3] = 127; + srand(time(NULL)); + sn76489->count[0] = 0; + sn76489->count[1] = (rand()&0x3FF)<<6; + sn76489->count[2] = (rand()&0x3FF)<<6; + sn76489->count[3] = (rand()&0x3FF)<<6; + sn76489->noise = 3; + sn76489->shift = 0x4000; + + return sn76489; +} + +void sn76489_close(void *p) +{ + sn76489_t *sn76489 = (sn76489_t *)p; + + free(sn76489); +} + +device_t sn76489_device = +{ + "TI SN74689 PSG", + sn76489_init, + sn76489_close, + NULL +}; diff --git a/src/sound_sn76489.h b/src/sound_sn76489.h new file mode 100644 index 0000000..89e2d93 --- /dev/null +++ b/src/sound_sn76489.h @@ -0,0 +1 @@ +extern device_t sn76489_device; diff --git a/src/sound_speaker.c b/src/sound_speaker.c new file mode 100644 index 0000000..87efb4e --- /dev/null +++ b/src/sound_speaker.c @@ -0,0 +1,42 @@ +#include "ibm.h" +#include "sound.h" +#include "sound_speaker.h" + +static int16_t speaker_buffer[SOUNDBUFLEN]; + +static int speaker_pos = 0; + +int wasgated = 0; + +static void speaker_poll(void *p) +{ + if (speaker_pos >= SOUNDBUFLEN) return; + +// printf("SPeaker - %i %i %i %02X\n",speakval,gated,speakon,pit.m[2]); + if (gated) + { + if (!pit.m[2] || pit.m[2]==4) + speaker_buffer[speaker_pos] = speakval; + else + speaker_buffer[speaker_pos] = speakon ? 0x1400 : 0; + } + else + speaker_buffer[speaker_pos] = wasgated ? 0x1400 : 0; + speaker_pos++; + wasgated = 0; +} + +static void speaker_get_buffer(int16_t *buffer, int len, void *p) +{ + int c; + + for (c = 0; c < len * 2; c++) + buffer[c] += speaker_buffer[c >> 1]; + + speaker_pos = 0; +} + +void speaker_init() +{ + sound_add_handler(speaker_poll, speaker_get_buffer, NULL); +} diff --git a/src/sound_speaker.h b/src/sound_speaker.h new file mode 100644 index 0000000..5b25efb --- /dev/null +++ b/src/sound_speaker.h @@ -0,0 +1 @@ +void speaker_init(); diff --git a/src/sound_wss.c b/src/sound_wss.c new file mode 100644 index 0000000..0fbf5bb --- /dev/null +++ b/src/sound_wss.c @@ -0,0 +1,307 @@ +/*PCem v0.8 by Tom Walker + + Windows Sound System compatible CODEC emulation (AD1848)*/ + +#include +#include +#include "ibm.h" + +#include "device.h" +#include "dma.h" +#include "io.h" +#include "pic.h" +#include "sound_opl.h" +#include "sound_wss.h" + +/*530, 11, 3 - 530=23*/ +/*530, 11, 1 - 530=22*/ +/*530, 11, 0 - 530=21*/ +/*530, 10, 1 - 530=1a*/ +/*530, 9, 1 - 530=12*/ +/*530, 7, 1 - 530=0a*/ +/*604, 11, 1 - 530=22*/ +/*e80, 11, 1 - 530=22*/ +/*f40, 11, 1 - 530=22*/ + + +static int wss_dma[4] = {0, 0, 1, 3}; +static int wss_irq[8] = {5, 7, 9, 10, 11, 12, 14, 15}; /*W95 only uses 7-9, others may be wrong*/ +static uint16_t wss_addr[4] = {0x530, 0x604, 0xe80, 0xf40}; + +typedef struct wss_t +{ + uint8_t config; + + int index; + uint8_t regs[16]; + uint8_t status; + + int trd; + int mce; + + int count; + + int16_t out_l, out_r; + + int interp_count, inc; + + int enable; + + int irq, dma; + + opl_t opl; + + int16_t opl_buffer[SOUNDBUFLEN * 2]; + int16_t pcm_buffer[2][SOUNDBUFLEN]; + + int pos; +} wss_t; + +static int wss_vols[64]; + +uint8_t wss_read(uint16_t addr, void *p) +{ + wss_t *wss = (wss_t *)p; + uint8_t temp = 0xff; +// pclog("wss_read - addr %04X %04X(%08X):%08X ", addr, CS, cs, pc); + switch (addr & 7) + { + case 0: case 1: case 2: case 3: /*Version*/ + temp = 4 | (wss->config & 0x40); + break; + + case 4: /*Index*/ + temp = wss->index | wss->trd | wss->mce; + break; + case 5: + temp = wss->regs[wss->index]; + break; + case 6: + temp = wss->status; + break; + } +// pclog("return %02X\n", temp); + return temp; +} + +void wss_write(uint16_t addr, uint8_t val, void *p) +{ + wss_t *wss = (wss_t *)p; + double freq; + pclog("wss_write - addr %04X val %02X %04X(%08X):%08X\n", addr, val, CS, cs, pc); + switch (addr & 7) + { + case 0: case 1: case 2: case 3: /*Config*/ + wss->config = val; + wss->dma = wss_dma[val & 3]; + wss->irq = wss_irq[(val >> 3) & 7]; + break; + + case 4: /*Index*/ + wss->index = val & 0xf; + wss->trd = val & 0x20; + wss->mce = val & 0x40; + break; + case 5: + switch (wss->index) + { + case 8: + freq = (val & 1) ? 16934400 : 24576000; + switch ((val >> 1) & 7) + { + case 0: freq /= 3072; break; + case 1: freq /= 1536; break; + case 2: freq /= 896; break; + case 3: freq /= 768; break; + case 4: freq /= 448; break; + case 5: freq /= 384; break; + case 6: freq /= 512; break; + case 7: freq /= 2560; break; + } + wss->inc = (int)((freq * 65536) / 48000); + break; + + case 9: + if (!wss->enable) + wss->interp_count = 0; + + wss->enable = ((val & 0x41) == 0x01); + break; + + case 12: + return; + + case 14: + wss->count = wss->regs[15] | (val << 8); + break; + } + wss->regs[wss->index] = val; + break; + case 6: + wss->status &= 0xfe; + break; + } +} + +static void wss_poll(void *p) +{ + wss_t *wss = (wss_t *)p; + + if (wss->pos >= SOUNDBUFLEN) + return; + + opl3_poll(&wss->opl, &wss->opl_buffer[wss->pos * 2], &wss->opl_buffer[(wss->pos * 2) + 1]); + + if (wss->enable) + { + int32_t temp; + + if (wss->regs[6] & 0x80) + wss->pcm_buffer[1][wss->pos] = 0; + else + wss->pcm_buffer[1][wss->pos] = (wss->out_l * wss_vols[wss->regs[6] & 0x3f]) >> 16; + + if (wss->regs[7] & 0x80) + wss->pcm_buffer[0][wss->pos] = 0; + else + wss->pcm_buffer[0][wss->pos] = (wss->out_r * wss_vols[wss->regs[7] & 0x3f]) >> 16; + + wss->interp_count += wss->inc; + if (wss->interp_count >= 0x10000) + { + wss->interp_count -= 0x10000; + + if (wss->count < 0) + { + wss->count = wss->regs[15] | (wss->regs[14] << 8); + if (!(wss->status & 0x01)) + { + wss->status |= 0x01; + if (wss->regs[0xa] & 2) + picint(1 << wss->irq); + } + } + + switch (wss->regs[8] & 0x70) + { + case 0x00: /*Mono, 8-bit PCM*/ + wss->out_l = wss->out_r = (dma_channel_read(wss->dma) ^ 0x80) * 256; + break; + case 0x10: /*Stereo, 8-bit PCM*/ + wss->out_l = (dma_channel_read(wss->dma) ^ 0x80) * 256; + wss->out_r = (dma_channel_read(wss->dma) ^ 0x80) * 256; + break; + + case 0x40: /*Mono, 16-bit PCM*/ + temp = dma_channel_read(wss->dma); + wss->out_l = wss->out_r = dma_channel_read(wss->dma) | (temp << 8); + break; + case 0x50: /*Stereo, 16-bit PCM*/ + temp = dma_channel_read(wss->dma); + wss->out_l = dma_channel_read(wss->dma) | (temp << 8); + temp = dma_channel_read(wss->dma); + wss->out_r = dma_channel_read(wss->dma) | (temp << 8); + break; + } + + wss->count--; + } +// pclog("wss_poll : enable %X %X %X %X %X %X\n", wss->pcm_buffer[0][wss->pos], wss->pcm_buffer[1][wss->pos], wss->out_l[0], wss->out_r[0], wss->out_l[1], wss->out_r[1]); + } + else + { + wss->pcm_buffer[0][wss->pos] = wss->pcm_buffer[1][wss->pos] = 0; +// pclog("wss_poll : not enable\n"); + } + wss->pos++; +} + +static void wss_get_buffer(int16_t *buffer, int len, void *p) +{ + wss_t *wss = (wss_t *)p; + + int c; + + for (c = 0; c < len * 2; c++) + { + buffer[c] += wss->opl_buffer[c]; + buffer[c] += (wss->pcm_buffer[c & 1][c >> 1] / 2); + } + + wss->pos = 0; +} + +void *wss_init() +{ + wss_t *wss = malloc(sizeof(wss_t)); + int c; + double attenuation; + + memset(wss, 0, sizeof(wss_t)); + + opl3_init(&wss->opl); + + pclog("wss_init - %i %i\n", sbtype, SND_WSS); + + wss->enable = 0; + + wss->status = 0xcc; + wss->index = wss->trd = 0; + wss->mce = 0x40; + + wss->regs[0] = wss->regs[1] = 0; + wss->regs[2] = wss->regs[3] = 0x80; + wss->regs[4] = wss->regs[5] = 0x80; + wss->regs[6] = wss->regs[7] = 0x80; + wss->regs[8] = 0; + wss->regs[9] = 0x08; + wss->regs[10] = wss->regs[11] = 0; + wss->regs[12] = 0xa; + wss->regs[13] = 0; + wss->regs[14] = wss->regs[15] = 0; + + wss->out_l = 0; + wss->out_r = 0; + wss->interp_count = 0; + + wss->irq = 7; + wss->dma = 3; + + io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); + io_sethandler(0x0530, 0x0008, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); + + sound_add_handler(wss_poll, wss_get_buffer, wss); + + for (c = 0; c < 64; c++) + { + attenuation = 0.0; + if (c & 0x01) attenuation -= 1.5; + if (c & 0x02) attenuation -= 3.0; + if (c & 0x04) attenuation -= 6.0; + if (c & 0x08) attenuation -= 12.0; + if (c & 0x10) attenuation -= 24.0; + if (c & 0x20) attenuation -= 48.0; + + attenuation = pow(10, attenuation / 10); + + wss_vols[c] = (int)(attenuation * 65536); + pclog("wss_vols %i = %f %i\n", c, attenuation, wss_vols[c]); + } + + return wss; +} + +void wss_close(void *p) +{ + wss_t *wss = (wss_t *)p; + + free(wss); +} + +device_t wss_device = +{ + "Windows Sound System", + wss_init, + wss_close, + NULL +}; diff --git a/src/sound_wss.h b/src/sound_wss.h new file mode 100644 index 0000000..3569c1f --- /dev/null +++ b/src/sound_wss.h @@ -0,0 +1 @@ +extern device_t wss_device; diff --git a/src/timer.c b/src/timer.c new file mode 100644 index 0000000..d746599 --- /dev/null +++ b/src/timer.c @@ -0,0 +1,94 @@ +#include "ibm.h" + +/*#include "sound_opl.h" +#include "adlibgold.h" +#include "sound_pas16.h" +#include "sound_sb.h" +#include "sound_sb_dsp.h" +#include "sound_wss.h"*/ +#include "timer.h" + +#define TIMERS_MAX 32 + +int TIMER_USEC; + +static struct +{ + int present; + void (*callback)(void *priv); + void *priv; + int *enable; + int *count; +} timers[TIMERS_MAX]; + +int timers_present = 0; +int timer_one = 1; + +int timer_count = 0, timer_latch = 0; + +void timer_process() +{ + int c; + + /*Get actual elapsed time*/ + timer_latch -= timer_count; + + for (c = 0; c < timers_present; c++) + { +// pclog("timer_process : %i enable %i %X\n", c, timers[c].enable, *timers[c].enable); + if (*timers[c].enable) + { + *timers[c].count = *timers[c].count - (timer_latch << TIMER_SHIFT); + if (*timers[c].count <= 0) + { + timers[c].callback(timers[c].priv); + } + } + } +} + +void timer_update_outstanding() +{ + int c; + timer_latch = 0x7fffffff; + for (c = 0; c < timers_present; c++) + { + if (*timers[c].enable && *timers[c].count < timer_latch) + timer_latch = *timers[c].count; + } + if (spktime < timer_latch) timer_latch = spktime; + //if (soundtime < timer_latch) timer_latch = soundtime; + //if (gustime < timer_latch) timer_latch = gustime; + //if (gustime2 < timer_latch) timer_latch = gustime2; + //if (vidtime < timer_latch) timer_latch = vidtime; + timer_count = timer_latch = (timer_latch + ((1 << TIMER_SHIFT) - 1)) >> TIMER_SHIFT; +} + +void timer_reset() +{ + pclog("timer_reset\n"); + timers_present = 0; + timer_latch = timer_count = 0; +// timer_process(); +} + +int timer_add(void (*callback)(void *priv), int *count, int *enable, void *priv) +{ + if (timers_present < TIMERS_MAX) + { + pclog("timer_add : adding timer %i\n", timers_present); + timers[timers_present].present = 1; + timers[timers_present].callback = callback; + timers[timers_present].priv = priv; + timers[timers_present].count = count; + timers[timers_present].enable = enable; + timers_present++; + return timers_present - 1; + } + return -1; +} + +void timer_set_callback(int timer, void (*callback)(void *priv)) +{ + timers[timer].callback = callback; +} diff --git a/src/timer.h b/src/timer.h new file mode 100644 index 0000000..ba0f625 --- /dev/null +++ b/src/timer.h @@ -0,0 +1,25 @@ +#define timer_clock(cycles) \ + do \ + { \ + timer_count -= cycles; \ + if (timer_count <= 0) \ + { \ + timer_process(); \ + timer_update_outstanding(); \ + } \ + } while (0) + +void timer_process(); +void timer_update_outstanding(); +void timer_reset(); +int timer_add(void (*callback)(void *priv), int *count, int *enable, void *priv); +void timer_set_callback(int timer, void (*callback)(void *priv)); + +#define TIMER_ALWAYS_ENABLED &timer_one + +extern int timer_count; +extern int timer_one; + +#define TIMER_SHIFT 6 + +extern int TIMER_USEC; diff --git a/src/um8669f.c b/src/um8669f.c new file mode 100644 index 0000000..30e55e6 --- /dev/null +++ b/src/um8669f.c @@ -0,0 +1,138 @@ +/*um8669f : + + aa to 108 unlocks + next 108 write is register select (Cx?) + data read/write to 109 + 55 to 108 locks + + + + +C0 +bit 3 = LPT1 enable +bit 2 = COM2 enable +bit 1 = COM1 enable +bit 0 = FDC enable + +C1 +bits 7-6 = LPT1 mode : 11 = ECP/EPP, 01 = EPP, 10 = SPP +bit 3 = clear when LPT1 = 278 + +C3 +bits 7-6 = LPT1 DMA mode : 11 = ECP/EPP DMA1, 10 = ECP/EPP DMA3, 01 = EPP/SPP, 00 = ECP +bits 5-4 = LPT1 addr : 10 = 278/IRQ5, 01 = 3BC/IRQ7, 00 = 378/IRQ7 + +COM1 : +3f8, IRQ4 - C1 = BF, C3 = 00 +2f8, IRQ3 - C1 = BF, C3 = 03 +3e8, IRQ4 - C1 = BD, C3 = 00 +2e8, IRQ3 - B1 = BD, C3 = 03 + +COM2 : +3f8, IRQ4 - C1 = BF, C3 = 0C +2f8, IRQ3 - C1 = BF, C3 = 00 +3e8, IRQ4 - C1 = BB, C3 = 0C +2e8, IRQ3 - C1 = BB, C3 = 00 + + */ + +#include "ibm.h" + +#include "fdc.h" +#include "io.h" +#include "lpt.h" +#include "mouse_serial.h" +#include "serial.h" +#include "um8669f.h" + +static int um8669f_locked; +static int um8669f_curreg; +static uint8_t um8669f_regs[256]; + +void um8669f_write(uint16_t port, uint8_t val, void *priv) +{ + int temp; + if (um8669f_locked) + { + if (port == 0x108 && val == 0xaa) + um8669f_locked = 0; + } + else + { + if (port == 0x108) + { + if (val == 0x55) + um8669f_locked = 1; + else + um8669f_curreg = val; + } + else + { + um8669f_regs[um8669f_curreg] = val; + pclog("um8669f_write : reg %02X = %02X\n", um8669f_curreg, val); + + fdc_remove(); + if (um8669f_regs[0xc0] & 1) + fdc_add(); + + serial1_remove(); + if (um8669f_regs[0xc0] & 2) + { + temp = um8669f_regs[0xc3] & 1; /*might be & 2*/ + if (!(um8669f_regs[0xc1] & 2)) + temp |= 2; + switch (temp) + { + case 0: serial1_init(0x3f8); break; + case 1: serial1_init(0x2f8); break; + case 2: serial1_init(0x3e8); break; + case 3: serial1_init(0x2e8); break; + } + } + + serial2_remove(); + if (um8669f_regs[0xc0] & 4) + { + temp = (um8669f_regs[0xc3] & 4) ? 0 : 1; /*might be & 8*/ + if (!(um8669f_regs[0xc1] & 4)) + temp |= 2; + switch (temp) + { + case 0: serial2_init(0x3f8); break; + case 1: serial2_init(0x2f8); break; + case 2: serial2_init(0x3e8); break; + case 3: serial2_init(0x2e8); break; + } + } + + mouse_serial_init(); + + lpt1_remove(); + lpt2_remove(); + temp = (um8669f_regs[0xc3] >> 4) & 3; + switch (temp) + { + case 0: lpt1_init(0x378); break; + case 1: lpt1_init(0x3bc); break; + case 2: lpt1_init(0x278); break; + } + } + } +} + +uint8_t um8669f_read(uint16_t port, void *priv) +{ + if (um8669f_locked) + return 0xff; + + if (port == 0x108) + return um8669f_curreg; /*???*/ + else + return um8669f_regs[um8669f_curreg]; +} + +void um8669f_init() +{ + io_sethandler(0x0108, 0x0002, um8669f_read, NULL, NULL, um8669f_write, NULL, NULL, NULL); + um8669f_locked = 1; +} diff --git a/src/um8669f.h b/src/um8669f.h new file mode 100644 index 0000000..45e35ed --- /dev/null +++ b/src/um8669f.h @@ -0,0 +1 @@ +extern void um8669f_init(); diff --git a/src/vid_ati18800.c b/src/vid_ati18800.c new file mode 100644 index 0000000..762a084 --- /dev/null +++ b/src/vid_ati18800.c @@ -0,0 +1,142 @@ +/*ATI 18800 emulation (VGA Edge-16)*/ +#include "ibm.h" +#include "io.h" +#include "video.h" +#include "vid_ati_eeprom.h" +#include "vid_svga.h" + +static uint8_t ati_regs[256]; +static int ati_index; + +void ati18800_out(uint16_t addr, uint8_t val, void *priv) +{ + uint8_t old; + + pclog("ati18800_out : %04X %02X %04X:%04X\n", addr, val, CS,pc); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60; + + switch (addr) + { + case 0x1ce: + ati_index = val; + break; + case 0x1cf: + ati_regs[ati_index] = val; + switch (ati_index) + { + case 0xb2: + case 0xbe: + if (ati_regs[0xbe] & 8) /*Read/write bank mode*/ + { + svgarbank = ((ati_regs[0xb2] >> 5) & 7) * 0x10000; + svgawbank = ((ati_regs[0xb2] >> 1) & 7) * 0x10000; + } + else /*Single bank mode*/ + svgarbank = svgawbank = ((ati_regs[0xb2] >> 1) & 7) * 0x10000; + break; + case 0xb3: + ati_eeprom_write(val & 8, val & 2, val & 1); + break; + } + break; + + case 0x3D4: + crtcreg = val & 0x3f; + return; + case 0x3D5: + if (crtcreg <= 7 && crtc[0x11] & 0x80) return; + old=crtc[crtcreg]; + crtc[crtcreg]=val; + if (old!=val) + { + if (crtcreg<0xE || crtcreg>0x10) + { + fullchange=changeframecount; + svga_recalctimings(); + } + } + break; + } + svga_out(addr, val, NULL); +} + +uint8_t ati18800_in(uint16_t addr, void *priv) +{ + uint8_t temp; + + if (addr != 0x3da) pclog("ati18800_in : %04X ", addr); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60; + + switch (addr) + { + case 0x1ce: + temp = ati_index; + break; + case 0x1cf: + switch (ati_index) + { + case 0xb7: + temp = ati_regs[ati_index] & ~8; + if (ati_eeprom_read()) + temp |= 8; + break; + + default: + temp = ati_regs[ati_index]; + break; + } + break; + + case 0x3D4: + temp = crtcreg; + break; + case 0x3D5: + temp = crtc[crtcreg]; + break; + default: + temp = svga_in(addr, NULL); + break; + } + if (addr != 0x3da) pclog("%02X %04X:%04X\n", temp, CS,pc); + return temp; +} + +int ati18800_init() +{ + svga_recalctimings_ex = NULL; + svga_vram_limit = 1 << 19; /*512kb*/ + vrammask = 0x7ffff; + svgawbank = svgarbank = 0; + bpp = 8; + svga_miscout = 1; + + io_sethandler(0x01ce, 0x0002, ati18800_in, NULL, NULL, ati18800_out, NULL, NULL, NULL); + + ati_eeprom_load("ati18800.nvr", 0); + + return svga_init(); +} + +GFXCARD vid_ati18800 = +{ + ati18800_init, + /*IO at 3Cx/3Dx*/ + ati18800_out, + ati18800_in, + /*IO at 3Ax/3Bx*/ + video_out_null, + video_in_null, + + svga_poll, + svga_recalctimings, + + svga_write, + video_write_null, + video_write_null, + + svga_read, + video_read_null, + video_read_null +}; diff --git a/src/vid_ati28800.c b/src/vid_ati28800.c new file mode 100644 index 0000000..5c89795 --- /dev/null +++ b/src/vid_ati28800.c @@ -0,0 +1,161 @@ +/*ATI 28800 emulation (VGA Charger)*/ +#include "ibm.h" +#include "io.h" +#include "video.h" +#include "vid_ati_eeprom.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + +static uint8_t ati_regs[256]; +static int ati_index; + +void ati28800_out(uint16_t addr, uint8_t val, void *priv) +{ + uint8_t old; + + pclog("ati28800_out : %04X %02X %04X:%04X\n", addr, val, CS,pc); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60; + + switch (addr) + { + case 0x1ce: + ati_index = val; + break; + case 0x1cf: + ati_regs[ati_index] = val; + switch (ati_index) + { + case 0xb2: + case 0xbe: + if (ati_regs[0xbe] & 8) /*Read/write bank mode*/ + { + svgarbank = ((ati_regs[0xb2] >> 5) & 7) * 0x10000; + svgawbank = ((ati_regs[0xb2] >> 1) & 7) * 0x10000; + } + else /*Single bank mode*/ + svgarbank = svgawbank = ((ati_regs[0xb2] >> 1) & 7) * 0x10000; + break; + case 0xb3: + ati_eeprom_write(val & 8, val & 2, val & 1); + break; + } + break; + + case 0x3D4: + crtcreg = val & 0x3f; + return; + case 0x3D5: + if (crtcreg <= 7 && crtc[0x11] & 0x80) return; + old=crtc[crtcreg]; + crtc[crtcreg]=val; + if (old!=val) + { + if (crtcreg<0xE || crtcreg>0x10) + { + fullchange=changeframecount; + svga_recalctimings(); + } + } + break; + } + svga_out(addr, val, NULL); +} + +uint8_t ati28800_in(uint16_t addr, void *priv) +{ + uint8_t temp; + + if (addr != 0x3da) pclog("ati28800_in : %04X ", addr); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60; + + switch (addr) + { + case 0x1ce: + temp = ati_index; + break; + case 0x1cf: + switch (ati_index) + { + case 0xb7: + temp = ati_regs[ati_index] & ~8; + if (ati_eeprom_read()) + temp |= 8; + break; + + default: + temp = ati_regs[ati_index]; + break; + } + break; + + case 0x3c2: + if ((vgapal[0].r + vgapal[0].g + vgapal[0].b) >= 0x50) + temp = 0; + else + temp = 0x10; + break; + case 0x3D4: + temp = crtcreg; + break; + case 0x3D5: + temp = crtc[crtcreg]; + break; + default: + temp = svga_in(addr, NULL); + break; + } + if (addr != 0x3da) pclog("%02X %04X:%04X\n", temp, CS,pc); + return temp; +} + +void ati28800_recalctimings() +{ + pclog("ati28800_recalctimings\n"); + if (!scrblank && (ati_regs[0xb0] & 0x20)) /*Extended 256 colour modes*/ + { + pclog("8bpp_highres\n"); + svga_render = svga_render_8bpp_highres; + svga_rowoffset <<= 1; + svga_ma <<= 1; + } +} + +int ati28800_init() +{ + svga_recalctimings_ex = ati28800_recalctimings; + svga_vram_limit = 1 << 19; /*512kb*/ + vrammask = 0x7ffff; + svgawbank = svgarbank = 0; + bpp = 8; + svga_miscout = 1; + + io_sethandler(0x01ce, 0x0002, ati28800_in, NULL, NULL, ati28800_out, NULL, NULL, NULL); + + ati_eeprom_load("ati28800.nvr", 0); + + return svga_init(); +} + +GFXCARD vid_ati28800 = +{ + ati28800_init, + /*IO at 3Cx/3Dx*/ + ati28800_out, + ati28800_in, + /*IO at 3Ax/3Bx*/ + video_out_null, + video_in_null, + + svga_poll, + svga_recalctimings, + + svga_write, + video_write_null, + video_write_null, + + svga_read, + video_read_null, + video_read_null +}; diff --git a/src/vid_ati68860_ramdac.c b/src/vid_ati68860_ramdac.c new file mode 100644 index 0000000..7dae246 --- /dev/null +++ b/src/vid_ati68860_ramdac.c @@ -0,0 +1,83 @@ +/*ATI 68860 RAMDAC emulation (for Mach64)*/ +/* +ATI 68860/68880 Truecolor DACs: +REG08 (R/W): +bit 0-? Always 2 ?? + +REG0A (R/W): +bit 0-? Always 1Dh ?? + +REG0B (R/W): (GMR ?) +bit 0-7 Mode. 82h: 4bpp, 83h: 8bpp, A0h: 15bpp, A1h: 16bpp, C0h: 24bpp, + E3h: 32bpp (80h for VGA modes ?) + +REG0C (R/W): Device Setup Register A +bit 0 Controls 6/8bit DAC. 0: 8bit DAC/LUT, 1: 6bit DAC/LUT + 2-3 Depends on Video memory (= VRAM width ?) . 1: Less than 1Mb, 2: 1Mb, + 3: > 1Mb + 5-6 Always set ? + 7 If set can remove "snow" in some cases (A860_Delay_L ?) ?? +*/ +#include "ibm.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_ati68860_ramdac.h" + +static uint8_t ramdac_regs[16]; +void ati68860_ramdac_out(uint16_t addr, uint8_t val, void *priv) +{ +// pclog("ati68860_out : addr %04X val %02X %04X:%04X\n", addr, val, CS,pc); + switch (addr) + { + case 0: + svga_out(0x3c8, val, NULL); + break; + case 1: + svga_out(0x3c9, val, NULL); + break; + case 2: + svga_out(0x3c6, val, NULL); + break; + case 3: + svga_out(0x3c7, val, NULL); + break; + default: + ramdac_regs[addr & 0xf] = val; + break; + } +} + +uint8_t ati68860_ramdac_in(uint16_t addr, void *priv) +{ + uint8_t ret = 0; + switch (addr) + { + case 0: + ret = svga_in(0x3c8, NULL); + break; + case 1: + ret = svga_in(0x3c9, NULL); + break; + case 2: + ret = svga_in(0x3c6, NULL); + break; + case 3: + ret = svga_in(0x3c7, NULL); + break; + case 4: case 8: + ret = 2; + break; + case 6: case 0xa: + ret = 0x1d; + break; + case 0xf: + ret = 0xd0; + break; + + default: + ret = ramdac_regs[addr & 0xf]; + break; + } +// pclog("ati68860_in : addr %04X ret %02X %04X:%04X\n", addr, ret, CS,pc); + return ret; +} diff --git a/src/vid_ati68860_ramdac.h b/src/vid_ati68860_ramdac.h new file mode 100644 index 0000000..1dc2bc4 --- /dev/null +++ b/src/vid_ati68860_ramdac.h @@ -0,0 +1,2 @@ +void ati68860_ramdac_out(uint16_t addr, uint8_t val, void *priv); +uint8_t ati68860_ramdac_in(uint16_t addr, void *priv); diff --git a/src/vid_ati_eeprom.c b/src/vid_ati_eeprom.c new file mode 100644 index 0000000..5e1dba7 --- /dev/null +++ b/src/vid_ati_eeprom.c @@ -0,0 +1,229 @@ +#include "ibm.h" +#include "vid_ati_eeprom.h" + +static uint16_t eeprom[256]; +enum +{ + EEPROM_IDLE, + EEPROM_WAIT, + EEPROM_OPCODE, + EEPROM_INPUT, + EEPROM_OUTPUT +}; + +enum +{ + EEPROM_OP_EW = 4, + EEPROM_OP_WRITE = 5, + EEPROM_OP_READ = 6, + EEPROM_OP_ERASE = 7, + + EEPROM_OP_WRALMAIN = -1 +}; + +enum +{ + EEPROM_OP_EWDS = 0, + EEPROM_OP_WRAL = 1, + EEPROM_OP_ERAL = 2, + EEPROM_OP_EWEN = 3 +}; + +static int oldclk, oldena; +static int eeprom_opcode, eeprom_state, eeprom_count, eeprom_out; +static int eeprom_wp; +static uint32_t eeprom_dat; +static int eeprom_type; + +static char eeprom_fn[256] = {0}; + +void ati_eeprom_load(char *fn, int type) +{ + FILE *f; + eeprom_type = type; + strcpy(eeprom_fn, fn); + f = romfopen(eeprom_fn, "rb"); + if (!f) + { + memset(eeprom, 0, type ? 512 : 128); + return; + } + fread(eeprom, 1, type ? 512 : 128, f); + fclose(f); +} + +void ati_eeprom_save() +{ + FILE *f = romfopen(eeprom_fn, "wb"); + if (!f) return; + fwrite(eeprom, 1, eeprom_type ? 512 : 128, f); + fclose(f); +} + +void ati_eeprom_write(int ena, int clk, int dat) +{ + int c; + pclog("EEPROM write %i %i %i\n", ena, clk, dat); + if (!ena) + { + eeprom_out = 1; + } + if (clk && !oldclk) + { + if (ena && !oldena) + { + eeprom_state = EEPROM_WAIT; + eeprom_opcode = 0; + eeprom_count = 3; + eeprom_out = 1; + } + else if (ena) + { + pclog("EEPROM receive %i %i %i\n", ena, clk, dat); + switch (eeprom_state) + { + case EEPROM_WAIT: + if (!dat) + break; + eeprom_state = EEPROM_OPCODE; + /* fall through */ + case EEPROM_OPCODE: + eeprom_opcode = (eeprom_opcode << 1) | (dat ? 1 : 0); + eeprom_count--; + if (!eeprom_count) + { + pclog("EEPROM opcode - %i\n", eeprom_opcode); + switch (eeprom_opcode) + { + case EEPROM_OP_WRITE: + eeprom_count = eeprom_type ? 24 : 22; + eeprom_state = EEPROM_INPUT; + eeprom_dat = 0; + break; + case EEPROM_OP_READ: + eeprom_count = eeprom_type ? 8 : 6; + eeprom_state = EEPROM_INPUT; + eeprom_dat = 0; + break; + case EEPROM_OP_EW: + eeprom_count = 2; + eeprom_state = EEPROM_INPUT; + eeprom_dat = 0; + break; + case EEPROM_OP_ERASE: + eeprom_count = eeprom_type ? 8 : 6; + eeprom_state = EEPROM_INPUT; + eeprom_dat = 0; + break; + } + } + break; + + case EEPROM_INPUT: + eeprom_dat = (eeprom_dat << 1) | (dat ? 1 : 0); + eeprom_count--; + if (!eeprom_count) + { + pclog("EEPROM dat - %02X\n", eeprom_dat); + switch (eeprom_opcode) + { + case EEPROM_OP_WRITE: + pclog("EEPROM_OP_WRITE addr %02X eeprom_dat %04X\n", (eeprom_dat >> 16) & (eeprom_type ? 255 : 63), eeprom_dat & 0xffff); + if (!eeprom_wp) + { + eeprom[(eeprom_dat >> 16) & (eeprom_type ? 255 : 63)] = eeprom_dat & 0xffff; + ati_eeprom_save(); + } + eeprom_state = EEPROM_IDLE; + eeprom_out = 1; + break; + + case EEPROM_OP_READ: + eeprom_count = 17; + eeprom_state = EEPROM_OUTPUT; + eeprom_dat = eeprom[eeprom_dat]; + pclog("Trigger EEPROM_OUTPUT %04X\n", eeprom_dat); + break; + case EEPROM_OP_EW: + pclog("EEPROM_OP_EW %i\n", eeprom_dat); + switch (eeprom_dat) + { + case EEPROM_OP_EWDS: + eeprom_wp = 1; + break; + case EEPROM_OP_WRAL: + opcode = EEPROM_OP_WRALMAIN; + eeprom_count = 20; + break; + case EEPROM_OP_ERAL: + if (!eeprom_wp) + { + memset(eeprom, 0xff, 128); + ati_eeprom_save(); + } + break; + case EEPROM_OP_EWEN: + eeprom_wp = 0; + break; + } + eeprom_state = EEPROM_IDLE; + eeprom_out = 1; + break; + + case EEPROM_OP_ERASE: + pclog("EEPROM_OP_ERASE %i\n", eeprom_dat); + if (!eeprom_wp) + { + eeprom[eeprom_dat] = 0xffff; + ati_eeprom_save(); + } + eeprom_state = EEPROM_IDLE; + eeprom_out = 1; + break; + + case EEPROM_OP_WRALMAIN: + pclog("EEPROM_OP_WRAL %04X\n", eeprom_dat); + if (!eeprom_wp) + { + for (c = 0; c < 256; c++) + eeprom[c] = eeprom_dat; + ati_eeprom_save(); + } + eeprom_state = EEPROM_IDLE; + eeprom_out = 1; + break; + } + } + break; + } + } + oldena = ena; + } + else if (!clk && oldclk) + { + if (ena) + { + switch (eeprom_state) + { + case EEPROM_OUTPUT: + eeprom_out = (eeprom_dat & 0x10000) ? 1 : 0; + eeprom_dat <<= 1; + pclog("EEPROM_OUTPUT - data %i\n", eeprom_out); + eeprom_count--; + if (!eeprom_count) + { + pclog("EEPROM_OUTPUT complete\n"); + eeprom_state = EEPROM_IDLE; + } + break; + } + } + } + oldclk = clk; +} + +int ati_eeprom_read() +{ + return eeprom_out; +} + diff --git a/src/vid_ati_eeprom.h b/src/vid_ati_eeprom.h new file mode 100644 index 0000000..f886ad0 --- /dev/null +++ b/src/vid_ati_eeprom.h @@ -0,0 +1,3 @@ +void ati_eeprom_load(char *fn, int type); +void ati_eeprom_write(int ena, int clk, int dat); +int ati_eeprom_read(); diff --git a/src/vid_ati_mach64.c b/src/vid_ati_mach64.c new file mode 100644 index 0000000..b163ded --- /dev/null +++ b/src/vid_ati_mach64.c @@ -0,0 +1,1767 @@ +/*ATI Mach64 emulation*/ +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_ati68860_ramdac.h" +#include "vid_ati_eeprom.h" +#include "vid_ics2595.h" +#include "vid_svga_render.h" + +//#define MACH64_DEBUG +static int mach64_bank_r[2] = {0, 0}; +static int mach64_bank_w[2] = {0, 0}; +void mach64_write(uint32_t addr, uint8_t val, void *priv); +uint8_t mach64_read(uint32_t addr, void *priv); + +static uint8_t ati_regs[256]; +static int ati_index; + +struct +{ + uint32_t config_cntl; + + uint32_t context_load_cntl; + uint32_t context_mask; + + uint32_t crtc_gen_cntl; + uint8_t crtc_int_cntl; + uint32_t crtc_h_total_disp; + uint32_t crtc_v_sync_strt_wid; + uint32_t crtc_v_total_disp; + uint32_t crtc_off_pitch; + + uint32_t clock_cntl; + + uint32_t cur_horz_vert_off; + uint32_t cur_horz_vert_posn; + uint32_t cur_offset; + + uint32_t dac_cntl; + + uint32_t dp_bkgd_clr; + uint32_t dp_frgd_clr; + uint32_t dp_mix; + uint32_t dp_pix_width; + uint32_t dp_src; + + uint32_t dst_bres_lnth; + uint32_t dst_bres_dec; + uint32_t dst_bres_err; + uint32_t dst_bres_inc; + + uint32_t dst_cntl; + uint32_t dst_height_width; + uint32_t dst_off_pitch; + uint32_t dst_y_x; + + uint32_t gen_test_cntl; + + uint32_t gui_traj_cntl; + + uint32_t mem_cntl; + + uint32_t pat_cntl; + uint32_t pat_reg0, pat_reg1; + + uint32_t sc_left_right, sc_top_bottom; + + uint32_t scratch_reg0, scratch_reg1; + + uint32_t src_cntl; + uint32_t src_off_pitch; + uint32_t src_y_x; + + struct + { + int op; + + int dst_x, dst_y; + int dst_x_start; + int src_x, src_y; + int src_x_start; + int xinc, yinc; + int x_count, y_count; + uint32_t src_offset, src_pitch; + uint32_t dst_offset, dst_pitch; + int mix_bg, mix_fg; + int source_bg, source_fg, source_mix; + int source_host; + int dst_width, dst_height; + int busy; + int pattern[8][8]; + int sc_left, sc_right, sc_top, sc_bottom; + int dst_pix_width, src_pix_width, host_pix_width; + int dst_size, src_size; + + uint32_t dp_bkgd_clr; + uint32_t dp_frgd_clr; + + int err; + } accel; +} mach64; + +enum +{ + SRC_BG = 0, + SRC_FG = 1, + SRC_HOST = 2, + SRC_BLITSRC = 3, + SRC_PAT = 4 +}; + +enum +{ + MONO_SRC_1 = 0, + MONO_SRC_PAT = 1, + MONO_SRC_HOST = 2, + MONO_SRC_BLITSRC = 3 +}; + +enum +{ + BPP_1 = 0, + BPP_4 = 1, + BPP_8 = 2, + BPP_15 = 3, + BPP_16 = 4, + BPP_32 = 5 +}; + +enum +{ + OP_RECT, + OP_LINE +}; + +static int mach64_width[6] = {0, 0, 0, 1, 1, 2}; + +enum +{ + DST_24_ROT_EN = 0x80 +}; + +uint8_t mach64_ext_readb(uint32_t addr, void *priv); +uint16_t mach64_ext_readw(uint32_t addr, void *priv); +uint32_t mach64_ext_readl(uint32_t addr, void *priv); +void mach64_ext_writeb(uint32_t addr, uint8_t val, void *priv); +void mach64_ext_writew(uint32_t addr, uint16_t val, void *priv); +void mach64_ext_writel(uint32_t addr, uint32_t val, void *priv); + +void mach64_out(uint16_t addr, uint8_t val, void *priv) +{ + uint8_t old; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60; + +// pclog("mach64 out %04X %02X\n", addr, val); + + switch (addr) + { + case 0x1ce: + ati_index = val; + break; + case 0x1cf: + ati_regs[ati_index] = val; + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + ati68860_ramdac_out((addr & 3) | ((mach64.dac_cntl & 3) << 2), val, NULL); + return; + + case 0x3cf: + if (gdcaddr == 6) + { + if ((gdcreg[6] & 0xc) != (val & 0xc)) + { + mem_removehandler(0xa0000, 0x20000, mach64_read, NULL, NULL, mach64_write, NULL, NULL, NULL); + mem_removehandler(0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL); + mem_removehandler(0xbc000, 0x04000, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL); + pclog("Write mapping %02X\n", val); + switch (val&0xC) + { + case 0x0: /*128k at A0000*/ + mem_sethandler(0xa0000, 0x10000, mach64_read, NULL, NULL, mach64_write, NULL, NULL, NULL); + mem_sethandler(0xbc000, 0x04000, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL); + break; + case 0x4: /*64k at A0000*/ + mem_sethandler(0xa0000, 0x10000, mach64_read, NULL, NULL, mach64_write, NULL, NULL, NULL); + break; + case 0x8: /*32k at B0000*/ + mem_sethandler(0xb0000, 0x08000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL); + break; + case 0xC: /*32k at B8000*/ + mem_sethandler(0xb8000, 0x08000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL); + break; + } + } + gdcreg[6] = val; + return; + } + break; + + case 0x3D4: + crtcreg = val & 0x3f; + return; + case 0x3D5: + if (crtcreg <= 7 && crtc[0x11] & 0x80) return; + old=crtc[crtcreg]; + crtc[crtcreg]=val; + + if (old!=val) + { + if (crtcreg<0xE || crtcreg>0x10) + { + fullchange=changeframecount; + svga_recalctimings(); + } + } + break; + } + svga_out(addr, val, NULL); +} + +uint8_t mach64_in(uint16_t addr, void *priv) +{ + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60; + +// pclog("IN mach64 %04X\n", addr); + + switch (addr) + { + case 0x1ce: + return ati_index; + case 0x1cf: + return ati_regs[ati_index]; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + return ati68860_ramdac_in((addr & 3) | ((mach64.dac_cntl & 3) << 2), NULL); + + case 0x3D4: + return crtcreg; + case 0x3D5: + return crtc[crtcreg]; + } + return svga_in(addr, NULL); +} + +void mach64_recalctimings() +{ + if (((mach64.crtc_gen_cntl >> 24) & 3) == 3) + { + svga_vtotal = (mach64.crtc_v_total_disp & 2047) + 1; + svga_dispend = ((mach64.crtc_v_total_disp >> 16) & 2047) + 1; + svga_htotal = (mach64.crtc_h_total_disp & 255) + 1; + svga_hdisp_time = svga_hdisp = ((mach64.crtc_h_total_disp >> 16) & 255) + 1; + svga_vsyncstart = (mach64.crtc_v_sync_strt_wid & 2047) + 1; + svga_rowoffset = (mach64.crtc_off_pitch >> 22); + svga_clock = cpuclock / ics2595_output_clock; + svga_ma = (mach64.crtc_off_pitch & 0x1fffff) * 2; + svga_linedbl = svga_rowcount = 0; +// svga_htotal <<= 1; +// svga_hdisp <<= 1; + svga_rowoffset <<= 1; + switch ((mach64.crtc_gen_cntl >> 8) & 7) + { + case 1: + svga_render = svga_render_4bpp_highres; + svga_hdisp *= 8; + break; + case 2: + svga_render = svga_render_8bpp_highres; + svga_hdisp *= 8; + svga_rowoffset /= 2; + break; + case 3: + svga_render = svga_render_15bpp_highres; + svga_hdisp *= 8; + //svga_rowoffset *= 2; + break; + case 4: + svga_render = svga_render_16bpp_highres; + svga_hdisp *= 8; + //svga_rowoffset *= 2; + break; + case 5: + svga_render = svga_render_24bpp_highres; + svga_hdisp *= 8; + svga_rowoffset = (svga_rowoffset * 3) / 2; + break; + case 6: + svga_render = svga_render_32bpp_highres; + svga_hdisp *= 8; + break; + } + + pclog("mach64_recalctimings : frame %i,%i disp %i,%i vsync at %i rowoffset %i pixel clock %f MA %08X\n", svga_htotal, svga_vtotal, svga_hdisp, svga_dispend, svga_vsyncstart, svga_rowoffset, svga_clock, svga_ma); + } +} + +#define READ8(addr, var) switch ((addr) & 3) \ + { \ + case 0: ret = (var) & 0xff; break; \ + case 1: ret = ((var) >> 8) & 0xff; break; \ + case 2: ret = ((var) >> 16) & 0xff; break; \ + case 3: ret = ((var) >> 24) & 0xff; break; \ + } + +#define WRITE8(addr, var, val) switch ((addr) & 3) \ + { \ + case 0: var = (var & 0xffffff00) | (val); break; \ + case 1: var = (var & 0xffff00ff) | ((val) << 8); break; \ + case 2: var = (var & 0xff00ffff) | ((val) << 16); break; \ + case 3: var = (var & 0x00ffffff) | ((val) << 24); break; \ + } + +void mach64_cursor_dump() +{ + pclog("Mach64 cursor :\n"); + pclog("Ena = %i X = %i Y = %i Addr = %05X Xoff = %i Yoff = %i\n", svga_hwcursor.ena, svga_hwcursor.x, svga_hwcursor.y, svga_hwcursor.addr, svga_hwcursor.xoff, svga_hwcursor.yoff); +} + +void mach64_start_fill() +{ + int x, y; + + mach64.accel.dst_x = (mach64.dst_y_x >> 16) & 0xfff; + mach64.accel.dst_y = mach64.dst_y_x & 0xfff; + + mach64.accel.dst_width = (mach64.dst_height_width >> 16) & 0x1fff; + mach64.accel.dst_height = mach64.dst_height_width & 0x1fff; + mach64.accel.x_count = mach64.accel.dst_width; + + mach64.accel.src_x = (mach64.src_y_x >> 16) & 0xfff; + mach64.accel.src_y = mach64.src_y_x & 0xfff; + + mach64.accel.src_pitch = (mach64.src_off_pitch >> 22) * 8; + mach64.accel.src_offset = (mach64.src_off_pitch & 0xfffff) * 8; + + mach64.accel.dst_pitch = (mach64.dst_off_pitch >> 22) * 8; + mach64.accel.dst_offset = (mach64.dst_off_pitch & 0xfffff) * 8; + + mach64.accel.mix_fg = (mach64.dp_mix >> 16) & 0x1f; + mach64.accel.mix_bg = mach64.dp_mix & 0x1f; + + mach64.accel.source_bg = mach64.dp_src & 7; + mach64.accel.source_fg = (mach64.dp_src >> 8) & 7; + mach64.accel.source_mix = (mach64.dp_src >> 16) & 7; + + mach64.accel.dst_pix_width = mach64.dp_pix_width & 7; + mach64.accel.src_pix_width = (mach64.dp_pix_width >> 8) & 7; + mach64.accel.host_pix_width = (mach64.dp_pix_width >> 16) & 7; + + mach64.accel.dst_size = mach64_width[mach64.accel.dst_pix_width]; + mach64.accel.src_size = mach64_width[mach64.accel.src_pix_width]; + +/* mach64.accel.src_x *= mach64_inc[mach64.accel.src_pix_width]; + mach64.accel.src_pitch *= mach64_inc[mach64.accel.src_pix_width]; + mach64.accel.dst_x *= mach64_inc[mach64.accel.dst_pix_width]; + mach64.accel.dst_pitch *= mach64_inc[mach64.accel.dst_pix_width];*/ + + mach64.accel.src_offset >>= mach64.accel.src_size; + mach64.accel.dst_offset >>= mach64.accel.dst_size; + + mach64.accel.src_x_start = mach64.accel.src_x; + mach64.accel.dst_x_start = mach64.accel.dst_x; + +/* if (mach64.accel.source_fg == SRC_BLITSRC || mach64.accel.source_bg == SRC_BLITSRC) + {*/ + mach64.accel.xinc = (mach64.dst_cntl & 1) ? 1 : -1; + mach64.accel.yinc = (mach64.dst_cntl & 2) ? 1 : -1; +/* } + else + { + mach64.accel.xinc = mach64_inc[mach64.accel.src_pix_width]; + mach64.accel.yinc = 1; + }*/ + + mach64.accel.source_host = ((mach64.dp_src & 7) == SRC_HOST) || (((mach64.dp_src >> 8) & 7) == SRC_HOST); + + +// pclog("mach64_start_fill : pattern %08X %08X\n", mach64.pat_reg0, mach64.pat_reg1); + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + uint32_t temp = (y & 4) ? mach64.pat_reg1 : mach64.pat_reg0; + mach64.accel.pattern[y][x] = (temp >> (x + ((y & 3) * 8))) & 1; +// pclog("%i ", mach64.accel.pattern[y][x]); + } +// pclog("\n"); + } + + mach64.accel.sc_left = mach64.sc_left_right & 0x1fff; + mach64.accel.sc_right = (mach64.sc_left_right >> 16) & 0x1fff; + mach64.accel.sc_top = mach64.sc_top_bottom & 0x7fff; + mach64.accel.sc_bottom = (mach64.sc_top_bottom >> 16) & 0x7fff; + +/* mach64.accel.sc_left *= mach64_inc[mach64.accel.dst_pix_width]; + mach64.accel.sc_right *= mach64_inc[mach64.accel.dst_pix_width];*/ + + mach64.accel.dp_frgd_clr = mach64.dp_frgd_clr; + mach64.accel.dp_bkgd_clr = mach64.dp_bkgd_clr; + + mach64.accel.busy = 1; +#ifdef MACH64_DEBUG + pclog("mach64_start_fill : dst %i, %i src %i, %i size %i, %i src pitch %i offset %X dst pitch %i offset %X scissor %i %i %i %i src_fg %i\n", mach64.accel.dst_x, mach64.accel.dst_y, mach64.accel.src_x, mach64.accel.src_y, mach64.accel.dst_width, mach64.accel.dst_height, mach64.accel.src_pitch, mach64.accel.src_offset, mach64.accel.dst_pitch, mach64.accel.dst_offset, mach64.accel.sc_left, mach64.accel.sc_right, mach64.accel.sc_top, mach64.accel.sc_bottom, mach64.accel.source_fg); +#endif + mach64.accel.op = OP_RECT; +} + +void mach64_start_line() +{ + int x, y; + + mach64.accel.dst_x = (mach64.dst_y_x >> 16) & 0xfff; + mach64.accel.dst_y = mach64.dst_y_x & 0xfff; + + mach64.accel.src_x = (mach64.src_y_x >> 16) & 0xfff; + mach64.accel.src_y = mach64.src_y_x & 0xfff; + + mach64.accel.src_pitch = (mach64.src_off_pitch >> 22) * 8; + mach64.accel.src_offset = (mach64.src_off_pitch & 0xfffff) * 8; + + mach64.accel.dst_pitch = (mach64.dst_off_pitch >> 22) * 8; + mach64.accel.dst_offset = (mach64.dst_off_pitch & 0xfffff) * 8; + + mach64.accel.mix_fg = (mach64.dp_mix >> 16) & 0x1f; + mach64.accel.mix_bg = mach64.dp_mix & 0x1f; + + mach64.accel.source_bg = mach64.dp_src & 7; + mach64.accel.source_fg = (mach64.dp_src >> 8) & 7; + mach64.accel.source_mix = (mach64.dp_src >> 16) & 7; + + mach64.accel.dst_pix_width = mach64.dp_pix_width & 7; + mach64.accel.src_pix_width = (mach64.dp_pix_width >> 8) & 7; + mach64.accel.host_pix_width = (mach64.dp_pix_width >> 16) & 7; + + mach64.accel.dst_size = mach64_width[mach64.accel.dst_pix_width]; + mach64.accel.src_size = mach64_width[mach64.accel.src_pix_width]; + + mach64.accel.src_offset >>= mach64.accel.src_size; + mach64.accel.dst_offset >>= mach64.accel.dst_size; + +/* mach64.accel.src_pitch *= mach64_inc[mach64.accel.src_pix_width]; + mach64.accel.dst_pitch *= mach64_inc[mach64.accel.dst_pix_width];*/ + + mach64.accel.source_host = ((mach64.dp_src & 7) == SRC_HOST) || (((mach64.dp_src >> 8) & 7) == SRC_HOST); + + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + uint32_t temp = (y & 4) ? mach64.pat_reg1 : mach64.pat_reg0; + mach64.accel.pattern[y][x] = (temp >> (x + ((y & 3) * 8))) & 1; + } + } + + mach64.accel.sc_left = mach64.sc_left_right & 0x1fff; + mach64.accel.sc_right = (mach64.sc_left_right >> 16) & 0x1fff; + mach64.accel.sc_top = mach64.sc_top_bottom & 0x7fff; + mach64.accel.sc_bottom = (mach64.sc_top_bottom >> 16) & 0x7fff; + + mach64.accel.dp_frgd_clr = mach64.dp_frgd_clr; + mach64.accel.dp_bkgd_clr = mach64.dp_bkgd_clr; + + mach64.accel.x_count = mach64.dst_bres_lnth & 0x7fff; + mach64.accel.err = (mach64.dst_bres_err & 0x3ffff) | ((mach64.dst_bres_err & 0x40000) ? 0xfffc0000 : 0); + + mach64.accel.busy = 1; +#ifdef MACH64_DEBUG + pclog("mach64_start_line\n"); +#endif + mach64.accel.op = OP_LINE; +} + +#define READ(addr, dat, width) if (width == 0) dat = vram[((addr)) & 0x7fffff]; \ + else if (width == 1) dat = *(uint16_t *)&vram[((addr) << 1) & 0x7fffff]; \ + else dat = *(uint32_t *)&vram[((addr) << 2) & 0x7fffff]; + +#define MIX switch (mix ? mach64.accel.mix_fg : mach64.accel.mix_bg) \ + { \ + case 0x0: dest_dat = ~dest_dat; break; \ + case 0x1: dest_dat = 0; break; \ + case 0x2: dest_dat = 0xffffffff; break; \ + case 0x3: dest_dat = dest_dat; break; \ + case 0x4: dest_dat = ~src_dat; break; \ + case 0x5: dest_dat = src_dat ^ dest_dat; break; \ + case 0x6: dest_dat = ~(src_dat ^ dest_dat); break; \ + case 0x7: dest_dat = src_dat; break; \ + case 0x8: dest_dat = ~(src_dat & dest_dat); break; \ + case 0x9: dest_dat = ~src_dat | dest_dat; break; \ + case 0xa: dest_dat = src_dat | ~dest_dat; break; \ + case 0xb: dest_dat = src_dat | dest_dat; break; \ + case 0xc: dest_dat = src_dat & dest_dat; break; \ + case 0xd: dest_dat = src_dat & ~dest_dat; break; \ + case 0xe: dest_dat = ~src_dat & dest_dat; break; \ + case 0xf: dest_dat = ~(src_dat | dest_dat); break; \ + } + +#define WRITE(addr, width) if (width == 0) \ + { \ + vram[(addr) & 0x7fffff] = dest_dat; \ + changedvram[((addr) & 0x7fffff) >> 10] = changeframecount; \ + } \ + else if (width == 1) \ + { \ + *(uint16_t *)&vram[((addr) << 1) & 0x7fffff] = dest_dat; \ + changedvram[(((addr) << 1) & 0x7fffff) >> 10] = changeframecount; \ + } \ + else \ + { \ + *(uint32_t *)&vram[((addr) << 2) & 0x7fffff] = dest_dat; \ + changedvram[(((addr) << 2) & 0x7fffff) >> 10] = changeframecount; \ + } + +void mach64_blit(uint32_t cpu_dat, int count) +{ + if (!mach64.accel.busy) + { +#ifdef MACH64_DEBUG + pclog("mach64_blit : return as not busy\n"); +#endif + return; + } + switch (mach64.accel.op) + { + case OP_RECT: + while (count) + { + uint32_t src_dat, dest_dat; + uint32_t host_dat; + int mix; + + if (mach64.accel.source_host) + { + host_dat = cpu_dat; + switch (mach64.accel.src_size) + { + case 0: + cpu_dat >>= 8; + count -= 8; + break; + case 1: + cpu_dat >>= 16; + count -= 16; + break; + case 2: + count -= 32; + break; + } + } + else + count--; + + switch (mach64.accel.source_mix) + { + case MONO_SRC_HOST: + mix = cpu_dat >> 31; + cpu_dat <<= 1; + break; + case MONO_SRC_PAT: + mix = mach64.accel.pattern[mach64.accel.dst_y & 7][mach64.accel.dst_x & 7]; + break; + case MONO_SRC_1: + default: + mix = 1; + break; + } + + if (mach64.accel.dst_x >= mach64.accel.sc_left && mach64.accel.dst_x <= mach64.accel.sc_right && + mach64.accel.dst_y >= mach64.accel.sc_top && mach64.accel.dst_y <= mach64.accel.sc_bottom) + { + switch (mix ? mach64.accel.source_fg : mach64.accel.source_bg) + { + case SRC_HOST: + src_dat = host_dat; + break; + case SRC_BLITSRC: + READ(mach64.accel.src_offset + (mach64.accel.src_y * mach64.accel.src_pitch) + mach64.accel.src_x, src_dat, mach64.accel.src_size); + break; + case SRC_FG: + src_dat = mach64.accel.dp_frgd_clr; + break; + case SRC_BG: + src_dat = mach64.accel.dp_bkgd_clr; + break; + default: + src_dat = 0; + break; + } + + READ(mach64.accel.dst_offset + (mach64.accel.dst_y * mach64.accel.dst_pitch) + mach64.accel.dst_x, dest_dat, mach64.accel.dst_size); + +// pclog("Blit %i,%i %i,%i %X %X %i %02X %02X %i ", mach64.accel.src_x, mach64.accel.src_y, mach64.accel.dst_x, mach64.accel.dst_y, (mach64.accel.src_offset + (mach64.accel.src_y * mach64.accel.src_pitch) + mach64.accel.src_x) & 0x7fffff, (mach64.accel.dst_offset + (mach64.accel.dst_y * mach64.accel.dst_pitch) + mach64.accel.dst_x) & 0x7fffff, count, src_dat, dest_dat, mix); + + MIX + +// pclog("%02X %i\n", dest_dat, mach64.accel.dst_height); + + WRITE(mach64.accel.dst_offset + (mach64.accel.dst_y * mach64.accel.dst_pitch) + mach64.accel.dst_x, mach64.accel.dst_size); + } + + if (mach64.dst_cntl & DST_24_ROT_EN) + { + mach64.accel.dp_frgd_clr = ((mach64.accel.dp_frgd_clr >> 8) & 0xffff) | (mach64.accel.dp_frgd_clr << 16); + mach64.accel.dp_bkgd_clr = ((mach64.accel.dp_bkgd_clr >> 8) & 0xffff) | (mach64.accel.dp_bkgd_clr << 16); + } + + mach64.accel.src_x += mach64.accel.xinc; + mach64.accel.dst_x += mach64.accel.xinc; + mach64.accel.x_count--; + + if (mach64.accel.x_count <= 0) + { + mach64.accel.x_count = mach64.accel.dst_width; + mach64.accel.src_x = mach64.accel.src_x_start; + mach64.accel.dst_x = mach64.accel.dst_x_start; + + mach64.accel.src_y += mach64.accel.yinc; + mach64.accel.dst_y += mach64.accel.yinc; + mach64.accel.dst_height--; + + if (mach64.accel.dst_height <= 0) + { + /*Blit finished*/ +#ifdef MACH64_DEBUG + pclog("mach64 blit finished\n"); +#endif + mach64.accel.busy = 0; + return; + } + if (mach64.accel.source_host) + return; + } + } + break; + + case OP_LINE: + while (count) + { + uint32_t src_dat, dest_dat; + uint32_t host_dat; + int mix; + + if (mach64.accel.source_host) + { + host_dat = cpu_dat; + switch (mach64.accel.src_size) + { + case 0: + cpu_dat >>= 8; + count -= 8; + break; + case 1: + cpu_dat >>= 16; + count -= 16; + break; + case 2: + count -= 32; + break; + } + } + else + count--; + + switch (mach64.accel.source_mix) + { + case MONO_SRC_HOST: + mix = cpu_dat >> 31; + cpu_dat <<= 1; + break; + case MONO_SRC_PAT: + mix = mach64.accel.pattern[mach64.accel.dst_y & 7][mach64.accel.dst_x & 7]; + break; + case MONO_SRC_1: + default: + mix = 1; + break; + } + + if (mach64.accel.dst_x >= mach64.accel.sc_left && mach64.accel.dst_x <= mach64.accel.sc_right && + mach64.accel.dst_y >= mach64.accel.sc_top && mach64.accel.dst_y <= mach64.accel.sc_bottom) + { + switch (mix ? mach64.accel.source_fg : mach64.accel.source_bg) + { + case SRC_HOST: + src_dat = host_dat; + break; + case SRC_BLITSRC: + READ(mach64.accel.src_offset + (mach64.accel.src_y * mach64.accel.src_pitch) + mach64.accel.src_x, src_dat, mach64.accel.src_size); + break; + case SRC_FG: + src_dat = mach64.accel.dp_frgd_clr; + break; + case SRC_BG: + src_dat = mach64.accel.dp_bkgd_clr; + break; + default: + src_dat = 0; + break; + } + + READ(mach64.accel.dst_offset + (mach64.accel.dst_y * mach64.accel.dst_pitch) + mach64.accel.dst_x, dest_dat, mach64.accel.dst_size); + +// pclog("Blit %i,%i %i,%i %X %X %i %02X %02X %i ", mach64.accel.src_x, mach64.accel.src_y, mach64.accel.dst_x, mach64.accel.dst_y, (mach64.accel.src_offset + (mach64.accel.src_y * mach64.accel.src_pitch) + mach64.accel.src_x) & 0x7fffff, (mach64.accel.dst_offset + (mach64.accel.dst_y * mach64.accel.dst_pitch) + mach64.accel.dst_x) & 0x7fffff, count, src_dat, dest_dat, mix); + + MIX + +// pclog("%02X %i\n", dest_dat, mach64.accel.dst_height); + + WRITE(mach64.accel.dst_offset + (mach64.accel.dst_y * mach64.accel.dst_pitch) + mach64.accel.dst_x, mach64.accel.dst_size); + } + + mach64.accel.x_count--; + if (mach64.accel.x_count <= 0) + { + /*Blit finished*/ +#ifdef MACH64_DEBUG + pclog("mach64 blit finished\n"); +#endif + mach64.accel.busy = 0; + return; + } + + switch (mach64.dst_cntl & 7) + { + case 0: case 2: + mach64.accel.src_x--; + mach64.accel.dst_x--; + break; + case 1: case 3: + mach64.accel.src_x++; + mach64.accel.dst_x++; + break; + case 4: case 5: + mach64.accel.src_y--; + mach64.accel.dst_y--; + break; + case 6: case 7: + mach64.accel.src_y++; + mach64.accel.dst_y++; + break; + } +#ifdef MACH64_DEBUG + pclog("x %i y %i err %i inc %i dec %i\n", mach64.accel.dst_x, mach64.accel.dst_y, mach64.accel.err, mach64.dst_bres_inc, mach64.dst_bres_dec); +#endif + if (mach64.accel.err >= 0) + { + mach64.accel.err += mach64.dst_bres_dec; + + switch (mach64.dst_cntl & 7) + { + case 0: case 1: + mach64.accel.src_y--; + mach64.accel.dst_y--; + break; + case 2: case 3: + mach64.accel.src_y++; + mach64.accel.dst_y++; + break; + case 4: case 6: + mach64.accel.src_x--; + mach64.accel.dst_x--; + break; + case 5: case 7: + mach64.accel.src_x++; + mach64.accel.dst_x++; + break; + } + } + else + mach64.accel.err += mach64.dst_bres_inc; + } + break; + } +} + +void mach64_load_context() +{ + uint32_t addr; + + while (mach64.context_load_cntl & 0x30000) + { + addr = (0x3fff - (mach64.context_load_cntl & 0x3fff)) * 256; + mach64.context_mask = *(uint32_t *)&vram[addr]; +#ifdef MACH64_DEBUG + pclog("mach64_load_context %08X from %08X : mask %08X\n", mach64.context_load_cntl, addr, mach64.context_mask); +#endif + + if (mach64.context_mask & (1 << 2)) + mach64_ext_writel(0x100, *(uint32_t *)&vram[addr + 0x08], NULL); + if (mach64.context_mask & (1 << 3)) + mach64_ext_writel(0x10c, *(uint32_t *)&vram[addr + 0x0c], NULL); + if (mach64.context_mask & (1 << 4)) + mach64_ext_writel(0x118, *(uint32_t *)&vram[addr + 0x10], NULL); + if (mach64.context_mask & (1 << 5)) + mach64_ext_writel(0x124, *(uint32_t *)&vram[addr + 0x14], NULL); + if (mach64.context_mask & (1 << 6)) + mach64_ext_writel(0x128, *(uint32_t *)&vram[addr + 0x18], NULL); + if (mach64.context_mask & (1 << 7)) + mach64_ext_writel(0x12c, *(uint32_t *)&vram[addr + 0x1c], NULL); + if (mach64.context_mask & (1 << 8)) + mach64_ext_writel(0x180, *(uint32_t *)&vram[addr + 0x20], NULL); + if (mach64.context_mask & (1 << 9)) + mach64_ext_writel(0x18c, *(uint32_t *)&vram[addr + 0x24], NULL); + if (mach64.context_mask & (1 << 10)) + mach64_ext_writel(0x198, *(uint32_t *)&vram[addr + 0x28], NULL); + if (mach64.context_mask & (1 << 11)) + mach64_ext_writel(0x1a4, *(uint32_t *)&vram[addr + 0x2c], NULL); + if (mach64.context_mask & (1 << 12)) + mach64_ext_writel(0x1b0, *(uint32_t *)&vram[addr + 0x30], NULL); + if (mach64.context_mask & (1 << 13)) + mach64_ext_writel(0x280, *(uint32_t *)&vram[addr + 0x34], NULL); + if (mach64.context_mask & (1 << 14)) + mach64_ext_writel(0x284, *(uint32_t *)&vram[addr + 0x38], NULL); + if (mach64.context_mask & (1 << 15)) + mach64_ext_writel(0x2a8, *(uint32_t *)&vram[addr + 0x3c], NULL); + if (mach64.context_mask & (1 << 16)) + mach64_ext_writel(0x2b4, *(uint32_t *)&vram[addr + 0x40], NULL); + if (mach64.context_mask & (1 << 17)) + mach64_ext_writel(0x2c0, *(uint32_t *)&vram[addr + 0x44], NULL); + if (mach64.context_mask & (1 << 18)) + mach64_ext_writel(0x2c4, *(uint32_t *)&vram[addr + 0x48], NULL); + if (mach64.context_mask & (1 << 19)) + mach64_ext_writel(0x2c8, *(uint32_t *)&vram[addr + 0x4c], NULL); + if (mach64.context_mask & (1 << 20)) + mach64_ext_writel(0x2cc, *(uint32_t *)&vram[addr + 0x50], NULL); + if (mach64.context_mask & (1 << 21)) + mach64_ext_writel(0x2d0, *(uint32_t *)&vram[addr + 0x54], NULL); + if (mach64.context_mask & (1 << 22)) + mach64_ext_writel(0x2d4, *(uint32_t *)&vram[addr + 0x58], NULL); + if (mach64.context_mask & (1 << 23)) + mach64_ext_writel(0x2d8, *(uint32_t *)&vram[addr + 0x5c], NULL); + if (mach64.context_mask & (1 << 24)) + mach64_ext_writel(0x300, *(uint32_t *)&vram[addr + 0x60], NULL); + if (mach64.context_mask & (1 << 25)) + mach64_ext_writel(0x304, *(uint32_t *)&vram[addr + 0x64], NULL); + if (mach64.context_mask & (1 << 26)) + mach64_ext_writel(0x308, *(uint32_t *)&vram[addr + 0x68], NULL); + if (mach64.context_mask & (1 << 27)) + mach64_ext_writel(0x330, *(uint32_t *)&vram[addr + 0x6c], NULL); + + mach64.context_load_cntl = *(uint32_t *)&vram[addr + 0x70]; + } +} + +uint8_t mach64_ext_readb(uint32_t addr, void *priv) +{ + uint8_t ret; + switch (addr & 0x3ff) + { + case 0x00: case 0x01: case 0x02: case 0x03: + READ8(addr, mach64.crtc_h_total_disp); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: + READ8(addr, mach64.crtc_v_total_disp); + break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + READ8(addr, mach64.crtc_v_sync_strt_wid); + break; + + case 0x14: case 0x15: case 0x16: case 0x17: + READ8(addr, mach64.crtc_off_pitch); + break; + + case 0x18: + ret = mach64.crtc_int_cntl & ~1; + if (cgastat & 8) + ret |= 1; + break; + + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + READ8(addr, mach64.crtc_gen_cntl); + break; + + case 0x68: case 0x69: case 0x6a: case 0x6b: + READ8(addr, mach64.cur_offset); + break; + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + READ8(addr, mach64.cur_horz_vert_posn); + break; + case 0x70: case 0x71: case 0x72: case 0x73: + READ8(addr, mach64.cur_horz_vert_off); + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + READ8(addr, mach64.scratch_reg0); + break; + case 0x84: case 0x85: case 0x86: case 0x87: + READ8(addr, mach64.scratch_reg1); + break; + + case 0x90: case 0x91: case 0x92: case 0x93: + READ8(addr, mach64.clock_cntl); + break; + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + READ8(addr, mach64.mem_cntl); + break; + + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + READ8(addr, mach64.dac_cntl); + break; + + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + READ8(addr, mach64.gen_test_cntl); + break; + + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + READ8(addr, 0xd7); /*88800GX*/ + break; + + case 0x100: case 0x101: case 0x102: case 0x103: + READ8(addr, mach64.dst_off_pitch); + break; + case 0x104: case 0x105: + READ8(addr, mach64.dst_y_x); + break; + case 0x108: case 0x109: case 0x11c: case 0x11d: + READ8(addr + 2, mach64.dst_y_x); + break; + case 0x10c: case 0x10d: case 0x10e: case 0x10f: + READ8(addr, mach64.dst_y_x); + break; + case 0x110: case 0x111: + addr += 2; + case 0x114: case 0x115: + case 0x118: case 0x119: case 0x11a: case 0x11b: + case 0x11e: case 0x11f: + READ8(addr, mach64.dst_height_width); + break; + + case 0x120: case 0x121: case 0x122: case 0x123: + READ8(addr, mach64.dst_bres_lnth); + break; + case 0x124: case 0x125: case 0x126: case 0x127: + READ8(addr, mach64.dst_bres_err); + break; + case 0x128: case 0x129: case 0x12a: case 0x12b: + READ8(addr, mach64.dst_bres_inc); + break; + case 0x12c: case 0x12d: case 0x12e: case 0x12f: + READ8(addr, mach64.dst_bres_dec); + break; + + case 0x130: case 0x131: case 0x132: case 0x133: + READ8(addr, mach64.dst_cntl); + break; + + case 0x180: case 0x181: case 0x182: case 0x183: + READ8(addr, mach64.src_off_pitch); + break; + case 0x184: case 0x185: + READ8(addr, mach64.src_y_x); + break; + case 0x188: case 0x189: + READ8(addr + 2, mach64.src_y_x); + break; + case 0x18c: case 0x18d: case 0x18e: case 0x18f: + READ8(addr, mach64.src_y_x); + break; + + case 0x1b4: case 0x1b5: case 0x1b6: case 0x1b7: + READ8(addr, mach64.src_cntl); + break; + + case 0x280: case 0x281: case 0x282: case 0x283: + READ8(addr, mach64.pat_reg0); + break; + case 0x284: case 0x285: case 0x286: case 0x287: + READ8(addr, mach64.pat_reg1); + break; + + case 0x2a0: case 0x2a1: case 0x2a8: case 0x2a9: + READ8(addr, mach64.sc_left_right); + break; + case 0x2a4: case 0x2a5: + addr += 2; + case 0x2aa: case 0x2ab: + READ8(addr, mach64.sc_left_right); + break; + + case 0x2ac: case 0x2ad: case 0x2b4: case 0x2b5: + READ8(addr, mach64.sc_top_bottom); + break; + case 0x2b0: case 0x2b1: + addr += 2; + case 0x2b6: case 0x2b7: + READ8(addr, mach64.sc_top_bottom); + break; + + case 0x2c0: case 0x2c1: case 0x2c2: case 0x2c3: + READ8(addr, mach64.dp_bkgd_clr); + break; + case 0x2c4: case 0x2c5: case 0x2c6: case 0x2c7: + READ8(addr, mach64.dp_frgd_clr); + break; + + case 0x2d0: case 0x2d1: case 0x2d2: case 0x2d3: + READ8(addr, mach64.dp_pix_width); + break; + case 0x2d4: case 0x2d5: case 0x2d6: case 0x2d7: + READ8(addr, mach64.dp_mix); + break; + case 0x2d8: case 0x2d9: case 0x2da: case 0x2db: + READ8(addr, mach64.dp_src); + break; + + case 0x320: case 0x321: case 0x322: case 0x323: + READ8(addr, mach64.context_mask); + break; + + case 0x330: case 0x331: + READ8(addr, mach64.dst_cntl); + break; + case 0x332: + READ8(addr - 2, mach64.src_cntl); + break; + case 0x333: + READ8(addr - 3, mach64.pat_cntl); + break; + + default: + ret = 0; + break; + } +#ifdef MACH64_DEBUG + if ((addr & 0x3fc) != 0x018) pclog("mach64_ext_readb : addr %08X ret %02X\n", addr, ret); +#endif + return ret; +} +uint16_t mach64_ext_readw(uint32_t addr, void *priv) +{ + uint16_t ret; + switch (addr & 0x3ff) + { + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + ret = mach64_ext_readb(addr, priv); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + ret |= mach64_ext_readb(addr + 1, priv) << 8; + break; + } +#ifdef MACH64_DEBUG + if ((addr & 0x3fc) != 0x018) pclog("mach64_ext_readw : addr %08X ret %04X\n", addr, ret); +#endif + return ret; +} +uint32_t mach64_ext_readl(uint32_t addr, void *priv) +{ + uint32_t ret; + switch (addr & 0x3ff) + { + case 0x18: + ret = mach64.crtc_int_cntl & ~1; + if (cgastat & 8) + ret |= 1; + break; + + case 0xb4: + ret = (mach64_bank_w[0] >> 15) | ((mach64_bank_w[1] >> 15) << 16); + break; + case 0xb8: + ret = (mach64_bank_r[0] >> 15) | ((mach64_bank_r[1] >> 15) << 16); + break; + + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + ret = mach64_ext_readw(addr, priv); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + ret |= mach64_ext_readw(addr + 2, priv) << 16; + break; + } +#ifdef MACH64_DEBUG + if ((addr & 0x3fc) != 0x018) pclog("mach64_ext_readl : addr %08X ret %08X\n", addr, ret); +#endif + return ret; +} + +void mach64_ext_writeb(uint32_t addr, uint8_t val, void *priv) +{ +#ifdef MACH64_DEBUG + pclog("mach64_ext_writeb : addr %08X val %02X\n", addr, val); +#endif + switch (addr & 0x3ff) + { + case 0x00: case 0x01: case 0x02: case 0x03: + WRITE8(addr, mach64.crtc_h_total_disp, val); + svga_recalctimings(); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: + WRITE8(addr, mach64.crtc_v_total_disp, val); + svga_recalctimings(); + break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + WRITE8(addr, mach64.crtc_v_sync_strt_wid, val); + svga_recalctimings(); + break; + + case 0x14: case 0x15: case 0x16: case 0x17: + WRITE8(addr, mach64.crtc_off_pitch, val); + svga_recalctimings(); + fullchange = changeframecount; + break; + + case 0x18: + mach64.crtc_int_cntl = val; + break; + + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + WRITE8(addr, mach64.crtc_gen_cntl, val); + svga_recalctimings(); + break; + + case 0x68: case 0x69: case 0x6a: case 0x6b: + WRITE8(addr, mach64.cur_offset, val); + svga_hwcursor.addr = (mach64.cur_offset & 0xfffff) * 8; + mach64_cursor_dump(); + break; + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + WRITE8(addr, mach64.cur_horz_vert_posn, val); + svga_hwcursor.x = mach64.cur_horz_vert_posn & 0x7ff; + svga_hwcursor.y = (mach64.cur_horz_vert_posn >> 16) & 0x7ff; + mach64_cursor_dump(); + break; + case 0x70: case 0x71: case 0x72: case 0x73: + WRITE8(addr, mach64.cur_horz_vert_off, val); + svga_hwcursor.xoff = mach64.cur_horz_vert_off & 0x3f; + svga_hwcursor.yoff = (mach64.cur_horz_vert_off >> 16) & 0x3f; + mach64_cursor_dump(); + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + WRITE8(addr, mach64.scratch_reg0, val); + break; + case 0x84: case 0x85: case 0x86: case 0x87: + WRITE8(addr, mach64.scratch_reg1, val); + break; + + case 0x90: case 0x91: case 0x92: case 0x93: + WRITE8(addr, mach64.clock_cntl, val); + ics2595_write(val & 0x40, val & 0xf); + break; + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + WRITE8(addr, mach64.mem_cntl, val); + break; + + case 0xb4: + mach64_bank_w[0] = val * 32768; +#ifdef MACH64_DEBUG + pclog("mach64 : write bank A0000-A7FFF set to %08X\n", mach64_bank_w[0]); +#endif + break; + case 0xb5: case 0xb6: + mach64_bank_w[1] = val * 32768; +#ifdef MACH64_DEBUG + pclog("mach64 : write bank A8000-AFFFF set to %08X\n", mach64_bank_w[1]); +#endif + break; + case 0xb8: + mach64_bank_r[0] = val * 32768; +#ifdef MACH64_DEBUG + pclog("mach64 : read bank A0000-A7FFF set to %08X\n", mach64_bank_r[0]); +#endif + break; + case 0xb9: case 0xba: + mach64_bank_r[1] = val * 32768; +#ifdef MACH64_DEBUG + pclog("mach64 : read bank A8000-AFFFF set to %08X\n", mach64_bank_r[1]); +#endif + break; + + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + WRITE8(addr, mach64.dac_cntl, val); + break; + + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + WRITE8(addr, mach64.gen_test_cntl, val); +// if (val == 2) output = 3; + ati_eeprom_write(mach64.gen_test_cntl & 0x10, mach64.gen_test_cntl & 2, mach64.gen_test_cntl & 1); + mach64.gen_test_cntl = (mach64.gen_test_cntl & ~8) | (ati_eeprom_read() ? 8 : 0); + svga_hwcursor.ena = mach64.gen_test_cntl & 0x80; + mach64_cursor_dump(); + break; + + case 0x100: case 0x101: case 0x102: case 0x103: + WRITE8(addr, mach64.dst_off_pitch, val); + break; + case 0x104: case 0x105: case 0x11c: case 0x11d: + WRITE8(addr + 2, mach64.dst_y_x, val); + break; + case 0x108: case 0x109: + WRITE8(addr, mach64.dst_y_x, val); + break; + case 0x10c: case 0x10d: case 0x10e: case 0x10f: + WRITE8(addr, mach64.dst_y_x, val); + break; + case 0x110: case 0x111: + addr += 2; + case 0x114: case 0x115: + case 0x118: case 0x119: case 0x11a: case 0x11b: + case 0x11e: case 0x11f: + WRITE8(addr, mach64.dst_height_width, val); + if ((addr & 0x3ff) == 0x11b || (addr & 0x3ff) == 0x11f) + { + mach64_start_fill(); +#ifdef MACH64_DEBUG + pclog("%i %i %i %i %i\n", (mach64.dst_height_width & 0x7ff), (mach64.dst_height_width & 0x7ff0000), + ((mach64.dp_src & 7) != SRC_HOST), (((mach64.dp_src >> 8) & 7) != SRC_HOST), + (((mach64.dp_src >> 16) & 3) != MONO_SRC_HOST)); +#endif + if ((mach64.dst_height_width & 0x7ff) && (mach64.dst_height_width & 0x7ff0000) && + ((mach64.dp_src & 7) != SRC_HOST) && (((mach64.dp_src >> 8) & 7) != SRC_HOST) && + (((mach64.dp_src >> 16) & 3) != MONO_SRC_HOST)) + mach64_blit(0, -1); + } + break; + + case 0x120: case 0x121: case 0x122: case 0x123: + WRITE8(addr, mach64.dst_bres_lnth, val); + if ((addr & 0x3ff) == 0x123 && !(val & 0x80)) + { + mach64_start_line(); + + if ((mach64.dst_bres_lnth & 0x7fff) && + ((mach64.dp_src & 7) != SRC_HOST) && (((mach64.dp_src >> 8) & 7) != SRC_HOST) && + (((mach64.dp_src >> 16) & 3) != MONO_SRC_HOST)) + mach64_blit(0, -1); + } + break; + case 0x124: case 0x125: case 0x126: case 0x127: + WRITE8(addr, mach64.dst_bres_err, val); + break; + case 0x128: case 0x129: case 0x12a: case 0x12b: + WRITE8(addr, mach64.dst_bres_inc, val); + break; + case 0x12c: case 0x12d: case 0x12e: case 0x12f: + WRITE8(addr, mach64.dst_bres_dec, val); + break; + + case 0x130: case 0x131: case 0x132: case 0x133: + WRITE8(addr, mach64.dst_cntl, val); + break; + + case 0x180: case 0x181: case 0x182: case 0x183: + WRITE8(addr, mach64.src_off_pitch, val); + break; + case 0x184: case 0x185: + WRITE8(addr, mach64.src_y_x, val); + break; + case 0x188: case 0x189: + WRITE8(addr + 2, mach64.src_y_x, val); + break; + case 0x18c: case 0x18d: case 0x18e: case 0x18f: + WRITE8(addr, mach64.src_y_x, val); + break; + + case 0x1b4: case 0x1b5: case 0x1b6: case 0x1b7: + WRITE8(addr, mach64.src_cntl, val); + break; + + case 0x200: case 0x201: case 0x202: case 0x203: + case 0x204: case 0x205: case 0x206: case 0x207: + case 0x208: case 0x209: case 0x20a: case 0x20b: + case 0x20c: case 0x20d: case 0x20e: case 0x20f: + case 0x210: case 0x211: case 0x212: case 0x213: + case 0x214: case 0x215: case 0x216: case 0x217: + case 0x218: case 0x219: case 0x21a: case 0x21b: + case 0x21c: case 0x21d: case 0x21e: case 0x21f: + case 0x220: case 0x221: case 0x222: case 0x223: + case 0x224: case 0x225: case 0x226: case 0x227: + case 0x228: case 0x229: case 0x22a: case 0x22b: + case 0x22c: case 0x22d: case 0x22e: case 0x22f: + case 0x230: case 0x231: case 0x232: case 0x233: + case 0x234: case 0x235: case 0x236: case 0x237: + case 0x238: case 0x239: case 0x23a: case 0x23b: + case 0x23c: case 0x23d: case 0x23e: case 0x23f: + mach64_blit(val, 8); + break; + + case 0x280: case 0x281: case 0x282: case 0x283: + WRITE8(addr, mach64.pat_reg0, val); + break; + case 0x284: case 0x285: case 0x286: case 0x287: + WRITE8(addr, mach64.pat_reg1, val); + break; + + case 0x2a0: case 0x2a1: case 0x2a8: case 0x2a9: + WRITE8(addr, mach64.sc_left_right, val); + break; + case 0x2a4: case 0x2a5: + addr += 2; + case 0x2aa: case 0x2ab: + WRITE8(addr, mach64.sc_left_right, val); + break; + + case 0x2ac: case 0x2ad: case 0x2b4: case 0x2b5: + WRITE8(addr, mach64.sc_top_bottom, val); + break; + case 0x2b0: case 0x2b1: + addr += 2; + case 0x2b6: case 0x2b7: + WRITE8(addr, mach64.sc_top_bottom, val); + break; + + case 0x2c0: case 0x2c1: case 0x2c2: case 0x2c3: + WRITE8(addr, mach64.dp_bkgd_clr, val); + break; + case 0x2c4: case 0x2c5: case 0x2c6: case 0x2c7: + WRITE8(addr, mach64.dp_frgd_clr, val); + break; + + case 0x2d0: case 0x2d1: case 0x2d2: case 0x2d3: + WRITE8(addr, mach64.dp_pix_width, val); + break; + case 0x2d4: case 0x2d5: case 0x2d6: case 0x2d7: + WRITE8(addr, mach64.dp_mix, val); + break; + case 0x2d8: case 0x2d9: case 0x2da: case 0x2db: + WRITE8(addr, mach64.dp_src, val); + break; + + case 0x320: case 0x321: case 0x322: case 0x323: + WRITE8(addr, mach64.context_mask, val); + break; + + case 0x330: case 0x331: + WRITE8(addr, mach64.dst_cntl, val); + break; + case 0x332: + WRITE8(addr - 2, mach64.src_cntl, val); + break; + case 0x333: + WRITE8(addr - 3, mach64.pat_cntl, val & 7); + break; + } +} +void mach64_ext_writew(uint32_t addr, uint16_t val, void *priv) +{ +#ifdef MACH64_DEBUG + pclog("mach64_ext_writew : addr %08X val %04X\n", addr, val); +#endif + switch (addr & 0x3fe) + { + case 0x200: case 0x202: case 0x204: case 0x206: + case 0x208: case 0x20a: case 0x20c: case 0x20e: + case 0x210: case 0x212: case 0x214: case 0x216: + case 0x218: case 0x21a: case 0x21c: case 0x21e: + case 0x220: case 0x222: case 0x224: case 0x226: + case 0x228: case 0x22a: case 0x22c: case 0x22e: + case 0x230: case 0x232: case 0x234: case 0x236: + case 0x238: case 0x23a: case 0x23c: case 0x23e: + mach64_blit(val, 16); + break; + + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_ext_writeb(addr, val, priv); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_ext_writeb(addr + 1, val >> 8, priv); + break; + } +} +void mach64_ext_writel(uint32_t addr, uint32_t val, void *priv) +{ +#ifdef MACH64_DEBUG + if ((addr & 0x3c0) != 0x200) + pclog("mach64_ext_writel : addr %08X val %08X\n", addr, val); +#endif + switch (addr & 0x3fc) + { + case 0x32c: + mach64.context_load_cntl = val; + if (val & 0x30000) + mach64_load_context(); + break; + + case 0x200: case 0x204: case 0x208: case 0x20c: + case 0x210: case 0x214: case 0x218: case 0x21c: + case 0x220: case 0x224: case 0x228: case 0x22c: + case 0x230: case 0x234: case 0x238: case 0x23c: + if (mach64.accel.source_host) + mach64_blit(val, 32); + else + mach64_blit(((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24), 32); + break; + + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_ext_writew(addr, val, priv); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_ext_writew(addr + 2, val >> 16, priv); + break; + } +} + +uint8_t mach64_ext_inb(uint16_t port, void *priv) +{ + uint8_t ret; +// if (CS == 0x2be7) output = 3; + switch (port) + { + case 0x02ec: case 0x02ed: case 0x02ee: case 0x02ef: + ret = mach64_ext_readb(0x00 | (port & 3), NULL); + break; + case 0x0aec: case 0x0aed: case 0x0aee: case 0x0aef: + ret = mach64_ext_readb(0x08 | (port & 3), NULL); + break; + case 0x0eec: case 0x0eed: case 0x0eee: case 0x0eef: + ret = mach64_ext_readb(0x0c | (port & 3), NULL); + break; + + case 0x16ec: case 0x16ed: case 0x16ee: case 0x16ef: + ret = mach64_ext_readb(0x14 | (port & 3), NULL); + break; + + case 0x1aec: + ret = mach64_ext_readb(0x18, NULL); + break; + + case 0x1eec: case 0x1eed: case 0x1eee: case 0x1eef: + ret = mach64_ext_readb(0x1c | (port & 3), NULL); + break; + + case 0x36ec: case 0x36ed: case 0x36ee: case 0x36ef: + ret = mach64_ext_readb(0x68 | (port & 3), NULL); + break; + case 0x3aec: case 0x3aed: case 0x3aee: case 0x3aef: + ret = mach64_ext_readb(0x6c | (port & 3), NULL); + break; + case 0x3eec: case 0x3eed: case 0x3eee: case 0x3eef: + ret = mach64_ext_readb(0x70 | (port & 3), NULL); + break; + + case 0x42ec: case 0x42ed: case 0x42ee: case 0x42ef: + ret = mach64_ext_readb(0x80 | (port & 3), NULL); + break; + case 0x46ec: case 0x46ed: case 0x46ee: case 0x46ef: + ret = mach64_ext_readb(0x84 | (port & 3), NULL); + break; + case 0x4aec: case 0x4aed: case 0x4aee: case 0x4aef: + ret = mach64_ext_readb(0x90 | (port & 3), NULL); + break; + + case 0x52ec: case 0x52ed: case 0x52ee: case 0x52ef: + ret = mach64_ext_readb(0xb0 | (port & 3), NULL); + break; + + case 0x56ec: + ret = mach64_ext_readb(0xb4, NULL); + break; + case 0x56ed: case 0x56ee: + ret = mach64_ext_readb(0xb5, NULL); + break; + case 0x5aec: + ret = mach64_ext_readb(0xb8, NULL); + break; + case 0x5aed: case 0x5aee: + ret = mach64_ext_readb(0xb9, NULL); + break; + + case 0x5eec: case 0x5eed: case 0x5eee: case 0x5eef: + ret = ati68860_ramdac_in((port & 3) | ((mach64.dac_cntl & 3) << 2), NULL); + break; + + case 0x62ec: case 0x62ed: case 0x62ee: case 0x62ef: + ret = mach64_ext_readb(0xc4 | (port & 3), NULL); + break; + + case 0x66ec: case 0x66ed: case 0x66ee: case 0x66ef: + ret = mach64_ext_readb(0xd0 | (port & 3), NULL); + break; + + case 0x6aec: case 0x6aed: case 0x6aee: case 0x6aef: + READ8(port, mach64.config_cntl); + break; + + case 0x6eec: case 0x6eed: case 0x6eee: case 0x6eef: + ret = mach64_ext_readb(0xe0 | (port & 3), NULL); + break; + + case 0x72ec: + ret = 6 | (3 << 3); /*VLB, 256Kx16 DRAM*/ + break; + + default: + ret = 0; + break; + } +#ifdef MACH64_DEBUG + pclog("mach64_ext_inb : port %04X ret %02X %04X:%04X\n", port, ret, CS,pc); +#endif + return ret; +} +uint16_t mach64_ext_inw(uint16_t port, void *priv) +{ + uint16_t ret; + switch (port) + { + default: + pclog(" "); + ret = mach64_ext_inb(port, priv); + pclog(" "); + ret |= (mach64_ext_inb(port + 1, priv) << 8); + break; + } +#ifdef MACH64_DEBUG + pclog("mach64_ext_inw : port %04X ret %04X\n", port, ret); +#endif + return ret; +} +uint32_t mach64_ext_inl(uint16_t port, void *priv) +{ + uint32_t ret; + switch (port) + { + case 0x56ec: + ret = mach64_ext_readl(0xb4, NULL); + break; + case 0x5aec: + ret = mach64_ext_readl(0xb8, NULL); + break; + + default: + pclog(" "); + ret = mach64_ext_inw(port, priv); + pclog(" "); + ret |= (mach64_ext_inw(port + 2, priv) << 16); + break; + } +#ifdef MACH64_DEBUG + pclog("mach64_ext_inl : port %04X ret %08X\n", port, ret); +#endif + return ret; +} + +void mach64_ext_outb(uint16_t port, uint8_t val, void *priv) +{ +#ifdef MACH64_DEBUG + pclog("mach64_ext_outb : port %04X val %02X %04X:%04X\n", port, val, CS,pc); +#endif + switch (port) + { + case 0x02ec: case 0x02ed: case 0x02ee: case 0x02ef: + case 0x7eec: case 0x7eed: case 0x7eee: case 0x7eef: + mach64_ext_writeb(0x00 | (port & 3), val, NULL); + break; + case 0x0aec: case 0x0aed: case 0x0aee: case 0x0aef: + mach64_ext_writeb(0x08 | (port & 3), val, NULL); + break; + case 0x0eec: case 0x0eed: case 0x0eee: case 0x0eef: + mach64_ext_writeb(0x0c | (port & 3), val, NULL); + break; + + case 0x16ec: case 0x16ed: case 0x16ee: case 0x16ef: + mach64_ext_writeb(0x14 | (port & 3), val, NULL); + break; + + case 0x1aec: + mach64_ext_writeb(0x18, val, NULL); + break; + + case 0x1eec: case 0x1eed: case 0x1eee: case 0x1eef: + mach64_ext_writeb(0x1c | (port & 3), val, NULL); + break; + + case 0x36ec: case 0x36ed: case 0x36ee: case 0x36ef: + mach64_ext_writeb(0x68 | (port & 3), val, NULL); + break; + case 0x3aec: case 0x3aed: case 0x3aee: case 0x3aef: + mach64_ext_writeb(0x6c | (port & 3), val, NULL); + break; + case 0x3eec: case 0x3eed: case 0x3eee: case 0x3eef: + mach64_ext_writeb(0x70 | (port & 3), val, NULL); + break; + + case 0x42ec: case 0x42ed: case 0x42ee: case 0x42ef: + mach64_ext_writeb(0x80 | (port & 3), val, NULL); + break; + case 0x46ec: case 0x46ed: case 0x46ee: case 0x46ef: + mach64_ext_writeb(0x84 | (port & 3), val, NULL); + break; + case 0x4aec: case 0x4aed: case 0x4aee: case 0x4aef: + mach64_ext_writeb(0x90 | (port & 3), val, NULL); + break; + + case 0x52ec: case 0x52ed: case 0x52ee: case 0x52ef: + mach64_ext_writeb(0xb0 | (port & 3), val, NULL); + break; + + case 0x56ec: + mach64_ext_writeb(0xb4, val, NULL); + break; + case 0x56ed: case 0x56ee: + mach64_ext_writeb(0xb5, val, NULL); + break; + case 0x5aec: + mach64_ext_writeb(0xb8, val, NULL); + break; + case 0x5aed: case 0x5aee: + mach64_ext_writeb(0xb9, val, NULL); + break; + + case 0x5eec: case 0x5eed: case 0x5eee: case 0x5eef: + ati68860_ramdac_out((port & 3) | ((mach64.dac_cntl & 3) << 2), val, NULL); + break; + + case 0x62ec: case 0x62ed: case 0x62ee: case 0x62ef: + mach64_ext_writeb(0xc4 | (port & 3), val, NULL); + break; + + case 0x66ec: case 0x66ed: case 0x66ee: case 0x66ef: + mach64_ext_writeb(0xd0 | (port & 3), val, NULL); + break; + + case 0x6aec: case 0x6aed: case 0x6aee: case 0x6aef: + WRITE8(port, mach64.config_cntl, val); + break; + } +} +void mach64_ext_outw(uint16_t port, uint16_t val, void *priv) +{ +#ifdef MACH64_DEBUG + pclog("mach64_ext_outw : port %04X val %04X\n", port, val); +#endif + switch (port) + { + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_ext_outb(port, val, priv); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_ext_outb(port + 1, val >> 8, priv); + break; + } +} +void mach64_ext_outl(uint16_t port, uint32_t val, void *priv) +{ + pclog("mach64_ext_outl : port %04X val %08X\n", port, val); + switch (port) + { + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_ext_outw(port, val, priv); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_ext_outw(port + 2, val >> 16, priv); + break; + } +} + +void mach64_write(uint32_t addr, uint8_t val, void *priv) +{ +// pclog("mach64_write : %05X %02X ", addr, val); + addr = (addr & 0x7fff) + mach64_bank_w[(addr >> 15) & 1]; +// pclog("%08X\n", addr); + svga_write_linear(addr, val, priv); +} + +uint8_t mach64_read(uint32_t addr, void *priv) +{ + uint8_t ret; +// pclog("mach64_read : %05X ", addr); + addr = (addr & 0x7fff) + mach64_bank_r[(addr >> 15) & 1]; + ret = svga_read_linear(addr, priv); +// pclog("%08X %02X\n", addr, ret); + return ret; +} + +void mach64_hwcursor_draw(int displine) +{ + int x, offset; + uint8_t dat; + offset = svga_hwcursor_latch.xoff; + for (x = 0; x < 64 - svga_hwcursor_latch.xoff; x += 4) + { + dat = vram[svga_hwcursor_latch.addr + (offset >> 2)]; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine])[svga_hwcursor_latch.x + x + 32] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine])[svga_hwcursor_latch.x + x + 32] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine])[svga_hwcursor_latch.x + x + 33] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine])[svga_hwcursor_latch.x + x + 33] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine])[svga_hwcursor_latch.x + x + 34] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine])[svga_hwcursor_latch.x + x + 34] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine])[svga_hwcursor_latch.x + x + 35] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine])[svga_hwcursor_latch.x + x + 35] ^= 0xFFFFFF; + dat >>= 2; + offset += 4; + } + svga_hwcursor_latch.addr += 16; +} + +int mach64_init() +{ + int c; + + svga_recalctimings_ex = mach64_recalctimings; + svga_hwcursor_draw = mach64_hwcursor_draw; + + svga_vram_limit = 1 << 22; /*4mb*/ + vrammask = 0x3fffff; + + for (c = 0; c < 8; c++) + { + io_sethandler((c * 0x1000) + 0x2ec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, NULL); + io_sethandler((c * 0x1000) + 0x6ec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, NULL); + io_sethandler((c * 0x1000) + 0xaec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, NULL); + io_sethandler((c * 0x1000) + 0xeec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, NULL); + } + + io_sethandler(0x01ce, 0x0002, mach64_in, NULL, NULL, mach64_out, NULL, NULL, NULL); + + ati_eeprom_load("mach64.nvr", 1); + + mach64.dac_cntl = 5 << 16; /*ATI 68860 RAMDAC*/ + + mach64.dst_cntl = 3; + return svga_init(); +} + +GFXCARD vid_mach64 = +{ + mach64_init, + /*IO at 3Cx/3Dx*/ + mach64_out, + mach64_in, + /*IO at 3Ax/3Bx*/ + video_out_null, + video_in_null, + + svga_poll, + svga_recalctimings, + + svga_write, + video_write_null, + video_write_null, + + svga_read, + video_read_null, + video_read_null +}; diff --git a/src/vid_cl5429.c b/src/vid_cl5429.c new file mode 100644 index 0000000..2214a9c --- /dev/null +++ b/src/vid_cl5429.c @@ -0,0 +1,850 @@ +/*Cirrus Logic CL-GD5429 emulation*/ +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_unk_ramdac.h" + +struct +{ + uint32_t bank[2]; + + struct + { + uint16_t bg_col, fg_col; + uint16_t width, height; + uint16_t dst_pitch, src_pitch; + uint32_t dst_addr, src_addr; + uint8_t mask, mode, rop; + + uint32_t dst_addr_backup, src_addr_backup; + uint16_t width_backup, height_internal; + int x_count; + } blt; + +} gd5429; + +void gd5429_write(uint32_t addr, uint8_t val, void *priv); +uint8_t gd5429_read(uint32_t addr, void *priv); + +void gd5429_mmio_write(uint32_t addr, uint8_t val, void *priv); +uint8_t gd5429_mmio_read(uint32_t addr, void *priv); + +void gd5429_blt_write_w(uint32_t addr, uint16_t val, void *priv); +void gd5429_blt_write_l(uint32_t addr, uint32_t val, void *priv); + +void gd5429_recalc_banking(); +void gd5429_recalc_mapping(); + +void gd5429_out(uint16_t addr, uint8_t val, void *priv) +{ + uint8_t old; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60; + + pclog("gd5429 out %04X %02X\n", addr, val); + + switch (addr) + { + case 0x3c4: + seqaddr = val; + break; + case 0x3c5: + if (seqaddr > 5) + { + seqregs[seqaddr & 0x1f] = val; + switch (seqaddr & 0x1f) + { + case 0x10: case 0x30: case 0x50: case 0x70: + case 0x90: case 0xb0: case 0xd0: case 0xf0: + svga_hwcursor.x = (val << 3) | ((seqaddr >> 5) & 7); + pclog("svga_hwcursor.x = %i\n", svga_hwcursor.x); + break; + case 0x11: case 0x31: case 0x51: case 0x71: + case 0x91: case 0xb1: case 0xd1: case 0xf1: + svga_hwcursor.y = (val << 3) | ((seqaddr >> 5) & 7); + pclog("svga_hwcursor.y = %i\n", svga_hwcursor.y); + break; + case 0x12: + svga_hwcursor.ena = val & 1; + pclog("svga_hwcursor.ena = %i\n", svga_hwcursor.ena); + break; + case 0x13: + svga_hwcursor.addr = 0x1fc000 + ((val & 0x3f) * 256); + pclog("svga_hwcursor.addr = %x\n", svga_hwcursor.addr); + break; + + case 0x17: + gd5429_recalc_mapping(); + break; + } + return; + } + break; + + case 0x3cf: + if (gdcaddr == 5) + { + gdcreg[5] = val; + if (gdcreg[0xb] & 0x04) + writemode = gdcreg[5] & 7; + else + writemode = gdcreg[5] & 3; + readmode = val & 8; + pclog("writemode = %i\n", writemode); + return; + } + if (gdcaddr == 6) + { + if ((gdcreg[6] & 0xc) != (val & 0xc)) + { + gdcreg[6] = val; + gd5429_recalc_mapping(); + } + gdcreg[6] = val; + return; + } + if (gdcaddr > 8) + { + gdcreg[gdcaddr & 0x3f] = val; + switch (gdcaddr) + { + case 0x09: case 0x0a: case 0x0b: + gd5429_recalc_banking(); + if (gdcreg[0xb] & 0x04) + writemode = gdcreg[5] & 7; + else + writemode = gdcreg[5] & 3; + break; + } + return; + } + break; + + case 0x3D4: + crtcreg = val & 0x3f; + return; + case 0x3D5: + if (crtcreg <= 7 && crtc[0x11] & 0x80) return; + old=crtc[crtcreg]; + crtc[crtcreg]=val; + + if (old!=val) + { + if (crtcreg<0xE || crtcreg>0x10) + { + fullchange=changeframecount; + svga_recalctimings(); + } + } + break; + } + svga_out(addr, val, NULL); +} + +uint8_t gd5429_in(uint16_t addr, void *priv) +{ + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60; + + if (addr != 0x3da) pclog("IN gd5429 %04X\n", addr); + + switch (addr) + { + case 0x3c5: + if (seqaddr > 5) + { + switch (seqaddr) + { + case 6: + return ((seqregs[6] & 0x17) == 0x12) ? 0x12 : 0x0f; + } + return seqregs[seqaddr & 0x3f]; + } + break; + + case 0x3cf: + if (gdcaddr > 8) + { + return gdcreg[seqaddr & 0x3f]; + } + break; + + case 0x3D4: + return crtcreg; + case 0x3D5: + switch (crtcreg) + { + case 0x27: /*ID*/ + return 0x9c; /*GD5429*/ + } + return crtc[crtcreg]; + } + return svga_in(addr, NULL); +} + +void gd5429_recalc_banking() +{ + if (gdcreg[0xb] & 0x20) + gd5429.bank[0] = (gdcreg[0x09] & 0x7f) << 14; + else + gd5429.bank[0] = gdcreg[0x09] << 12; + + if (gdcreg[0xb] & 0x01) + { + if (gdcreg[0xb] & 0x20) + gd5429.bank[1] = (gdcreg[0x0a] & 0x7f) << 14; + else + gd5429.bank[1] = gdcreg[0x0a] << 12; + } + else + gd5429.bank[1] = gd5429.bank[0] + 0x8000; +} + +void gd5429_recalc_mapping() +{ + mem_removehandler(0xa0000, 0x20000, gd5429_read, NULL, NULL, gd5429_write, NULL, NULL, NULL); + mem_removehandler(0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL); + mem_removehandler(0xb8000, 0x00100, gd5429_mmio_read, NULL, NULL, gd5429_mmio_write, NULL, NULL, NULL); + pclog("Write mapping %02X %i\n", gdcreg[6], seqregs[0x17] & 0x04); + switch (gdcreg[6] & 0x0C) + { + case 0x0: /*128k at A0000*/ + mem_sethandler(0xa0000, 0x10000, gd5429_read, NULL, NULL, gd5429_write, NULL, NULL, NULL); + break; + case 0x4: /*64k at A0000*/ + mem_sethandler(0xa0000, 0x10000, gd5429_read, NULL, NULL, gd5429_write, NULL, NULL, NULL); + if (seqregs[0x17] & 0x04) + mem_sethandler(0xb8000, 0x00100, gd5429_mmio_read, NULL, NULL, gd5429_mmio_write, NULL, NULL, NULL); + break; + case 0x8: /*32k at B0000*/ + mem_sethandler(0xb0000, 0x08000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL); + break; + case 0xC: /*32k at B8000*/ + mem_sethandler(0xb8000, 0x08000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL); + break; + } +} + +void gd5429_recalctimings() +{ + if (seqregs[7] & 0x01) + { + svga_render = svga_render_8bpp_highres; + } + + svga_ma |= ((crtc[0x1b] & 0x01) << 16) | ((crtc[0x1b] & 0xc) << 15); + pclog("MA now %05X %02X\n", svga_ma, crtc[0x1b]); +} + +void gd5429_hwcursor_draw(int displine) +{ + int x; + uint8_t dat[2]; + int xx; + int offset = svga_hwcursor_latch.x - svga_hwcursor_latch.xoff; + + pclog("HWcursor %i %i %i %i %x %02X %02X\n", svga_hwcursor_latch.x, svga_hwcursor_latch.y, offset, displine, svga_hwcursor_latch.addr, vram[svga_hwcursor_latch.addr], vram[svga_hwcursor_latch.addr + 0x80]); + for (x = 0; x < 32; x += 8) + { + dat[0] = vram[svga_hwcursor_latch.addr]; + dat[1] = vram[svga_hwcursor_latch.addr + 0x80]; + for (xx = 0; xx < 8; xx++) + { + if (offset >= svga_hwcursor_latch.x) + { + if (dat[1] & 0x80) + ((uint32_t *)buffer32->line[displine])[offset + 32] = 0; + if (dat[0] & 0x80) + ((uint32_t *)buffer32->line[displine])[offset + 32] ^= 0xffffff; + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + svga_hwcursor_latch.addr++; + } +} + +int gd5429_init() +{ + svga_recalctimings_ex = gd5429_recalctimings; + svga_hwcursor_draw = gd5429_hwcursor_draw; + svga_vram_limit = 2 << 20; /*2mb*/ + vrammask = 0x1fffff; + + svga_hwcursor.yoff = 32; + svga_hwcursor.xoff = 0; + + memset(&gd5429, 0, sizeof(gd5429)); + + gd5429.bank[1] = 0x8000; + + return svga_init(); +} + +static uint8_t la, lb, lc, ld; + +uint8_t gd5429_read_linear(uint32_t addr, void *priv); +void gd5429_write_linear(uint32_t addr, uint8_t val, void *priv); + +void gd5429_write(uint32_t addr, uint8_t val, void *priv) +{ +// pclog("gd5429_write : %05X %02X ", addr, val); + addr = (addr & 0x7fff) + gd5429.bank[(addr >> 15) & 1]; +// pclog("%08X\n", addr); + gd5429_write_linear(addr, val, priv); +} + +uint8_t gd5429_read(uint32_t addr, void *priv) +{ + uint8_t ret; +// pclog("gd5429_read : %05X ", addr); + addr = (addr & 0x7fff) + gd5429.bank[(addr >> 15) & 1]; + ret = gd5429_read_linear(addr, priv); +// pclog("%08X %02X\n", addr, ret); + return ret; +} + +void gd5429_write_linear(uint32_t addr, uint8_t val, void *priv) +{ + uint8_t vala,valb,valc,vald,wm=writemask; + int writemask2 = writemask; + + cycles -= video_timing_b; + cycles_lost += video_timing_b; + + egawrites++; + +// if (svga_output) pclog("Write LFB %08X %02X ", addr, val); + if (!(gdcreg[6]&1)) fullchange=2; + if (chain4 && (writemode < 4)) + { + writemask2=1<<(addr&3); + addr&=~3; + } + else + { + addr<<=2; + } + addr &= 0x7fffff; +// if (svga_output) pclog("%08X\n", addr); + changedvram[addr>>10]=changeframecount; + + switch (writemode) + { + case 4: + pclog("Writemode 4 : %X ", addr); + addr <<= 1; + changedvram[addr>>10]=changeframecount; + pclog("%X %X\n", addr, val); + if (val & 0x80) + vram[addr + 0] = gdcreg[1]; + if (val & 0x40) + vram[addr + 1] = gdcreg[1]; + if (val & 0x20) + vram[addr + 2] = gdcreg[1]; + if (val & 0x10) + vram[addr + 3] = gdcreg[1]; + if (val & 0x08) + vram[addr + 4] = gdcreg[1]; + if (val & 0x04) + vram[addr + 5] = gdcreg[1]; + if (val & 0x02) + vram[addr + 6] = gdcreg[1]; + if (val & 0x01) + vram[addr + 7] = gdcreg[1]; + break; + + case 5: + pclog("Writemode 5 : %X ", addr); + addr <<= 1; + changedvram[addr>>10]=changeframecount; + pclog("%X %X\n", addr, val); + vram[addr + 0] = (val & 0x80) ? gdcreg[1] : gdcreg[0]; + vram[addr + 1] = (val & 0x40) ? gdcreg[1] : gdcreg[0]; + vram[addr + 2] = (val & 0x20) ? gdcreg[1] : gdcreg[0]; + vram[addr + 3] = (val & 0x10) ? gdcreg[1] : gdcreg[0]; + vram[addr + 4] = (val & 0x08) ? gdcreg[1] : gdcreg[0]; + vram[addr + 5] = (val & 0x04) ? gdcreg[1] : gdcreg[0]; + vram[addr + 6] = (val & 0x02) ? gdcreg[1] : gdcreg[0]; + vram[addr + 7] = (val & 0x01) ? gdcreg[1] : gdcreg[0]; + break; + + case 1: + if (writemask2&1) vram[addr]=la; + if (writemask2&2) vram[addr|0x1]=lb; + if (writemask2&4) vram[addr|0x2]=lc; + if (writemask2&8) vram[addr|0x3]=ld; + break; + case 0: + if (gdcreg[3]&7) val=svga_rotate[gdcreg[3]&7][val]; + if (gdcreg[8]==0xFF && !(gdcreg[3]&0x18) && !gdcreg[1]) + { + if (writemask2&1) vram[addr]=val; + if (writemask2&2) vram[addr|0x1]=val; + if (writemask2&4) vram[addr|0x2]=val; + if (writemask2&8) vram[addr|0x3]=val; + } + else + { + if (gdcreg[1]&1) vala=(gdcreg[0]&1)?0xFF:0; + else vala=val; + if (gdcreg[1]&2) valb=(gdcreg[0]&2)?0xFF:0; + else valb=val; + if (gdcreg[1]&4) valc=(gdcreg[0]&4)?0xFF:0; + else valc=val; + if (gdcreg[1]&8) vald=(gdcreg[0]&8)?0xFF:0; + else vald=val; + + switch (gdcreg[3]&0x18) + { + case 0: /*Set*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])|(la&~gdcreg[8]); + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|(lb&~gdcreg[8]); + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|(lc&~gdcreg[8]); + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|(ld&~gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2&1) vram[addr]=(vala|~gdcreg[8])&la; + if (writemask2&2) vram[addr|0x1]=(valb|~gdcreg[8])&lb; + if (writemask2&4) vram[addr|0x2]=(valc|~gdcreg[8])&lc; + if (writemask2&8) vram[addr|0x3]=(vald|~gdcreg[8])&ld; + break; + case 0x10: /*OR*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])|la; + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|lb; + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|lc; + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|ld; + break; + case 0x18: /*XOR*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])^la; + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])^lb; + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])^lc; + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])^ld; + break; + } +// pclog("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); + } + break; + case 2: + if (!(gdcreg[3]&0x18) && !gdcreg[1]) + { + if (writemask2&1) vram[addr]=(((val&1)?0xFF:0)&gdcreg[8])|(la&~gdcreg[8]); + if (writemask2&2) vram[addr|0x1]=(((val&2)?0xFF:0)&gdcreg[8])|(lb&~gdcreg[8]); + if (writemask2&4) vram[addr|0x2]=(((val&4)?0xFF:0)&gdcreg[8])|(lc&~gdcreg[8]); + if (writemask2&8) vram[addr|0x3]=(((val&8)?0xFF:0)&gdcreg[8])|(ld&~gdcreg[8]); + } + else + { + vala=((val&1)?0xFF:0); + valb=((val&2)?0xFF:0); + valc=((val&4)?0xFF:0); + vald=((val&8)?0xFF:0); + switch (gdcreg[3]&0x18) + { + case 0: /*Set*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])|(la&~gdcreg[8]); + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|(lb&~gdcreg[8]); + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|(lc&~gdcreg[8]); + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|(ld&~gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2&1) vram[addr]=(vala|~gdcreg[8])&la; + if (writemask2&2) vram[addr|0x1]=(valb|~gdcreg[8])&lb; + if (writemask2&4) vram[addr|0x2]=(valc|~gdcreg[8])&lc; + if (writemask2&8) vram[addr|0x3]=(vald|~gdcreg[8])&ld; + break; + case 0x10: /*OR*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])|la; + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|lb; + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|lc; + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|ld; + break; + case 0x18: /*XOR*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])^la; + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])^lb; + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])^lc; + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])^ld; + break; + } + } + break; + case 3: + if (gdcreg[3]&7) val=svga_rotate[gdcreg[3]&7][val]; + wm=gdcreg[8]; + gdcreg[8]&=val; + + vala=(gdcreg[0]&1)?0xFF:0; + valb=(gdcreg[0]&2)?0xFF:0; + valc=(gdcreg[0]&4)?0xFF:0; + vald=(gdcreg[0]&8)?0xFF:0; + switch (gdcreg[3]&0x18) + { + case 0: /*Set*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])|(la&~gdcreg[8]); + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|(lb&~gdcreg[8]); + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|(lc&~gdcreg[8]); + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|(ld&~gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2&1) vram[addr]=(vala|~gdcreg[8])&la; + if (writemask2&2) vram[addr|0x1]=(valb|~gdcreg[8])&lb; + if (writemask2&4) vram[addr|0x2]=(valc|~gdcreg[8])&lc; + if (writemask2&8) vram[addr|0x3]=(vald|~gdcreg[8])&ld; + break; + case 0x10: /*OR*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])|la; + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|lb; + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|lc; + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|ld; + break; + case 0x18: /*XOR*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])^la; + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])^lb; + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])^lc; + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])^ld; + break; + } + gdcreg[8]=wm; + break; + } +} + +uint8_t gd5429_read_linear(uint32_t addr, void *priv) +{ + uint8_t temp,temp2,temp3,temp4; + + cycles -= video_timing_b; + cycles_lost += video_timing_b; + + egareads++; + + if (chain4) + { + addr &= 0x7fffff; + if (addr >= svga_vram_limit) + return 0xff; + return vram[addr & 0x7fffff]; + } + else addr<<=2; + + addr &= 0x7fffff; + + if (addr >= svga_vram_limit) + return 0xff; + + la=vram[addr]; + lb=vram[addr|0x1]; + lc=vram[addr|0x2]; + ld=vram[addr|0x3]; + if (readmode) + { + temp= (colournocare&1) ?0xFF:0; + temp&=la; + temp^=(colourcompare&1)?0xFF:0; + temp2= (colournocare&2) ?0xFF:0; + temp2&=lb; + temp2^=(colourcompare&2)?0xFF:0; + temp3= (colournocare&4) ?0xFF:0; + temp3&=lc; + temp3^=(colourcompare&4)?0xFF:0; + temp4= (colournocare&8) ?0xFF:0; + temp4&=ld; + temp4^=(colourcompare&8)?0xFF:0; + return ~(temp|temp2|temp3|temp4); + } +//printf("Read %02X %04X %04X\n",vram[addr|readplane],addr,readplane); + return vram[addr|readplane]; +} + +void gd5429_start_blit(uint32_t cpu_dat, int count) +{ + pclog("gd5429_start_blit %i\n", count); + if (count == -1) + { + gd5429.blt.dst_addr_backup = gd5429.blt.dst_addr; + gd5429.blt.src_addr_backup = gd5429.blt.src_addr; + gd5429.blt.width_backup = gd5429.blt.width; + gd5429.blt.height_internal = gd5429.blt.height; + gd5429.blt.x_count = gd5429.blt.mask & 7; + pclog("gd5429_start_blit : size %i, %i\n", gd5429.blt.width, gd5429.blt.height); + + if (gd5429.blt.mode & 0x04) + { +// pclog("blt.mode & 0x04\n"); + mem_removehandler(0xa0000, 0x10000, gd5429_read, NULL, NULL, gd5429_write, NULL, NULL, NULL); + mem_sethandler(0xa0000, 0x10000, NULL, NULL, NULL, NULL, gd5429_blt_write_w, gd5429_blt_write_l, NULL); + return; + } + else + { + mem_removehandler(0xa0000, 0x10000, NULL, NULL, NULL, NULL, gd5429_blt_write_w, gd5429_blt_write_l, NULL); + gd5429_recalc_mapping(); + } + } + + while (count) + { + uint8_t src, dst; + int mask; + + if (gd5429.blt.mode & 0x04) + { + if (gd5429.blt.mode & 0x80) + { + src = (cpu_dat & 0x80) ? gd5429.blt.fg_col : gd5429.blt.bg_col; + mask = cpu_dat & 0x80; + cpu_dat <<= 1; + count--; + } + else + { + src = cpu_dat & 0xff; + cpu_dat >>= 8; + count -= 8; + mask = 1; + } + } + else + { + switch (gd5429.blt.mode & 0xc0) + { + case 0x00: + src = vram[gd5429.blt.src_addr & vrammask]; + gd5429.blt.src_addr += ((gd5429.blt.mode & 0x01) ? -1 : 1); + mask = 1; + break; + case 0x40: + src = vram[(gd5429.blt.src_addr & (vrammask & ~7)) | (gd5429.blt.dst_addr & 7)]; + mask = 1; + break; + case 0x80: + mask = vram[gd5429.blt.src_addr & vrammask] & (0x80 >> gd5429.blt.x_count); + src = mask ? gd5429.blt.fg_col : gd5429.blt.bg_col; + gd5429.blt.x_count++; + if (gd5429.blt.x_count == 8) + { + gd5429.blt.x_count = 0; + gd5429.blt.src_addr++; + } + break; + case 0xc0: + mask = vram[gd5429.blt.src_addr & vrammask] & (0x80 >> (gd5429.blt.dst_addr & 7)); + src = mask ? gd5429.blt.fg_col : gd5429.blt.bg_col; + break; + } + count--; + } + dst = vram[gd5429.blt.dst_addr & vrammask]; + changedvram[(gd5429.blt.dst_addr & vrammask) >> 10] = changeframecount; + + pclog("Blit %i,%i %06X %06X %06X %02X %02X %02X %02X ", gd5429.blt.width, gd5429.blt.height_internal, gd5429.blt.src_addr, gd5429.blt.dst_addr, gd5429.blt.src_addr & vrammask, vram[gd5429.blt.src_addr & vrammask], 0x80 >> (gd5429.blt.dst_addr & 7), src, dst); + switch (gd5429.blt.rop) + { + case 0x00: dst = 0; break; + case 0x05: dst = src & dst; break; + case 0x06: dst = dst; break; + case 0x09: dst = src & ~dst; break; + case 0x0b: dst = ~ dst; break; + case 0x0d: dst = src; break; + case 0x0e: dst = 0xff; break; + case 0x50: dst = ~ src & dst; break; + case 0x59: dst = src ^ dst; break; + case 0x6d: dst = src | dst; break; + case 0x90: dst = ~(src | dst); break; + case 0x95: dst = ~(src ^ dst); break; + case 0xad: dst = src | ~dst; break; + case 0xd0: dst = ~src; break; + case 0xd6: dst = ~src | dst; break; + case 0xda: dst = ~(src & dst); break; + } + pclog("%02X %02X\n", dst, mask); + + if ((gd5429.blt.width_backup - gd5429.blt.width) >= (gd5429.blt.mask & 7) && + !((gd5429.blt.mode & 0x08) && !mask)) + vram[gd5429.blt.dst_addr & vrammask] = dst; + + gd5429.blt.dst_addr += ((gd5429.blt.mode & 0x01) ? -1 : 1); + + gd5429.blt.width--; + + if (gd5429.blt.width == 0xffff) + { + gd5429.blt.width = gd5429.blt.width_backup; + + gd5429.blt.dst_addr = gd5429.blt.dst_addr_backup = gd5429.blt.dst_addr_backup + ((gd5429.blt.mode & 0x01) ? -gd5429.blt.dst_pitch : gd5429.blt.dst_pitch); + + switch (gd5429.blt.mode & 0xc0) + { + case 0x00: + gd5429.blt.src_addr = gd5429.blt.src_addr_backup = gd5429.blt.src_addr_backup + ((gd5429.blt.mode & 0x01) ? -gd5429.blt.src_pitch : gd5429.blt.src_pitch); + break; + case 0x40: + gd5429.blt.src_addr = ((gd5429.blt.src_addr + ((gd5429.blt.mode & 0x01) ? -8 : 8)) & 0x38) | (gd5429.blt.src_addr & ~0x38); + break; + case 0x80: + if (gd5429.blt.x_count != 0) + { + gd5429.blt.x_count = 0; + gd5429.blt.src_addr++; + } + break; + case 0xc0: + gd5429.blt.src_addr = ((gd5429.blt.src_addr + ((gd5429.blt.mode & 0x01) ? -1 : 1)) & 7) | (gd5429.blt.src_addr & ~7); + break; + } + + gd5429.blt.height_internal--; + if (gd5429.blt.height_internal == 0xffff) + { + if (gd5429.blt.mode & 0x04) + { + mem_removehandler(0xa0000, 0x10000, NULL, NULL, NULL, NULL, gd5429_blt_write_w, gd5429_blt_write_l, NULL); + gd5429_recalc_mapping(); + } + return; + } + + if (gd5429.blt.mode & 0x04) + return; + } + } +} + +void gd5429_mmio_write(uint32_t addr, uint8_t val, void *priv) +{ + pclog("MMIO write %08X %02X\n", addr, val); + switch (addr & 0xff) + { + case 0x00: + gd5429.blt.bg_col = (gd5429.blt.bg_col & 0xff00) | val; + break; + case 0x01: + gd5429.blt.bg_col = (gd5429.blt.bg_col & 0x00ff) | (val << 8); + break; + + case 0x04: + gd5429.blt.fg_col = (gd5429.blt.fg_col & 0xff00) | val; + break; + case 0x05: + gd5429.blt.fg_col = (gd5429.blt.fg_col & 0x00ff) | (val << 8); + break; + + case 0x08: + gd5429.blt.width = (gd5429.blt.width & 0xff00) | val; + break; + case 0x09: + gd5429.blt.width = (gd5429.blt.width & 0x00ff) | (val << 8); + break; + case 0x0a: + gd5429.blt.height = (gd5429.blt.height & 0xff00) | val; + break; + case 0x0b: + gd5429.blt.height = (gd5429.blt.height & 0x00ff) | (val << 8); + break; + case 0x0c: + gd5429.blt.dst_pitch = (gd5429.blt.dst_pitch & 0xff00) | val; + break; + case 0x0d: + gd5429.blt.dst_pitch = (gd5429.blt.dst_pitch & 0x00ff) | (val << 8); + break; + case 0x0e: + gd5429.blt.src_pitch = (gd5429.blt.src_pitch & 0xff00) | val; + break; + case 0x0f: + gd5429.blt.src_pitch = (gd5429.blt.src_pitch & 0x00ff) | (val << 8); + break; + + case 0x10: + gd5429.blt.dst_addr = (gd5429.blt.dst_addr & 0xffff00) | val; + break; + case 0x11: + gd5429.blt.dst_addr = (gd5429.blt.dst_addr & 0xff00ff) | (val << 8); + break; + case 0x12: + gd5429.blt.dst_addr = (gd5429.blt.dst_addr & 0x00ffff) | (val << 16); + break; + + case 0x14: + gd5429.blt.src_addr = (gd5429.blt.src_addr & 0xffff00) | val; + break; + case 0x15: + gd5429.blt.src_addr = (gd5429.blt.src_addr & 0xff00ff) | (val << 8); + break; + case 0x16: + gd5429.blt.src_addr = (gd5429.blt.src_addr & 0x00ffff) | (val << 16); + break; + + case 0x17: + gd5429.blt.mask = val; + break; + case 0x18: + gd5429.blt.mode = val; + break; + + case 0x1a: + gd5429.blt.rop = val; + break; + + case 0x40: + if (val & 0x02) + gd5429_start_blit(0, -1); + break; + } +} + +uint8_t gd5429_mmio_read(uint32_t addr, void *priv) +{ + pclog("MMIO read %08X\n", addr); + switch (addr & 0xff) + { + case 0x40: /*BLT status*/ + return 0; + } + return 0xff; /*All other registers read-only*/ +} + +void gd5429_blt_write_w(uint32_t addr, uint16_t val, void *priv) +{ + pclog("gd5429_blt_write_w %08X %08X\n", addr, val); + gd5429_start_blit(val, 16); +} + +void gd5429_blt_write_l(uint32_t addr, uint32_t val, void *priv) +{ + pclog("gd5429_blt_write_l %08X %08X %04X %04X\n", addr, val, ((val >> 8) & 0x00ff) | ((val << 8) & 0xff00), ((val >> 24) & 0x00ff) | ((val >> 8) & 0xff00)); + if ((gd5429.blt.mode & 0x84) == 0x84) + { + gd5429_start_blit( val & 0xff, 8); + gd5429_start_blit((val >> 8) & 0xff, 8); + gd5429_start_blit((val >> 16) & 0xff, 8); + gd5429_start_blit((val >> 24) & 0xff, 8); + } + else + gd5429_start_blit(val, 32); +} + +GFXCARD vid_gd5429 = +{ + gd5429_init, + /*IO at 3Cx/3Dx*/ + gd5429_out, + gd5429_in, + /*IO at 3Ax/3Bx*/ + video_out_null, + video_in_null, + + svga_poll, + svga_recalctimings, + + svga_write, + video_write_null, + video_write_null, + + svga_read, + video_read_null, + video_read_null +}; diff --git a/src/vid_et4000w32.h b/src/vid_et4000w32.h new file mode 100644 index 0000000..e69de29 diff --git a/src/vid_ics2595.c b/src/vid_ics2595.c new file mode 100644 index 0000000..af6946f --- /dev/null +++ b/src/vid_ics2595.c @@ -0,0 +1,63 @@ +/*ICS2595 clock chip emulation + Used by ATI Mach64*/ + +#include "ibm.h" +#include "vid_ics2595.h" + +enum +{ + ICS2595_IDLE, + ICS2595_WRITE, + ICS2595_READ +}; + +static int ics2595_oldfs3, ics2595_oldfs2; +static int ics2595_dat; +static int ics2595_pos; +static int ics2595_state = ICS2595_IDLE; + +static int ics2595_div[4] = {8, 4, 2, 1}; + +static double ics2595_clocks[16]; +double ics2595_output_clock; + +void ics2595_write(int strobe, int dat) +{ + pclog("ics2595_write : %i %i\n", strobe, dat); + if (strobe) + { + if ((dat & 8) && !ics2595_oldfs3) /*Data clock*/ + { + pclog(" - new dat %i\n", dat & 4); + switch (ics2595_state) + { + case ICS2595_IDLE: + ics2595_state = (dat & 4) ? ICS2595_WRITE : ICS2595_IDLE; + ics2595_pos = 0; + break; + case ICS2595_WRITE: + ics2595_dat = (ics2595_dat >> 1); + if (dat & 4) + ics2595_dat |= (1 << 19); + ics2595_pos++; + if (ics2595_pos == 20) + { + int d, n, l; + pclog("ICS2595_WRITE : dat %08X\n", ics2595_dat); + l = (ics2595_dat >> 2) & 31; + n = ((ics2595_dat >> 7) & 255) + 257; + d = ics2595_div[(ics2595_dat >> 16) & 3]; + + ics2595_clocks[l] = (14318181.8 * ((double)n / 46.0)) / (double)d; + pclog("ICS2595 clock set - L %i N %i D %i freq = %f\n", l, n, d, (14318181.8 * ((double)n / 46.0)) / (double)d); + ics2595_state = ICS2595_IDLE; + } + break; + } + } + + ics2595_oldfs2 = dat & 4; + ics2595_oldfs3 = dat & 8; + } + ics2595_output_clock = ics2595_clocks[dat]; +} diff --git a/src/vid_ics2595.h b/src/vid_ics2595.h new file mode 100644 index 0000000..dd975b1 --- /dev/null +++ b/src/vid_ics2595.h @@ -0,0 +1,2 @@ +void ics2595_write(int strobe, int dat); +extern double ics2595_output_clock; diff --git a/src/vid_s3_virge.c b/src/vid_s3_virge.c new file mode 100644 index 0000000..43199d1 --- /dev/null +++ b/src/vid_s3_virge.c @@ -0,0 +1,467 @@ +/*S3 ViRGE emulation + + The SVGA core is largely the same as older S3 chips, but the blitter is totally different*/ +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "pci.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +//#include "vid_sdac_ramdac.h" + +void s3_virge_updatemapping(); + +static uint8_t s3_bank; +static uint8_t s3_ma_ext; +static int s3_width = 1024; +static int s3_bpp = 0; + +static uint8_t s3_virge_id, s3_virge_id_high, s3_virge_id_low, s3_virge_rev; + +uint8_t s3_virge_mmio_read(uint32_t addr, void *priv); +uint16_t s3_virge_mmio_read_w(uint32_t addr, void *priv); +uint32_t s3_virge_mmio_read_l(uint32_t addr, void *priv); +void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *priv); +void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *priv); +void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv); + +void s3_virge_out(uint16_t addr, uint8_t val, void *priv) +{ + uint8_t old; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60; + + pclog("S3 out %04X %02X %04X:%08X %04X %04X %i\n", addr, val, CS, pc, ES, BX, ins); + + switch (addr) + { + case 0x3c5: + if (seqaddr >= 0x10) + { + seqregs[seqaddr&0x1F]=val; + return; + } + if (seqaddr == 4) /*Chain-4 - update banking*/ + { + if (val & 8) svgawbank = svgarbank = s3_bank << 16; + else svgawbank = svgarbank = s3_bank << 14; + } + break; + + //case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: +// pclog("Write RAMDAC %04X %02X %04X:%04X\n", addr, val, CS, pc); + //sdac_ramdac_out(addr,val); + //return; + + case 0x3D4: + crtcreg=val&0x7f; + return; + case 0x3D5: +// if (crtcreg == 0x67) pclog("Write CRTC R%02X %02X\n", crtcreg, val); + if (crtcreg <= 7 && crtc[0x11] & 0x80) return; + if (crtcreg >= 0x20 && crtcreg != 0x38 && (crtc[0x38] & 0xcc) != 0x48) return; + old=crtc[crtcreg]; + crtc[crtcreg]=val; + switch (crtcreg) + { + case 0x31: + s3_ma_ext = (s3_ma_ext & 0x1c) | ((val & 0x30) >> 4); + vrammask = (val & 8) ? 0x3fffff : 0x3ffff; + break; + + case 0x50: + switch (crtc[0x50] & 0xc1) + { + case 0x00: s3_width = (crtc[0x31] & 2) ? 2048 : 1024; break; + case 0x01: s3_width = 1152; break; + case 0x40: s3_width = 640; break; + case 0x80: s3_width = 800; break; + case 0x81: s3_width = 1600; break; + case 0xc0: s3_width = 1280; break; + } + s3_bpp = (crtc[0x50] >> 4) & 3; + break; + case 0x69: + s3_ma_ext = val & 0x1f; + break; + + case 0x35: + s3_bank = (s3_bank & 0x70) | (val & 0xf); +// pclog("CRTC write R35 %02X\n", val); + if (chain4) svgawbank = svgarbank = s3_bank << 16; + else svgawbank = svgarbank = s3_bank << 14; + break; + case 0x51: + s3_bank = (s3_bank & 0x4f) | ((val & 0xc) << 2); + if (chain4) svgawbank = svgarbank = s3_bank << 16; + else svgawbank = svgarbank = s3_bank << 14; + s3_ma_ext = (s3_ma_ext & ~0xc) | ((val & 3) << 2); + break; + case 0x6a: + s3_bank = val; +// pclog("CRTC write R6a %02X\n", val); + if (chain4) svgawbank = svgarbank = s3_bank << 16; + else svgawbank = svgarbank = s3_bank << 14; + break; + + case 0x3a: + if (val & 0x10) gdcreg[5] |= 0x40; /*Horrible cheat*/ + break; + + case 0x45: + svga_hwcursor.ena = val & 1; + break; + case 0x48: + svga_hwcursor.x = ((crtc[0x46] << 8) | crtc[0x47]) & 0x7ff; + if (bpp == 32) svga_hwcursor.x >>= 1; + svga_hwcursor.y = ((crtc[0x48] << 8) | crtc[0x49]) & 0x7ff; + svga_hwcursor.xoff = crtc[0x4e] & 63; + svga_hwcursor.yoff = crtc[0x4f] & 63; + svga_hwcursor.addr = ((((crtc[0x4c] << 8) | crtc[0x4d]) & 0xfff) * 1024) + (svga_hwcursor.yoff * 16); + break; + + case 0x53: + case 0x58: case 0x59: case 0x5a: + s3_virge_updatemapping(); + break; + + case 0x67: + switch (val >> 4) + { + case 3: bpp = 15; break; + case 5: bpp = 16; break; + case 7: bpp = 24; break; + case 13: bpp = 32; break; + default: bpp = 8; break; + } + break; + //case 0x55: case 0x43: +// pclog("Write CRTC R%02X %02X\n", crtcreg, val); + } + if (old!=val) + { + if (crtcreg<0xE || crtcreg>0x10) + { + fullchange=changeframecount; + svga_recalctimings(); + } + } + break; + } + svga_out(addr, val, NULL); +} + +uint8_t s3_virge_in(uint16_t addr, void *priv) +{ + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60; + + if (addr != 0x3da) pclog("S3 in %04X %04X:%08X\n", addr, CS, pc); + switch (addr) + { + //case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: +// pclog("Read RAMDAC %04X %04X:%04X\n", addr, CS, pc); + //return sdac_ramdac_in(addr); + + case 0x3c5: + if (seqaddr >= 0x10) + return seqregs[seqaddr&0x1F]; + break; + + case 0x3D4: + return crtcreg; + case 0x3D5: +// pclog("Read CRTC R%02X %04X:%04X\n", crtcreg, CS, pc); + switch (crtcreg) + { + case 0x2d: return s3_virge_id_high; /*Extended chip ID*/ + case 0x2e: return s3_virge_id_low; /*New chip ID*/ + case 0x2f: return s3_virge_rev; + case 0x30: return s3_virge_id; /*Chip ID*/ + case 0x31: return (crtc[0x31] & 0xcf) | ((s3_ma_ext & 3) << 4); + case 0x35: return (crtc[0x35] & 0xf0) | (s3_bank & 0xf); + case 0x51: return (crtc[0x51] & 0xf0) | ((s3_bank >> 2) & 0xc) | ((s3_ma_ext >> 2) & 3); + case 0x69: return s3_ma_ext; + case 0x6a: return s3_bank; + } + return crtc[crtcreg]; + } + return svga_in(addr, NULL); +} + +void s3_virge_recalctimings() +{ +// pclog("recalctimings\n"); + svga_ma |= (s3_ma_ext << 16); +// pclog("SVGA_MA %08X\n", svga_ma); +// if (gdcreg[5] & 0x40) svga_lowres = !(crtc[0x3a] & 0x10); + if ((gdcreg[5] & 0x40) && (crtc[0x3a] & 0x10)) + { + switch (bpp) + { + case 8: + svga_render = svga_render_8bpp_highres; + break; + case 15: + svga_render = svga_render_15bpp_highres; + break; + case 16: + svga_render = svga_render_16bpp_highres; + break; + case 24: + svga_render = svga_render_24bpp_highres; + break; + case 32: + svga_render = svga_render_32bpp_highres; + break; + } + } + + if (crtc[0x5d] & 0x01) svga_htotal += 0x100; + if (crtc[0x5d] & 0x02) svga_hdisp += 0x100; + if (crtc[0x5e] & 0x01) svga_vtotal += 0x400; + if (crtc[0x5e] & 0x02) svga_dispend += 0x400; + if (crtc[0x5e] & 0x10) svga_vsyncstart += 0x400; + if (crtc[0x5e] & 0x40) svga_split += 0x400; + if (crtc[0x51] & 0x30) svga_rowoffset += (crtc[0x51] & 0x30) << 4; + else if (crtc[0x43] & 0x04) svga_rowoffset += 0x100; + if (!svga_rowoffset) svga_rowoffset = 256; + svga_interlace = crtc[0x42] & 0x20; + if (bpp == 32) + { + svga_htotal <<= 2; + svga_hdisp <<= 2; + } + //svga_clock = cpuclock / sdac_getclock((svga_miscout >> 2) & 3); +// pclog("SVGA_CLOCK = %f %02X %f\n", svga_clock, svga_miscout, cpuclock); + //if (bpp > 8) svga_clock /= 2; +} + +static uint32_t s3_linear_base = 0, s3_linear_size = 0; +void s3_virge_updatemapping() +{ + mem_removehandler(s3_linear_base, s3_linear_size, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL); + +// video_write_a000_w = video_write_a000_l = NULL; + + mem_removehandler(0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL); + mem_removehandler(0xa0000, 0x20000, s3_virge_mmio_read, s3_virge_mmio_read_w, s3_virge_mmio_read_l, s3_virge_mmio_write, s3_virge_mmio_write_w, s3_virge_mmio_write_l, NULL); + pclog("Update mapping - bank %02X ", gdcreg[6] & 0xc); + switch (gdcreg[6] & 0xc) /*Banked framebuffer*/ + { + case 0x0: /*128k at A0000*/ + mem_sethandler(0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL); + break; + case 0x4: /*64k at A0000*/ + mem_sethandler(0xa0000, 0x10000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL); + break; + case 0x8: /*32k at B0000*/ + mem_sethandler(0xb0000, 0x08000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL); + break; + case 0xC: /*32k at B8000*/ + mem_sethandler(0xb8000, 0x08000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL); + break; + } + + pclog("Linear framebuffer %02X ", crtc[0x58] & 0x10); + if (crtc[0x58] & 0x10) /*Linear framebuffer*/ + { + s3_linear_base = (crtc[0x5a] << 16) | (crtc[0x59] << 24); + switch (crtc[0x58] & 3) + { + case 0: /*64k*/ + s3_linear_size = 0x10000; + break; + case 1: /*1mb*/ + s3_linear_size = 0x100000; + break; + case 2: /*2mb*/ + s3_linear_size = 0x200000; + break; + case 3: /*8mb*/ + s3_linear_size = 0x400000; + break; + } + s3_linear_base &= ~(s3_linear_size - 1); +// pclog("%08X %08X %02X %02X %02X\n", linear_base, linear_size, crtc[0x58], crtc[0x59], crtc[0x5a]); + pclog("Linear framebuffer at %08X size %08X\n", s3_linear_base, s3_linear_size); + if (s3_linear_base == 0xa0000) + mem_sethandler(0xa0000, 0x10000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL); + else + mem_sethandler(s3_linear_base, s3_linear_size, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL); + } + + pclog("Memory mapped IO %02X\n", crtc[0x53] & 0x18); + output = 0; + if ((crtc[0x53] & 0x18) == 0x10) /*Memory mapped IO*/ + { + output = 3; + if (crtc[0x53] & 0x20) + mem_sethandler(0xb8000, 0x8000, s3_virge_mmio_read, s3_virge_mmio_read_w, s3_virge_mmio_read_l, s3_virge_mmio_write, s3_virge_mmio_write_w, s3_virge_mmio_write_l, NULL); + else + mem_sethandler(0xa8000, 0x8000, s3_virge_mmio_read, s3_virge_mmio_read_w, s3_virge_mmio_read_l, s3_virge_mmio_write, s3_virge_mmio_write_w, s3_virge_mmio_write_l, NULL); + } + +} + + +uint8_t s3_virge_mmio_read(uint32_t addr, void *priv) +{ + pclog("MMIO readb %08X\n", addr); + return 0xff; +} +uint16_t s3_virge_mmio_read_w(uint32_t addr, void *priv) +{ + pclog("MMIO readw %08X\n", addr); + return 0xffff; +} +uint32_t s3_virge_mmio_read_l(uint32_t addr, void *priv) +{ + pclog("MMIO readl %08X\n", addr); + return 0xffffffff; +} +void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *priv) +{ + pclog("MMIO writeb %08X %02X\n", addr, val); +} +void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *priv) +{ + pclog("MMIO writew %08X %04X\n", addr, val); +} +void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) +{ + pclog("MMIO writel %08X %08X\n", addr, val); +} + + + +void s3_virge_hwcursor_draw(int displine) +{ + int x; + uint16_t dat[2]; + int xx; + int offset = svga_hwcursor_latch.x - svga_hwcursor_latch.xoff; + + pclog("HWcursor %i %i\n", svga_hwcursor_latch.x, svga_hwcursor_latch.y); + for (x = 0; x < 64; x += 16) + { + dat[0] = (vram[svga_hwcursor_latch.addr] << 8) | vram[svga_hwcursor_latch.addr + 1]; + dat[1] = (vram[svga_hwcursor_latch.addr + 2] << 8) | vram[svga_hwcursor_latch.addr + 3]; + for (xx = 0; xx < 16; xx++) + { + if (offset >= svga_hwcursor_latch.x) + { + if (!(dat[0] & 0x8000)) + ((uint32_t *)buffer32->line[displine])[offset + 32] = (dat[1] & 0x8000) ? 0xffffff : 0; + else if (dat[1] & 0x8000) + ((uint32_t *)buffer32->line[displine])[offset + 32] ^= 0xffffff; +// pclog("Plot %i, %i (%i %i) %04X %04X\n", offset, displine, x+xx, svga_hwcursor_on, dat[0], dat[1]); + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + svga_hwcursor_latch.addr += 4; + } +} + + +static uint8_t s3_virge_pci_regs[256]; + +uint8_t s3_virge_pci_read(int func, int addr, void *priv) +{ +// pclog("S3 PCI read %08X\n", addr); + switch (addr) + { + case 0x00: return 0x33; /*'S3'*/ + case 0x01: return 0x53; + + case 0x02: return s3_virge_id_low; + case 0x03: return s3_virge_id_high; + + case 0x08: return 0; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + + case 0x0a: return 0x00; /*Supports VGA interface*/ + case 0x0b: return 0x03; + + case 0x10: return 0x00; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return 0x00; + case 0x13: return crtc[0x59] & 0xfc; + + case 0x30: return 0x01; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return 0x0C; + case 0x33: return 0x00; + + } + return s3_virge_pci_regs[addr]; +} + +void s3_virge_pci_write(int func, int addr, uint8_t val, void *priv) +{ + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x3d: case 0x3e: case 0x3f: + break; + + case 0x13: crtc[0x59] = val & 0xfc; s3_virge_updatemapping(); break; + } + s3_virge_pci_regs[addr] = val; +} + +int s3_virge_init() +{ + s3_virge_pci_regs[4] = 3; + s3_virge_pci_regs[5] = 0; + s3_virge_pci_regs[6] = 0; + s3_virge_pci_regs[7] = 2; + s3_virge_pci_regs[0x3d] = 1; + s3_virge_pci_regs[0x3e] = 4; + s3_virge_pci_regs[0x3f] = 0xff; + + s3_virge_id_high = 0x56; + s3_virge_id_low = 0x31; + s3_virge_rev = 0; + s3_virge_id = 0xe1; + + svga_recalctimings_ex = s3_virge_recalctimings; + svga_hwcursor_draw = s3_virge_hwcursor_draw; + + crtc[0x36] = 1 | (2 << 2) | (1 << 4) | (4 << 5); + crtc[0x37] = 1 | (7 << 5); + + vrammask = 0x3fffff; + + pci_add(s3_virge_pci_read, s3_virge_pci_write, NULL); + + svga_vram_limit = 4 << 20; /*4mb*/ + return svga_init(); +} + +GFXCARD vid_s3_virge = +{ + s3_virge_init, + /*IO at 3Cx/3Dx*/ + s3_virge_out, + s3_virge_in, + /*IO at 3Ax/3Bx*/ + video_out_null, + video_in_null, + + svga_poll, + svga_recalctimings, + + svga_write, + video_write_null, + video_write_null, + + svga_read, + video_read_null, + video_read_null +}; + diff --git a/src/vid_svga_render.c b/src/vid_svga_render.c new file mode 100644 index 0000000..20a6df6 --- /dev/null +++ b/src/vid_svga_render.c @@ -0,0 +1,487 @@ +#include "ibm.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + +void svga_render_blank() +{ + int x, xx; + + if (firstline_draw == 2000) firstline_draw = displine; + lastline_draw = displine; + for (x=0;xline[displine])[(x*9)+xx+32]=0; + break; + case 1: + for (xx=0;xx<8;xx++) ((uint32_t *)buffer32->line[displine])[(x*8)+xx+32]=0; + break; + case 8: + for (xx=0;xx<18;xx++) ((uint32_t *)buffer32->line[displine])[(x*18)+xx+32]=0; + break; + case 9: + for (xx=0;xx<16;xx++) ((uint32_t *)buffer32->line[displine])[(x*16)+xx+32]=0; + break; + } + } +} + +void svga_render_text_40() +{ + if (firstline_draw == 2000) firstline_draw = displine; + lastline_draw = displine; + + if (fullchange) + { + int x, xx; + int drawcursor; + uint8_t chr, attr, dat; + uint32_t charaddr; + int fg, bg; + int xinc = (seqregs[1] & 1) ? 16 : 18; + + for (x=0;x>4]]; + } + else + { + fg=pallook[egapal[attr&15]]; + bg=pallook[egapal[attr>>4]]; + if (attr&0x80 && attrregs[0x10]&8) + { + bg=pallook[egapal[(attr>>4)&7]]; + if (cgablink&16) fg=bg; + } + } + + dat=vram[charaddr+(sc<<2)]; + if (seqregs[1]&1) + { + for (xx=0;xx<8;xx++) + ((uint32_t *)buffer32->line[displine])[(x+32+(xx<<1))&2047]=((uint32_t *)buffer32->line[displine])[(x+33+(xx<<1))&2047]=(dat&(0x80>>xx))?fg:bg; + } + else + { + for (xx=0;xx<8;xx++) + ((uint32_t *)buffer32->line[displine])[(x+32+(xx<<1))&2047]=((uint32_t *)buffer32->line[displine])[(x+33+(xx<<1))&2047]=(dat&(0x80>>xx))?fg:bg; + if ((chr&~0x1F)!=0xC0 || !(attrregs[0x10]&4)) + ((uint32_t *)buffer32->line[displine])[(x+32+16)&2047]=((uint32_t *)buffer32->line[displine])[(x+32+17)&2047]=bg; + else + ((uint32_t *)buffer32->line[displine])[(x+32+16)&2047]=((uint32_t *)buffer32->line[displine])[(x+32+17)&2047]=(dat&1)?fg:bg; + } + ma+=4; ma&=vrammask; + } + } +} + +void svga_render_text_80() +{ + if (firstline_draw == 2000) firstline_draw = displine; + lastline_draw = displine; + + if (fullchange) + { + int x, xx; + int drawcursor; + uint8_t chr, attr, dat; + uint32_t charaddr; + int fg, bg; + int xinc = (seqregs[1] & 1) ? 8 : 9; + + for (x=0;x>4]]; + } + else + { + fg=pallook[egapal[attr&15]]; + bg=pallook[egapal[attr>>4]]; + if (attr&0x80 && attrregs[0x10]&8) + { + bg=pallook[egapal[(attr>>4)&7]]; + if (cgablink&16) fg=bg; + } + } + + dat=vram[charaddr+(sc<<2)]; + if (seqregs[1]&1) + { + for (xx=0;xx<8;xx++) + ((uint32_t *)buffer32->line[displine])[(x+32+xx)&2047]=(dat&(0x80>>xx))?fg:bg; + } + else + { + for (xx=0;xx<8;xx++) + ((uint32_t *)buffer32->line[displine])[(x+32+xx)&2047]=(dat&(0x80>>xx))?fg:bg; + if ((chr&~0x1F)!=0xC0 || !(attrregs[0x10]&4)) + ((uint32_t *)buffer32->line[displine])[(x+32+8)&2047]=bg; + else + ((uint32_t *)buffer32->line[displine])[(x+32+8)&2047]=(dat&1)?fg:bg; + } + ma+=4; ma&=vrammask; + } + } +} + +void svga_render_4bpp_lowres() +{ + int x, offset; + uint8_t edat[4], dat; + + if (firstline_draw == 2000) firstline_draw = displine; + lastline_draw = displine; + + offset=((8-scrollcache)<<1)+16; + for (x = 0; x <= svga_hdisp; x += 16) + { + edat[0]=vram[ma]; + edat[1]=vram[ma|0x1]; + edat[2]=vram[ma|0x2]; + edat[3]=vram[ma|0x3]; + ma+=4; ma&=vrammask; + + dat=edatlookup[edat[0]&3][edat[1]&3]|(edatlookup[edat[2]&3][edat[3]&3]<<2); + ((uint32_t *)buffer32->line[displine])[x+14+offset]=((uint32_t *)buffer32->line[displine])[x+15+offset]=pallook[egapal[dat&0xF]]; + ((uint32_t *)buffer32->line[displine])[x+12+offset]=((uint32_t *)buffer32->line[displine])[x+13+offset]=pallook[egapal[dat>>4]]; + dat=edatlookup[(edat[0]>>2)&3][(edat[1]>>2)&3]|(edatlookup[(edat[2]>>2)&3][(edat[3]>>2)&3]<<2); + ((uint32_t *)buffer32->line[displine])[x+10+offset]=((uint32_t *)buffer32->line[displine])[x+11+offset]=pallook[egapal[dat&0xF]]; + ((uint32_t *)buffer32->line[displine])[x+8+offset]= ((uint32_t *)buffer32->line[displine])[x+9+offset]=pallook[egapal[dat>>4]]; + dat=edatlookup[(edat[0]>>4)&3][(edat[1]>>4)&3]|(edatlookup[(edat[2]>>4)&3][(edat[3]>>4)&3]<<2); + ((uint32_t *)buffer32->line[displine])[x+6+offset]= ((uint32_t *)buffer32->line[displine])[x+7+offset]=pallook[egapal[dat&0xF]]; + ((uint32_t *)buffer32->line[displine])[x+4+offset]= ((uint32_t *)buffer32->line[displine])[x+5+offset]=pallook[egapal[dat>>4]]; + dat=edatlookup[edat[0]>>6][edat[1]>>6]|(edatlookup[edat[2]>>6][edat[3]>>6]<<2); + ((uint32_t *)buffer32->line[displine])[x+2+offset]= ((uint32_t *)buffer32->line[displine])[x+3+offset]=pallook[egapal[dat&0xF]]; + ((uint32_t *)buffer32->line[displine])[x+offset]= ((uint32_t *)buffer32->line[displine])[x+1+offset]=pallook[egapal[dat>>4]]; + } +} + +void svga_render_4bpp_highres() +{ + int x, offset; + uint8_t edat[4], dat; + + if (firstline_draw == 2000) firstline_draw = displine; + lastline_draw = displine; + + offset=(8-scrollcache)+24; + for (x = 0; x <= svga_hdisp; x += 8) + { + edat[0]=vram[ma]; + edat[1]=vram[ma|0x1]; + edat[2]=vram[ma|0x2]; + edat[3]=vram[ma|0x3]; + ma+=4; ma&=vrammask; + + dat=edatlookup[edat[0]&3][edat[1]&3]|(edatlookup[edat[2]&3][edat[3]&3]<<2); + ((uint32_t *)buffer32->line[displine])[x+7+offset]=pallook[egapal[dat&0xF]]; + ((uint32_t *)buffer32->line[displine])[x+6+offset]=pallook[egapal[dat>>4]]; + dat=edatlookup[(edat[0]>>2)&3][(edat[1]>>2)&3]|(edatlookup[(edat[2]>>2)&3][(edat[3]>>2)&3]<<2); + ((uint32_t *)buffer32->line[displine])[x+5+offset]=pallook[egapal[dat&0xF]]; + ((uint32_t *)buffer32->line[displine])[x+4+offset]=pallook[egapal[dat>>4]]; + dat=edatlookup[(edat[0]>>4)&3][(edat[1]>>4)&3]|(edatlookup[(edat[2]>>4)&3][(edat[3]>>4)&3]<<2); + ((uint32_t *)buffer32->line[displine])[x+3+offset]=pallook[egapal[dat&0xF]]; + ((uint32_t *)buffer32->line[displine])[x+2+offset]=pallook[egapal[dat>>4]]; + dat=edatlookup[edat[0]>>6][edat[1]>>6]|(edatlookup[edat[2]>>6][edat[3]>>6]<<2); + ((uint32_t *)buffer32->line[displine])[x+1+offset]=pallook[egapal[dat&0xF]]; + ((uint32_t *)buffer32->line[displine])[x+offset]= pallook[egapal[dat>>4]]; + } +} + +void svga_render_2bpp_lowres() +{ + int x, offset; + uint8_t edat[4], dat; + + if (firstline_draw == 2000) firstline_draw = displine; + lastline_draw = displine; + offset=((8-scrollcache)<<1)+16; + /*Low res (320) only, though high res (640) should be possible*/ + for (x = 0; x <= svga_hdisp; x += 16) + { + if (sc&1 && !(crtc[0x17]&1)) + { + edat[0]=vram[(ma<<1)+0x8000]; + edat[1]=vram[(ma<<1)+0x8004]; + } + else + { + edat[0]=vram[(ma<<1)]; + edat[1]=vram[(ma<<1)+4]; + } + ma+=4; ma&=vrammask; + + ((uint32_t *)buffer32->line[displine])[x+14+offset]=((uint32_t *)buffer32->line[displine])[x+15+offset]=pallook[egapal[edat[1]&3]]; + ((uint32_t *)buffer32->line[displine])[x+12+offset]=((uint32_t *)buffer32->line[displine])[x+13+offset]=pallook[egapal[(edat[1]>>2)&3]]; + dat=edatlookup[(edat[0]>>2)&3][(edat[1]>>2)&3]|(edatlookup[(edat[2]>>2)&3][(edat[3]>>2)&3]<<2); + ((uint32_t *)buffer32->line[displine])[x+10+offset]=((uint32_t *)buffer32->line[displine])[x+11+offset]=pallook[egapal[(edat[1]>>4)&3]]; + ((uint32_t *)buffer32->line[displine])[x+8+offset]= ((uint32_t *)buffer32->line[displine])[x+9+offset]=pallook[egapal[(edat[1]>>6)&3]]; + dat=edatlookup[(edat[0]>>4)&3][(edat[1]>>4)&3]|(edatlookup[(edat[2]>>4)&3][(edat[3]>>4)&3]<<2); + ((uint32_t *)buffer32->line[displine])[x+6+offset]= ((uint32_t *)buffer32->line[displine])[x+7+offset]=pallook[egapal[(edat[0]>>0)&3]]; + ((uint32_t *)buffer32->line[displine])[x+4+offset]= ((uint32_t *)buffer32->line[displine])[x+5+offset]=pallook[egapal[(edat[0]>>2)&3]]; + dat=edatlookup[edat[0]>>6][edat[1]>>6]|(edatlookup[edat[2]>>6][edat[3]>>6]<<2); + ((uint32_t *)buffer32->line[displine])[x+2+offset]= ((uint32_t *)buffer32->line[displine])[x+3+offset]=pallook[egapal[(edat[0]>>4)&3]]; + ((uint32_t *)buffer32->line[displine])[x+offset]= ((uint32_t *)buffer32->line[displine])[x+1+offset]=pallook[egapal[(edat[0]>>6)&3]]; + } +} + +void svga_render_8bpp_lowres() +{ + int x, offset; + uint8_t edat[4]; + + if (changedvram[ma>>10] || changedvram[(ma>>10)+1] || changedvram[(ma>>10)+2] || fullchange) + { + if (firstline_draw == 2000) firstline_draw = displine; + lastline_draw = displine; + + offset=(8-(scrollcache&6))+24; + + for (x = 0; x <= svga_hdisp; x += 8) + { + edat[0]=vram[ma]; + edat[1]=vram[ma|0x1]; + edat[2]=vram[ma|0x2]; + edat[3]=vram[ma|0x3]; + ma+=4; ma&=vrammask; + ((uint32_t *)buffer32->line[displine])[x+6+offset]= ((uint32_t *)buffer32->line[displine])[x+7+offset]=pallook[edat[3]]; + ((uint32_t *)buffer32->line[displine])[x+4+offset]= ((uint32_t *)buffer32->line[displine])[x+5+offset]=pallook[edat[2]]; + ((uint32_t *)buffer32->line[displine])[x+2+offset]= ((uint32_t *)buffer32->line[displine])[x+3+offset]=pallook[edat[1]]; + ((uint32_t *)buffer32->line[displine])[x+offset]= ((uint32_t *)buffer32->line[displine])[x+1+offset]=pallook[edat[0]]; + } + } +} + +void svga_render_8bpp_highres() +{ + int x, offset; + uint8_t edat[4]; + + if (changedvram[ma>>10] || changedvram[(ma>>10)+1] || changedvram[(ma>>10)+2] || fullchange) + { + if (firstline_draw == 2000) firstline_draw = displine; + lastline_draw = displine; + + offset = (8 - ((scrollcache & 6) >> 1)) + 24; + + for (x = 0; x <= svga_hdisp; x += 8) + { + edat[0]=vram[ma]; + edat[1]=vram[ma|0x1]; + edat[2]=vram[ma|0x2]; + edat[3]=vram[ma|0x3]; + ma+=4; ma&=vrammask; + ((uint32_t *)buffer32->line[displine])[x+3+offset] = pallook[edat[3]]; + ((uint32_t *)buffer32->line[displine])[x+2+offset] = pallook[edat[2]]; + ((uint32_t *)buffer32->line[displine])[x+1+offset] = pallook[edat[1]]; + ((uint32_t *)buffer32->line[displine])[x+offset] = pallook[edat[0]]; + edat[0]=vram[ma]; + edat[1]=vram[ma|0x1]; + edat[2]=vram[ma|0x2]; + edat[3]=vram[ma|0x3]; + ma+=4; ma&=vrammask; + ((uint32_t *)buffer32->line[displine])[x+7+offset] = pallook[edat[3]]; + ((uint32_t *)buffer32->line[displine])[x+6+offset] = pallook[edat[2]]; + ((uint32_t *)buffer32->line[displine])[x+5+offset] = pallook[edat[1]]; + ((uint32_t *)buffer32->line[displine])[x+4+offset] = pallook[edat[0]]; + } + } +} + +void svga_render_15bpp_lowres() +{ + int x, offset; + uint16_t fg, bg; + + if (changedvram[ma>>10] || changedvram[(ma>>10)+1] || changedvram[(ma>>10)+2] || fullchange) + { + if (firstline_draw == 2000) firstline_draw = displine; + lastline_draw = displine; + + offset=(8-(scrollcache&6))+24; + + for (x = 0; x <= svga_hdisp; x += 4) + { + fg=vram[ma]|(vram[ma|0x1]<<8); + bg=vram[ma|0x2]|(vram[ma|0x3]<<8); + ma+=4; ma&=vrammask; + ((uint32_t *)buffer32->line[displine])[x+2+offset]=((uint32_t *)buffer32->line[displine])[x+3+offset]=((bg&31)<<3)|(((bg>>5)&31)<<11)|(((bg>>10)&31)<<19); + ((uint32_t *)buffer32->line[displine])[x+0+offset]=((uint32_t *)buffer32->line[displine])[x+1+offset]=((fg&31)<<3)|(((fg>>5)&31)<<11)|(((fg>>10)&31)<<19); + } + } +} + +void svga_render_15bpp_highres() +{ + int x, offset; + uint16_t fg, bg; + + if (changedvram[ma>>10] || changedvram[(ma>>10)+1] || changedvram[(ma>>10)+2] || fullchange) + { + if (firstline_draw == 2000) firstline_draw = displine; + lastline_draw = displine; + + offset = (8 - ((scrollcache & 6) >> 1)) + 24; + + for (x = 0; x <= svga_hdisp; x += 2) + { + fg=vram[ma]|(vram[ma|0x1]<<8); + bg=vram[ma|0x2]|(vram[ma|0x3]<<8); + ma+=4; ma&=vrammask; + ((uint32_t *)buffer32->line[displine])[x + 1 + offset] = ((bg&31)<<3)|(((bg>>5)&31)<<11)|(((bg>>10)&31)<<19); + ((uint32_t *)buffer32->line[displine])[x + 0 + offset] = ((fg&31)<<3)|(((fg>>5)&31)<<11)|(((fg>>10)&31)<<19); + } + } +} + +void svga_render_16bpp_lowres() +{ + int x, offset; + uint16_t fg, bg; + + if (changedvram[ma>>10] || changedvram[(ma>>10)+1] || changedvram[(ma>>10)+2] || fullchange) + { + if (firstline_draw == 2000) firstline_draw = displine; + lastline_draw = displine; + + offset=(8-(scrollcache&6))+24; + + for (x = 0; x <= svga_hdisp; x += 4) + { + fg=vram[ma]|(vram[ma|0x1]<<8); + bg=vram[ma|0x2]|(vram[ma|0x3]<<8); + ma+=4; ma&=vrammask; + ((uint32_t *)buffer32->line[displine])[x+2+offset]=((uint32_t *)buffer32->line[displine])[x+3+offset]=((bg&31)<<3)|(((bg>>5)&63)<<10)|(((bg>>11)&31)<<19); + ((uint32_t *)buffer32->line[displine])[x+0+offset]=((uint32_t *)buffer32->line[displine])[x+1+offset]=((fg&31)<<3)|(((fg>>5)&63)<<10)|(((fg>>11)&31)<<19); + } + } +} + +void svga_render_16bpp_highres() +{ + int x, offset; + uint16_t fg, bg; + + if (changedvram[ma>>10] || changedvram[(ma>>10)+1] || changedvram[(ma>>10)+2] || fullchange) + { + if (firstline_draw == 2000) firstline_draw = displine; + lastline_draw = displine; + + offset = (8 - ((scrollcache & 6) >> 1)) + 24; + + for (x = 0; x <= svga_hdisp; x += 2) + { + fg=vram[ma]|(vram[ma|0x1]<<8); + bg=vram[ma|0x2]|(vram[ma|0x3]<<8); + ma+=4; ma&=vrammask; + ((uint32_t *)buffer32->line[displine])[x + 1 + offset] = ((bg&31)<<3)|(((bg>>5)&63)<<10)|(((bg>>11)&31)<<19); + ((uint32_t *)buffer32->line[displine])[x + 0 + offset] = ((fg&31)<<3)|(((fg>>5)&63)<<10)|(((fg>>11)&31)<<19); + } + } +} + +void svga_render_24bpp_lowres() +{ + int x, offset; + uint32_t fg; + + if (changedvram[ma>>10] || changedvram[(ma>>10)+1] || changedvram[(ma>>10)+2] || fullchange) + { + if (firstline_draw == 2000) firstline_draw = displine; + lastline_draw = displine; + + offset=(8-(scrollcache&6))+24; + + for (x = 0; x <= svga_hdisp; x++) + { + fg=vram[ma]|(vram[ma+1]<<8)|(vram[ma+2]<<16); + ma+=3; ma&=vrammask; + ((uint32_t *)buffer32->line[displine])[(x<<1)+offset]=((uint32_t *)buffer32->line[displine])[(x<<1)+1+offset]=fg; + } + } +} + +void svga_render_24bpp_highres() +{ + int x, offset; + uint32_t fg; + + if (changedvram[ma>>10] || changedvram[(ma>>10)+1] || changedvram[(ma>>10)+2] || fullchange) + { + if (firstline_draw == 2000) firstline_draw = displine; + lastline_draw = displine; + + offset = (8 - ((scrollcache & 6) >> 1)) + 24; + + for (x = 0; x <= svga_hdisp; x++) + { + fg=vram[ma]|(vram[ma+1]<<8)|(vram[ma+2]<<16); + ma+=3; ma&=vrammask; + ((uint32_t *)buffer32->line[displine])[x + offset] = fg; + } + } +} + +void svga_render_32bpp_lowres() +{ + int x, offset; + uint32_t fg; + + if (changedvram[ma>>10] || changedvram[(ma>>10)+1] || changedvram[(ma>>10)+2] || fullchange) + { + if (firstline_draw == 2000) firstline_draw = displine; + lastline_draw = displine; + + offset=(8-(scrollcache&6))+24; + + for (x = 0; x <= svga_hdisp; x++) + { + fg = vram[ma] | (vram[ma + 1] << 8) | (vram[ma + 2] << 16); + ma += 4; ma &= vrammask; + ((uint32_t *)buffer32->line[displine])[(x << 1) + offset] = ((uint32_t *)buffer32->line[displine])[(x << 1) + 1 + offset] = fg; + } + } +} + +void svga_render_32bpp_highres() +{ + int x, offset; + uint32_t fg; + + if (changedvram[ma>>10] || changedvram[(ma>>10)+1] || changedvram[(ma>>10)+2] || fullchange) + { + if (firstline_draw == 2000) firstline_draw = displine; + lastline_draw = displine; + + offset = (8 - ((scrollcache & 6) >> 1)) + 24; + + for (x = 0; x <= svga_hdisp; x++) + { + fg=vram[ma]|(vram[ma+1]<<8)|(vram[ma+2]<<16); + ma+=4; ma&=vrammask; + ((uint32_t *)buffer32->line[displine])[x + offset] = fg; + } + } +} + diff --git a/src/vid_svga_render.h b/src/vid_svga_render.h new file mode 100644 index 0000000..63fac70 --- /dev/null +++ b/src/vid_svga_render.h @@ -0,0 +1,30 @@ +extern int firstline_draw, lastline_draw; +extern int displine; +extern int sc; + +extern uint32_t ma, ca; +extern int con, cursoron, cgablink; + +extern int scrollcache; + +extern uint8_t edatlookup[4][4]; + +void svga_render_blank(); +void svga_render_text_40(); +void svga_render_text_80(); + +void svga_render_2bpp_lowres(); +void svga_render_4bpp_lowres(); +void svga_render_4bpp_highres(); +void svga_render_8bpp_lowres(); +void svga_render_8bpp_highres(); +void svga_render_15bpp_lowres(); +void svga_render_15bpp_highres(); +void svga_render_16bpp_lowres(); +void svga_render_16bpp_highres(); +void svga_render_24bpp_lowres(); +void svga_render_24bpp_highres(); +void svga_render_32bpp_lowres(); +void svga_render_32bpp_highres(); + +extern void (*svga_render)(); diff --git a/src/vid_vga.c b/src/vid_vga.c new file mode 100644 index 0000000..dce8a8d --- /dev/null +++ b/src/vid_vga.c @@ -0,0 +1,92 @@ +/*IBM VGA emulation*/ +#include "ibm.h" +#include "io.h" +#include "video.h" +#include "vid_svga.h" + +void vga_out(uint16_t addr, uint8_t val, void *priv) +{ + uint8_t old; + + pclog("vga_out : %04X %02X %04X:%04X %02X %i\n", addr, val, CS,pc, ram[0x489], ins); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60; + + switch (addr) + { + case 0x3D4: + crtcreg = val & 0x1f; + return; + case 0x3D5: + if (crtcreg <= 7 && crtc[0x11] & 0x80) return; + old=crtc[crtcreg]; + crtc[crtcreg]=val; + if (old!=val) + { + if (crtcreg<0xE || crtcreg>0x10) + { + fullchange=changeframecount; + svga_recalctimings(); + } + } + break; + } + svga_out(addr, val, NULL); +} + +uint8_t vga_in(uint16_t addr, void *priv) +{ + uint8_t temp; + + if (addr != 0x3da) pclog("vga_in : %04X ", addr); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60; + + switch (addr) + { + case 0x3D4: + temp = crtcreg; + break; + case 0x3D5: + temp = crtc[crtcreg]; + break; + default: + temp = svga_in(addr, NULL); + break; + } + if (addr != 0x3da) pclog("%02X %04X:%04X\n", temp, CS,pc); + return temp; +} + +int vga_init() +{ + svga_recalctimings_ex = NULL; + svga_vram_limit = 1 << 18; /*256kb*/ + vrammask = 0x3ffff; + svgawbank = svgarbank = 0; + bpp = 8; + svga_miscout = 1; + return svga_init(); +} + +GFXCARD vid_vga = +{ + vga_init, + /*IO at 3Cx/3Dx*/ + vga_out, + vga_in, + /*IO at 3Ax/3Bx*/ + video_out_null, + video_in_null, + + svga_poll, + svga_recalctimings, + + svga_write, + video_write_null, + video_write_null, + + svga_read, + video_read_null, + video_read_null +}; diff --git a/src/vid_voodoo.c b/src/vid_voodoo.c new file mode 100644 index 0000000..2f216aa --- /dev/null +++ b/src/vid_voodoo.c @@ -0,0 +1,732 @@ +#include +#include "ibm.h" +#include "mem.h" +#include "pci.h" +#include "vid_voodoo.h" + +static int tris = 0; + +static struct voodoo +{ + int pci_enable; + + uint32_t color0, color1; + + uint8_t dac_data[8]; + int dac_reg; + uint8_t dac_readdata; + + uint32_t dRdX, dGdX, dBdX, dZdX, dAdX, dSdX, dTdX, dWdX; + + uint32_t dRdY, dGdY, dBdY, dZdY, dAdY, dSdY, dTdY, dWdY; + + uint32_t fbiInit0, fbiInit1, fbiInit2, fbiInit3, fbiInit4; + + uint32_t fbzMode; + + uint8_t initEnable; + + uint32_t lfbMode; + + uint32_t memBaseAddr; + + uint32_t startR, startG, startB, startZ, startA, startS, startT, startW; + + uint32_t vertexAx, vertexAy, vertexBx, vertexBy, vertexCx, vertexCy; + + uint32_t front_offset, back_offset, aux_offset; + + uint32_t fb_read_offset, fb_write_offset; + + uint32_t draw_offset; + + int row_width; + + uint8_t *fb_mem, *tex_mem; +} voodoo; + +enum +{ + SST_status = 0x000, + + SST_vertexAx = 0x008, + SST_vertexAy = 0x00c, + SST_vertexBx = 0x010, + SST_vertexBy = 0x014, + SST_vertexCx = 0x018, + SST_vertexCy = 0x01c, + + SST_startR = 0x0020, + SST_startG = 0x0024, + SST_startB = 0x0028, + SST_startZ = 0x002c, + SST_startA = 0x0030, + SST_startS = 0x0034, + SST_startT = 0x0038, + SST_startW = 0x003c, + + SST_dRdX = 0x0040, + SST_dGdX = 0x0044, + SST_dBdX = 0x0048, + SST_dZdX = 0x004c, + SST_dAdX = 0x0050, + SST_dSdX = 0x0054, + SST_dTdX = 0x0058, + SST_dWdX = 0x005c, + + SST_dRdY = 0x0060, + SST_dGdY = 0x0064, + SST_dBdY = 0x0068, + SST_dZdY = 0x006c, + SST_dAdY = 0x0070, + SST_dSdY = 0x0074, + SST_dTdY = 0x0078, + SST_dWdY = 0x007c, + + SST_triangleCMD = 0x0080, + + SST_fbzMode = 0x110, + SST_lfbMode = 0x114, + SST_swapbufferCMD = 0x128, + + SST_color0 = 0x144, + SST_color1 = 0x148, + + SST_fbiInit4 = 0x200, + SST_fbiInit0 = 0x210, + SST_fbiInit1 = 0x214, + SST_fbiInit2 = 0x218, + SST_fbiInit3 = 0x21c, + SST_dacData = 0x22c +}; + +enum +{ + LFB_WRITE_FRONT = 0x0000, + LFB_WRITE_BACK = 0x0010, + LFB_WRITE_MASK = 0x0030 +}; + +enum +{ + LFB_READ_FRONT = 0x0000, + LFB_READ_BACK = 0x0040, + LFB_READ_AUX = 0x0080, + LFB_READ_MASK = 0x00c0 +}; + +enum +{ + LFB_FORMAT_RGB565 = 0, + LFB_FORMAT_DEPTH = 15, + LFB_FORMAT_MASK = 15 +}; + +enum +{ + LFB_WRITE_COLOUR = 1, + LFB_WRITE_DEPTH = 2 +}; + +enum +{ + FBZ_DITHER = 0x100, + FBZ_DRAWRGB = 0x200, + + FBZ_DRAW_FRONT = 0x0000, + FBZ_DRAW_BACK = 0x4000, + FBZ_DRAW_MASK = 0xc000 +}; + +static int voodoo_reads = 0; + +static void voodoo_recalc() +{ + uint32_t buffer_offset = ((voodoo.fbiInit2 >> 11) & 511) * 4096; + + voodoo.front_offset = 0; + voodoo.back_offset = buffer_offset; + voodoo.aux_offset = buffer_offset * 2; + + switch (voodoo.lfbMode & LFB_WRITE_MASK) + { + case LFB_WRITE_FRONT: + voodoo.fb_write_offset = voodoo.front_offset; + break; + case LFB_WRITE_BACK: + voodoo.fb_write_offset = voodoo.back_offset; + break; + + default: + fatal("voodoo_recalc : unknown lfb destination\n"); + } + + switch (voodoo.lfbMode & LFB_READ_MASK) + { + case LFB_READ_FRONT: + voodoo.fb_read_offset = voodoo.front_offset; + break; + case LFB_READ_BACK: + voodoo.fb_read_offset = voodoo.back_offset; + break; + case LFB_READ_AUX: + voodoo.fb_read_offset = voodoo.aux_offset; + break; + + default: + fatal("voodoo_recalc : unknown lfb source\n"); + } + + switch (voodoo.fbzMode & FBZ_DRAW_MASK) + { + case FBZ_DRAW_FRONT: + voodoo.draw_offset = voodoo.front_offset; + break; + case FBZ_DRAW_BACK: + voodoo.draw_offset = voodoo.back_offset; + break; + + default: + fatal("voodoo_recalc : unknown draw buffer\n"); + } + + voodoo.row_width = ((voodoo.fbiInit1 >> 4) & 15) * 64 * 2; + pclog("voodoo_recalc : front_offset %08X back_offset %08X aux_offset %08X\n", voodoo.front_offset, voodoo.back_offset, voodoo.aux_offset); + pclog(" fb_read_offset %08X fb_write_offset %08X row_width %i\n", voodoo.fb_read_offset, voodoo.fb_write_offset, voodoo.row_width); +} + +static int dither_matrix_4x4[16] = +{ + 0, 8, 2, 10, + 12, 4, 14, 6, + 3, 11, 1, 9, + 15, 7, 13, 5 +}; + +static int dither_rb[256][4][4]; +static int dither_g[256][4][4]; + +static void voodoo_make_dither() +{ + int c, x, y; + int seen_rb[1024]; + int seen_g[1024]; + + for (c = 0; c < 256; c++) + { + int rb = (int)(((double)c * 496.0) / 256.0); + int g = (int)(((double)c * 1008.0) / 256.0); + pclog("rb %i %i\n", rb, c); + for (y = 0; y < 4; y++) + { + for (x = 0; x < 4; x++) + { + int val; + + val = rb + dither_matrix_4x4[x + (y << 2)]; + dither_rb[c][y][x] = val >> 4; + pclog("RB %i %i, %i %i %i %i\n", c, x, y, val, val >> 4, dither_rb[c][y][x]); + + if (dither_rb[c][y][x] > 31) + fatal("RB overflow %i %i %i %i\n", c, x, y, dither_rb[c][y][x]); + + val = g + dither_matrix_4x4[x + (y << 2)]; + dither_g[c][y][x] = val >> 4; + + if (dither_g[c][y][x] > 63) + fatal("G overflow %i %i %i %i\n", c, x, y, dither_g[c][y][x]); + } + } + } + + memset(seen_rb, 0, sizeof(seen_rb)); + memset(seen_g, 0, sizeof(seen_g)); + + for (c = 0; c < 256; c++) + { + int total_rb = 0; + int total_g = 0; + for (y = 0; y < 4; y++) + { + for (x = 0; x < 4; x++) + { + total_rb += dither_rb[c][y][x]; + pclog("total_rb %i %i, %i %i %i\n", c, x, y, total_rb, dither_rb[c][y][x]); + total_g += dither_g[c][y][x]; + } + } + + if (seen_rb[total_rb]) + fatal("Duplicate rb %i %i\n", c, total_rb); + seen_rb[total_rb] = 1; + + if (seen_g[total_g]) + fatal("Duplicate g %i %i\n", c, total_g); + seen_g[total_g] = 1; + } +} + +static void voodoo_triangle(struct voodoo *voodoo) +{ + int y, yend, ydir; + int xstart, xend, xdir; + int dx1, dx2; + + pclog("voodoo_triangle %i : vA %f, %f vB %f, %f vC %f, %f\n", tris, (float)voodoo->vertexAx / 16.0, (float)voodoo->vertexAy / 16.0, + (float)voodoo->vertexBx / 16.0, (float)voodoo->vertexBy / 16.0, + (float)voodoo->vertexCx / 16.0, (float)voodoo->vertexCy / 16.0); +// output = 3; + tris++; +// if (tris == 3) +// fatal("tris 2\n"); + + y = voodoo->vertexAy >> 4; + ydir = (voodoo->vertexAy >= voodoo->vertexCy) ? -1 : 1; + + if (voodoo->vertexAy == voodoo->vertexBy) + { + xstart = voodoo->vertexAx << 8; + xend = voodoo->vertexBx << 8; + } + else + xstart = xend = voodoo->vertexAx << 8; + xdir = (xstart >= xend) ? -1 : 1; + + if (voodoo->vertexAy != voodoo->vertexBy) + { + /*Draw top half*/ + dx1 = (int)(((voodoo->vertexBx << 8) - xstart) << 4) / (int)((voodoo->vertexBy - voodoo->vertexAy) * ydir); + dx2 = (int)(((voodoo->vertexCx << 8) - xend) << 4) / (int)((voodoo->vertexCy - voodoo->vertexAy) * ydir); + yend = voodoo->vertexBy >> 4; + + pclog("voodoo_triangle : top-half %X %X %X %X %i %i %i %i\n", xstart, xend, dx1, dx2, xdir, y, yend, ydir); + + for (; y != yend; y += ydir) + { + pclog(" %i : %i - %i\n", xstart >> 12, xend >> 12); + xstart += dx1; + xend += dx2; + } + } + + + if (voodoo->vertexBy != voodoo->vertexCy) + { + /*Draw bottom half*/ + dx1 = (int)(((voodoo->vertexCx << 8) - xstart) << 4) / (int)((voodoo->vertexCy - voodoo->vertexAy) * ydir); + dx2 = (int)(((voodoo->vertexCx << 8) - xend) << 4) / (int)((voodoo->vertexCy - voodoo->vertexAy) * ydir); + yend = voodoo->vertexCy >> 4; + + pclog("voodoo_triangle : bottom-half %X %X %X %X %X %i %i %i %i\n", xstart, xend, dx1, dx2, dx2 * 36, xdir, y, yend, ydir); + + for (; y != yend; y += ydir) + { + int x = xstart >> 12, x2 = xend >> 12; + pclog(" %i : %i - %i\n", y, x, x2); + + for (; x != x2; x += xdir) + { + if (voodoo->fbzMode & FBZ_DRAWRGB) + { + int r = (voodoo->color1 >> 16) & 0xff; + int g = (voodoo->color1 >> 8) & 0xff; + int b = voodoo->color1 & 0xff; + if (voodoo->fbzMode & FBZ_DITHER) + { + r = dither_rb[r][y & 3][x & 3]; + g = dither_g[g][y & 3][x & 3]; + b = dither_rb[b][y & 3][x & 3]; +/* r = ((r << 1) + dither_matrix_4x4[(x & 3) + ((y & 3) << 2)]) >> 4; + g = ((g << 2) + dither_matrix_4x4[(x & 3) + ((y & 3) << 2)]) >> 4; + b = ((b << 1) + dither_matrix_4x4[(x & 3) + ((y & 3) << 2)]) >> 4; + if (r > 31) r = 31; + if (g > 63) g = 63; + if (b > 31) b = 31;*/ +/* r = (((r << 1) - (r >> 4) + (r >> 7) + dither_matrix_4x4[(x & 3) + ((y & 3) << 2)]) >> 1) >> 3; + g = (((g << 2) - (g >> 4) + (g >> 6) + dither_matrix_4x4[(x & 3) + ((y & 3) << 2)]) >> 2) >> 2; + b = (((b << 1) - (b >> 4) + (b >> 7) + dither_matrix_4x4[(x & 3) + ((y & 3) << 2)]) >> 1) >> 3;*/ + } + else + { + r >>= 3; + g >>= 2; + b >>= 3; + } + *(uint16_t *)(&voodoo->fb_mem[voodoo->draw_offset + (y * voodoo->row_width) + (x << 1)]) = b | (g << 5) | (r << 11); + pclog(" %i = %i %i %i %04X %08X %08X\n", x, r, g, b, b | (g << 5) | (r << 11), voodoo->draw_offset + (y * voodoo->row_width) + (x << 1), *(uint32_t *)(&voodoo->fb_mem[4])); + } + } + xstart += dx1; + xend += dx2; + } + } + +/* for (y = ystart, y != yend; y += ydir) + { + if (voodoo.fbzMode & FBZ_DITHER + }*/ +} + +static uint32_t voodoo_readl(uint32_t addr, void *priv) +{ + uint32_t temp; + switch (addr & 0x3fc) + { + case SST_status: + temp = 0x0ffff03f; /*FIFOs empty*/ + break; + + case SST_lfbMode: + return voodoo.lfbMode; + + case SST_fbiInit4: + temp = voodoo.fbiInit4; + break; + case SST_fbiInit0: + temp = voodoo.fbiInit0; + break; + case SST_fbiInit1: + temp = voodoo.fbiInit1 & ~5; /*Pass-thru board with one SST-1*/ + break; + case SST_fbiInit2: + if (voodoo.initEnable & 0x04) + temp = voodoo.dac_readdata; + else + temp = voodoo.fbiInit2; + break; + case SST_fbiInit3: + temp = voodoo.fbiInit3; + break; + + default: + fatal("voodoo_readl : bad addr %08X\n", addr); + temp = 0xffffffff; + } + pclog("voodoo_readl : addr %08X val %08X %04X(%08X):%08X %i\n", addr, temp, CS, cs, pc, voodoo_reads++); +// if (voodoo_reads == 200494) +// output = 3; + return temp; +} + +static void voodoo_writel(uint32_t addr, uint32_t val, void *priv) +{ + pclog("voodoo_writel : addr %08X val %08X %04X(%08X):%08X\n", addr, val, CS, cs, pc); + switch (addr & 0x3fc) + { + case SST_swapbufferCMD: + pclog(" start swap buffer command\n"); +// output = 3; + break; + + case SST_vertexAx: + voodoo.vertexAx = val & 0xffff; + break; + case SST_vertexAy: + voodoo.vertexAy = val & 0xffff; + break; + case SST_vertexBx: + voodoo.vertexBx = val & 0xffff; + break; + case SST_vertexBy: + voodoo.vertexBy = val & 0xffff; + break; + case SST_vertexCx: + voodoo.vertexCx = val & 0xffff; + break; + case SST_vertexCy: + voodoo.vertexCy = val & 0xffff; + break; + + case SST_startR: + voodoo.startR = val & 0xffffff; + break; + case SST_startG: + voodoo.startG = val & 0xffffff; + break; + case SST_startB: + voodoo.startB = val & 0xffffff; + break; + case SST_startZ: + voodoo.startZ = val; + break; + case SST_startA: + voodoo.startA = val & 0xffffff; + break; + case SST_startS: + voodoo.startS = val; + break; + case SST_startT: + voodoo.startT = val; + break; + case SST_startW: + voodoo.startW = val; + break; + + case SST_dRdX: + voodoo.dRdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dGdX: + voodoo.dGdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dBdX: + voodoo.dBdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dZdX: + voodoo.dZdX = val; + break; + case SST_dAdX: + voodoo.dAdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dSdX: + voodoo.dSdX = val; + break; + case SST_dTdX: + voodoo.dTdX = val; + break; + case SST_dWdX: + voodoo.dWdX = val; + break; + + case SST_dRdY: + voodoo.dRdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dGdY: + voodoo.dGdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dBdY: + voodoo.dBdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dZdY: + voodoo.dZdY = val; + break; + case SST_dAdY: + voodoo.dAdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dSdY: + voodoo.dSdY = val; + break; + case SST_dTdY: + voodoo.dTdY = val; + break; + case SST_dWdY: + voodoo.dWdY = val; + break; + + case SST_triangleCMD: + voodoo_triangle(&voodoo); + break; + + + case SST_fbzMode: + voodoo.fbzMode = val; + break; + case SST_lfbMode: + voodoo.lfbMode = val; + voodoo_recalc(); + break; + + case SST_color0: + voodoo.color0 = val; + break; + case SST_color1: + voodoo.color1 = val; + break; + + case SST_fbiInit4: + if (voodoo.initEnable & 0x01) + voodoo.fbiInit4 = val; + break; + case SST_fbiInit0: + if (voodoo.initEnable & 0x01) + voodoo.fbiInit0 = val; + break; + case SST_fbiInit1: + if (voodoo.initEnable & 0x01) + voodoo.fbiInit1 = val; + break; + case SST_fbiInit2: + if (voodoo.initEnable & 0x01) + { + voodoo.fbiInit2 = val; + voodoo_recalc(); + } + break; + case SST_fbiInit3: + if (voodoo.initEnable & 0x01) + voodoo.fbiInit3 = val; + break; + + case SST_dacData: + voodoo.dac_reg = (val >> 8) & 7; + voodoo.dac_readdata = 0xff; + if (val & 0x800) + { + pclog(" dacData read %i %02X\n", voodoo.dac_reg, voodoo.dac_data[7]); + if (voodoo.dac_reg == 5) + { + switch (voodoo.dac_data[7]) + { + case 0x01: voodoo.dac_readdata = 0x55; break; + case 0x07: voodoo.dac_readdata = 0x71; break; + case 0x0b: voodoo.dac_readdata = 0x79; break; + } + } + else + voodoo.dac_readdata = voodoo.dac_data[voodoo.dac_readdata]; + } + else + voodoo.dac_data[voodoo.dac_reg] = val & 0xff; + break; + } +} + +static uint16_t voodoo_fb_readw(uint32_t addr, void *priv) +{ + pclog("voodoo_fb_readw : %08X %04X\n", addr, *(uint16_t *)(&voodoo.fb_mem[addr & 0x1fffff])); + return *(uint16_t *)(&voodoo.fb_mem[addr & 0x1fffff]); +} +static uint32_t voodoo_fb_readl(uint32_t addr, void *priv) +{ + int x, y; + uint32_t read_addr; + uint32_t temp; + + x = (addr >> 1) & 0x3ff; + y = (addr >> 11) & 0x3ff; + read_addr = voodoo.fb_read_offset + (x << 1) + (y * voodoo.row_width); + + temp = *(uint32_t *)(&voodoo.fb_mem[read_addr & 0x1fffff]); + + pclog("voodoo_fb_readl : %08X %08X %i %i %08X %08X\n", addr, temp, x, y, read_addr, *(uint32_t *)(&voodoo.fb_mem[4])); + return temp; +} +static void voodoo_fb_writew(uint32_t addr, uint16_t val, void *priv) +{ + pclog("voodoo_fb_writew : %08X %04X\n", addr, val); + *(uint16_t *)(&voodoo.fb_mem[addr & 0x1fffff]) = val; +} +static void voodoo_fb_writel(uint32_t addr, uint32_t val, void *priv) +{ + int x, y; + uint32_t write_addr, write_addr_aux; + uint32_t colour_data, depth_data; + int write_mask, count = 1; + + pclog("voodoo_fb_writel : %08X %08X\n", addr, val); + + if (voodoo.lfbMode & 0x100) + fatal("voodoo_fb_writel : using pixel processing\n"); + + switch (voodoo.lfbMode & LFB_FORMAT_MASK) + { + case LFB_FORMAT_RGB565: + colour_data = val; + write_mask = LFB_WRITE_COLOUR; + break; + + case LFB_FORMAT_DEPTH: + depth_data = val; + write_mask = LFB_WRITE_DEPTH; + addr <<= 1; + count = 2; + break; + + default: + fatal("voodoo_fb_writel : bad LFB format %08X\n", voodoo.lfbMode); + } + + x = addr & 0x3fe; + y = (addr >> 10) & 0x3ff; + + write_addr = voodoo.fb_read_offset + x + (y * voodoo.row_width); + write_addr_aux = voodoo.aux_offset + x + (y * voodoo.row_width); + + while (count--) + { + if (write_mask & LFB_WRITE_COLOUR) + *(uint16_t *)(&voodoo.fb_mem[write_addr & 0x1ffffe]) = colour_data; + if (write_mask & LFB_WRITE_DEPTH) + *(uint16_t *)(&voodoo.fb_mem[write_addr_aux & 0x1ffffe]) = depth_data; + + colour_data >>= 16; + depth_data >>= 16; + + write_addr += 2; + write_addr_aux += 2; + } +} + +static void voodoo_tex_writew(uint32_t addr, uint16_t val, void *priv) +{ + pclog("voodoo_tex_write : %08X %04X\n", addr, val); + *(uint16_t *)(&voodoo.tex_mem[addr & 0x1fffff]) = val; +} +static void voodoo_tex_writel(uint32_t addr, uint32_t val, void *priv) +{ + pclog("voodoo_tex_write : %08X %08X\n", addr, val); + *(uint32_t *)(&voodoo.tex_mem[addr & 0x1fffff]) = val; +} + +static void voodoo_recalcmapping() +{ + mem_removehandler(0x00000000, 0xffffffff, NULL, NULL, voodoo_readl, NULL, NULL, voodoo_writel, NULL); + mem_removehandler(0x00000000, 0xffffffff, NULL, voodoo_fb_readw, voodoo_fb_readl, NULL, voodoo_fb_writew, voodoo_fb_writel, NULL); + mem_removehandler(0x00000000, 0xffffffff, NULL, NULL, NULL, NULL, voodoo_tex_writew, voodoo_tex_writel, NULL); + if (voodoo.pci_enable) + { + pclog("voodoo_recalcmapping : memBaseAddr %08X\n", voodoo.memBaseAddr); + mem_sethandler(voodoo.memBaseAddr, 0x003fffff, NULL, NULL, voodoo_readl, NULL, NULL, voodoo_writel, NULL); + mem_sethandler(voodoo.memBaseAddr + 0x00400000, 0x003fffff, NULL, voodoo_fb_readw, voodoo_fb_readl, NULL, voodoo_fb_writew, voodoo_fb_writel, NULL); + mem_sethandler(voodoo.memBaseAddr + 0x00800000, 0x007fffff, NULL, NULL, NULL, NULL, voodoo_tex_writew, voodoo_tex_writel, NULL); + } + else + pclog("voodoo_recalcmapping : disabled\n"); +} + +uint8_t voodoo_pci_read(int func, int addr, void *priv) +{ + pclog("Voodoo PCI read %08X\n", addr); + switch (addr) + { + case 0x00: return 0x1a; /*3dfx*/ + case 0x01: return 0x12; + + case 0x02: return 0x01; /*SST-1 (Voodoo Graphics)*/ + case 0x03: return 0x00; + + case 0x04: return voodoo.pci_enable ? 0x02 : 0x00; /*Respond to memory accesses*/ + + case 0x08: return 0; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + + case 0x10: return 0x00; /*memBaseAddr*/ + case 0x11: return 0x00; + case 0x12: return 0x00; + case 0x13: return voodoo.memBaseAddr >> 24; + + case 0x40: return voodoo.initEnable; + } + return 0; +} + +void voodoo_pci_write(int func, int addr, uint8_t val, void *priv) +{ + pclog("Voodoo PCI write %04X %02X\n", addr, val); + switch (addr) + { + case 0x04: voodoo.pci_enable = val & 2; voodoo_recalcmapping(); break; + + case 0x13: voodoo.memBaseAddr = val << 24; voodoo_recalcmapping(); break; + + case 0x40: voodoo.initEnable = val; break; + } +} + +void voodoo_init() +{ + return; + voodoo_make_dither(); + pci_add(voodoo_pci_read, voodoo_pci_write, NULL); + voodoo.fb_mem = malloc(2 * 1024 * 1024); + voodoo.tex_mem = malloc(2 * 1024 * 1024); +} diff --git a/src/vid_voodoo.h b/src/vid_voodoo.h new file mode 100644 index 0000000..26d40f5 --- /dev/null +++ b/src/vid_voodoo.h @@ -0,0 +1 @@ +void voodoo_init(); diff --git a/src/x86_ops.h b/src/x86_ops.h new file mode 100644 index 0000000..ce4f43a --- /dev/null +++ b/src/x86_ops.h @@ -0,0 +1,12 @@ +typedef int (*OpFn)(uint32_t fetchdat); + +void x86_setopcodes(OpFn *opcodes, OpFn *opcodes_0f); + +extern OpFn *x86_opcodes; +extern OpFn *x86_opcodes_0f; + +extern OpFn ops_286[1024]; +extern OpFn ops_286_0f[1024]; + +extern OpFn ops_386[1024]; +extern OpFn ops_386_0f[1024]; diff --git a/src/x86_ops_arith.h b/src/x86_ops_arith.h new file mode 100644 index 0000000..e047878 --- /dev/null +++ b/src/x86_ops_arith.h @@ -0,0 +1,645 @@ +#define OP_ARITH(name, operation, setflags, flagops) \ + static int op ## name ## _b_rmw_a16(uint32_t fetchdat) \ + { \ + int tempc = CF_SET(); \ + fetch_ea_16(fetchdat); \ + if (mod == 3) \ + { \ + uint8_t dst = getr8(rm); \ + uint8_t src = getr8(reg); \ + setflags ## 8 flagops; \ + setr8(rm, operation); \ + cycles -= timing_rr; \ + } \ + else \ + { \ + uint8_t dst = geteab(); if (abrt) return 0; \ + uint8_t src = getr8(reg); \ + seteab(operation); if (abrt) return 0; \ + setflags ## 8 flagops; \ + cycles -= timing_mr; \ + } \ + return 0; \ + } \ + static int op ## name ## _b_rmw_a32(uint32_t fetchdat) \ + { \ + int tempc = CF_SET(); \ + fetch_ea_32(fetchdat); \ + if (mod == 3) \ + { \ + uint8_t dst = getr8(rm); \ + uint8_t src = getr8(reg); \ + setflags ## 8 flagops; \ + setr8(rm, operation); \ + cycles -= timing_rr; \ + } \ + else \ + { \ + uint8_t dst = geteab(); if (abrt) return 0; \ + uint8_t src = getr8(reg); \ + seteab(operation); if (abrt) return 0; \ + setflags ## 8 flagops; \ + cycles -= timing_mr; \ + } \ + return 0; \ + } \ + \ + static int op ## name ## _w_rmw_a16(uint32_t fetchdat) \ + { \ + int tempc = CF_SET(); \ + fetch_ea_16(fetchdat); \ + if (mod == 3) \ + { \ + uint16_t dst = regs[rm].w; \ + uint16_t src = regs[reg].w; \ + setflags ## 16 flagops; \ + regs[rm].w = operation; \ + cycles -= timing_rr; \ + } \ + else \ + { \ + uint16_t dst = geteaw(); if (abrt) return 0; \ + uint16_t src = regs[reg].w; \ + seteaw(operation); if (abrt) return 0; \ + setflags ## 16 flagops; \ + cycles -= timing_mr; \ + } \ + return 0; \ + } \ + static int op ## name ## _w_rmw_a32(uint32_t fetchdat) \ + { \ + int tempc = CF_SET(); \ + fetch_ea_32(fetchdat); \ + if (mod == 3) \ + { \ + uint16_t dst = regs[rm].w; \ + uint16_t src = regs[reg].w; \ + setflags ## 16 flagops; \ + regs[rm].w = operation; \ + cycles -= timing_rr; \ + } \ + else \ + { \ + uint16_t dst = geteaw(); if (abrt) return 0; \ + uint16_t src = regs[reg].w; \ + seteaw(operation); if (abrt) return 0; \ + setflags ## 16 flagops; \ + cycles -= timing_mr; \ + } \ + return 0; \ + } \ + \ + static int op ## name ## _l_rmw_a16(uint32_t fetchdat) \ + { \ + int tempc = CF_SET(); \ + fetch_ea_16(fetchdat); \ + if (mod == 3) \ + { \ + uint32_t dst = regs[rm].l; \ + uint32_t src = regs[reg].l; \ + setflags ## 32 flagops; \ + regs[rm].l = operation; \ + cycles -= timing_rr; \ + } \ + else \ + { \ + uint32_t dst = geteal(); if (abrt) return 0; \ + uint32_t src = regs[reg].l; \ + seteal(operation); if (abrt) return 0; \ + setflags ## 32 flagops; \ + cycles -= timing_mrl; \ + } \ + return 0; \ + } \ + static int op ## name ## _l_rmw_a32(uint32_t fetchdat) \ + { \ + int tempc = CF_SET(); \ + fetch_ea_32(fetchdat); \ + if (mod == 3) \ + { \ + uint32_t dst = regs[rm].l; \ + uint32_t src = regs[reg].l; \ + setflags ## 32 flagops; \ + regs[rm].l = operation; \ + cycles -= timing_rr; \ + } \ + else \ + { \ + uint32_t dst = geteal(); if (abrt) return 0; \ + uint32_t src = regs[reg].l; \ + seteal(operation); if (abrt) return 0; \ + setflags ## 32 flagops; \ + cycles -= timing_mrl; \ + } \ + return 0; \ + } \ + \ + static int op ## name ## _b_rm_a16(uint32_t fetchdat) \ + { \ + int tempc = CF_SET(); \ + uint8_t dst, src; \ + fetch_ea_16(fetchdat); \ + dst = getr8(reg); \ + src = geteab(); if (abrt) return 0; \ + setflags ## 8 flagops; \ + setr8(reg, operation); \ + cycles -= (mod == 3) ? timing_rr : timing_rm; \ + return 0; \ + } \ + static int op ## name ## _b_rm_a32(uint32_t fetchdat) \ + { \ + int tempc = CF_SET(); \ + uint8_t dst, src; \ + fetch_ea_32(fetchdat); \ + dst = getr8(reg); \ + src = geteab(); if (abrt) return 0; \ + setflags ## 8 flagops; \ + setr8(reg, operation); \ + cycles -= (mod == 3) ? timing_rr : timing_rm; \ + return 0; \ + } \ + \ + static int op ## name ## _w_rm_a16(uint32_t fetchdat) \ + { \ + int tempc = CF_SET(); \ + uint16_t dst, src; \ + fetch_ea_16(fetchdat); \ + dst = regs[reg].w; \ + src = geteaw(); if (abrt) return 0; \ + setflags ## 16 flagops; \ + regs[reg].w = operation; \ + cycles -= (mod == 3) ? timing_rr : timing_rm; \ + return 0; \ + } \ + static int op ## name ## _w_rm_a32(uint32_t fetchdat) \ + { \ + int tempc = CF_SET(); \ + uint16_t dst, src; \ + fetch_ea_32(fetchdat); \ + dst = regs[reg].w; \ + src = geteaw(); if (abrt) return 0; \ + setflags ## 16 flagops; \ + regs[reg].w = operation; \ + cycles -= (mod == 3) ? timing_rr : timing_rm; \ + return 0; \ + } \ + \ + static int op ## name ## _l_rm_a16(uint32_t fetchdat) \ + { \ + int tempc = CF_SET(); \ + uint32_t dst, src; \ + fetch_ea_16(fetchdat); \ + dst = regs[reg].l; \ + src = geteal(); if (abrt) return 0; \ + setflags ## 32 flagops; \ + regs[reg].l = operation; \ + cycles -= (mod == 3) ? timing_rr : timing_rml; \ + return 0; \ + } \ + static int op ## name ## _l_rm_a32(uint32_t fetchdat) \ + { \ + int tempc = CF_SET(); \ + uint32_t dst, src; \ + fetch_ea_32(fetchdat); \ + dst = regs[reg].l; \ + src = geteal(); if (abrt) return 0; \ + setflags ## 32 flagops; \ + regs[reg].l = operation; \ + cycles -= (mod == 3) ? timing_rr : timing_rml; \ + return 0; \ + } \ + \ + static int op ## name ## _AL_imm(uint32_t fetchdat) \ + { \ + int tempc = CF_SET(); \ + uint8_t dst = AL; \ + uint8_t src = getbytef(); \ + setflags ## 8 flagops; \ + AL = operation; \ + cycles -= timing_rr; \ + return 0; \ + } \ + \ + static int op ## name ## _AX_imm(uint32_t fetchdat) \ + { \ + int tempc = CF_SET(); \ + uint16_t dst = AX; \ + uint16_t src = getwordf(); \ + setflags ## 16 flagops; \ + AX = operation; \ + cycles -= timing_rr; \ + return 0; \ + } \ + \ + static int op ## name ## _EAX_imm(uint32_t fetchdat) \ + { \ + int tempc = CF_SET(); \ + uint32_t dst = EAX; \ + uint32_t src = getlong(); \ + setflags ## 32 flagops; \ + EAX = operation; \ + cycles -= timing_rr; \ + return 0; \ + } + +OP_ARITH(ADD, dst + src, setadd, (dst, src)) +OP_ARITH(ADC, dst + src + tempc, setadc, (dst, src)) +OP_ARITH(SUB, dst - src, setsub, (dst, src)) +OP_ARITH(SBB, dst - (src + tempc), setsbc, (dst, src)) +OP_ARITH(OR, dst | src, setznp, (dst | src)) +OP_ARITH(AND, dst & src, setznp, (dst & src)) +OP_ARITH(XOR, dst ^ src, setznp, (dst ^ src)) + +static int opCMP_b_rmw_a16(uint32_t fetchdat) +{ + uint8_t dst; + fetch_ea_16(fetchdat); + dst = geteab(); if (abrt) return 0; + setsub8(dst, getr8(reg)); + if (is486) cycles -= ((mod == 3) ? 1 : 2); + else cycles -= ((mod == 3) ? 2 : 5); + return 0; +} +static int opCMP_b_rmw_a32(uint32_t fetchdat) +{ + uint8_t dst; + fetch_ea_32(fetchdat); + dst = geteab(); if (abrt) return 0; + setsub8(dst, getr8(reg)); + if (is486) cycles -= ((mod == 3) ? 1 : 2); + else cycles -= ((mod == 3) ? 2 : 5); + return 0; +} + +static int opCMP_w_rmw_a16(uint32_t fetchdat) +{ + uint16_t dst; + fetch_ea_16(fetchdat); + dst = geteaw(); if (abrt) return 0; + setsub16(dst, regs[reg].w); + if (is486) cycles -= ((mod == 3) ? 1 : 2); + else cycles -= ((mod == 3) ? 2 : 5); + return 0; +} +static int opCMP_w_rmw_a32(uint32_t fetchdat) +{ + uint16_t dst; + fetch_ea_32(fetchdat); + dst = geteaw(); if (abrt) return 0; + setsub16(dst, regs[reg].w); + if (is486) cycles -= ((mod == 3) ? 1 : 2); + else cycles -= ((mod == 3) ? 2 : 5); + return 0; +} + +static int opCMP_l_rmw_a16(uint32_t fetchdat) +{ + uint32_t dst; + fetch_ea_16(fetchdat); + dst = geteal(); if (abrt) return 0; + setsub32(dst, regs[reg].l); + if (is486) cycles -= ((mod == 3) ? 1 : 2); + else cycles -= ((mod == 3) ? 2 : 5); + return 0; +} +static int opCMP_l_rmw_a32(uint32_t fetchdat) +{ + uint32_t dst; + fetch_ea_32(fetchdat); + dst = geteal(); if (abrt) return 0; + setsub32(dst, regs[reg].l); + if (is486) cycles -= ((mod == 3) ? 1 : 2); + else cycles -= ((mod == 3) ? 2 : 5); + return 0; +} + +static int opCMP_b_rm_a16(uint32_t fetchdat) +{ + uint8_t src; + fetch_ea_16(fetchdat); + src = geteab(); if (abrt) return 0; + setsub8(getr8(reg), src); + cycles -= (mod == 3) ? timing_rr : timing_rm; + return 0; +} +static int opCMP_b_rm_a32(uint32_t fetchdat) +{ + uint8_t src; + fetch_ea_32(fetchdat); + src = geteab(); if (abrt) return 0; + setsub8(getr8(reg), src); + cycles -= (mod == 3) ? timing_rr : timing_rm; + return 0; +} + +static int opCMP_w_rm_a16(uint32_t fetchdat) +{ + uint16_t src; + fetch_ea_16(fetchdat); + src = geteaw(); if (abrt) return 0; + setsub16(regs[reg].w, src); + cycles -= (mod == 3) ? timing_rr : timing_rm; + return 0; +} +static int opCMP_w_rm_a32(uint32_t fetchdat) +{ + uint16_t src; + fetch_ea_32(fetchdat); + src = geteaw(); if (abrt) return 0; + setsub16(regs[reg].w, src); + cycles -= (mod == 3) ? timing_rr : timing_rm; + return 0; +} + +static int opCMP_l_rm_a16(uint32_t fetchdat) +{ + uint32_t src; + fetch_ea_16(fetchdat); + src = geteal(); if (abrt) return 0; + setsub32(regs[reg].l, src); + cycles -= (mod == 3) ? timing_rr : timing_rml; + return 0; +} +static int opCMP_l_rm_a32(uint32_t fetchdat) +{ + uint32_t src; + fetch_ea_32(fetchdat); + src = geteal(); if (abrt) return 0; + setsub32(regs[reg].l, src); + cycles -= (mod == 3) ? timing_rr : timing_rml; + return 0; +} + +static int opCMP_AL_imm(uint32_t fetchdat) +{ + uint8_t src = getbytef(); + setsub8(AL, src); + cycles -= timing_rr; + return 0; +} + +static int opCMP_AX_imm(uint32_t fetchdat) +{ + uint16_t src = getwordf(); + setsub16(AX, src); + cycles -= timing_rr; + return 0; +} + +static int opCMP_EAX_imm(uint32_t fetchdat) +{ + uint32_t src = getlong(); + setsub32(EAX, src); + cycles -= timing_rr; + return 0; +} + +static int opTEST_b_a16(uint32_t fetchdat) +{ + uint8_t temp, temp2; + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 0; + temp2 = getr8(reg); + setznp8(temp & temp2); + if (is486) cycles -= ((mod == 3) ? 1 : 2); + else cycles -= ((mod == 3) ? 2 : 5); + return 0; +} +static int opTEST_b_a32(uint32_t fetchdat) +{ + uint8_t temp, temp2; + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 0; + temp2 = getr8(reg); + setznp8(temp & temp2); + if (is486) cycles -= ((mod == 3) ? 1 : 2); + else cycles -= ((mod == 3) ? 2 : 5); + return 0; +} + +static int opTEST_w_a16(uint32_t fetchdat) +{ + uint16_t temp, temp2; + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 0; + temp2 = regs[reg].w; + setznp16(temp & temp2); + if (is486) cycles -= ((mod == 3) ? 1 : 2); + else cycles -= ((mod == 3) ? 2 : 5); + return 0; +} +static int opTEST_w_a32(uint32_t fetchdat) +{ + uint16_t temp, temp2; + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 0; + temp2 = regs[reg].w; + setznp16(temp & temp2); + if (is486) cycles -= ((mod == 3) ? 1 : 2); + else cycles -= ((mod == 3) ? 2 : 5); + return 0; +} + +static int opTEST_l_a16(uint32_t fetchdat) +{ + uint32_t temp, temp2; + fetch_ea_16(fetchdat); + temp = geteal(); if (abrt) return 0; + temp2 = regs[reg].l; + setznp32(temp & temp2); + if (is486) cycles -= ((mod == 3) ? 1 : 2); + else cycles -= ((mod == 3) ? 2 : 5); + return 0; +} +static int opTEST_l_a32(uint32_t fetchdat) +{ + uint32_t temp, temp2; + fetch_ea_32(fetchdat); + temp = geteal(); if (abrt) return 0; + temp2 = regs[reg].l; + setznp32(temp & temp2); + if (is486) cycles -= ((mod == 3) ? 1 : 2); + else cycles -= ((mod == 3) ? 2 : 5); + return 0; +} + +static int opTEST_AL(uint32_t fetchdat) +{ + uint8_t temp = getbytef(); + setznp8(AL & temp); + cycles -= timing_rr; + return 0; +} +static int opTEST_AX(uint32_t fetchdat) +{ + uint16_t temp = getwordf(); + setznp16(AX & temp); + cycles -= timing_rr; + return 0; +} +static int opTEST_EAX(uint32_t fetchdat) +{ + uint32_t temp = getlong(); if (abrt) return 0; + setznp32(EAX & temp); + cycles -= timing_rr; + return 0; +} + + +#define ARITH_MULTI(ea_width, flag_width) \ + dst = getea ## ea_width(); if (abrt) return 0; \ + switch (rmdat&0x38) \ + { \ + case 0x00: /*ADD ea, #*/ \ + setea ## ea_width(dst + src); if (abrt) return 0; \ + setadd ## flag_width(dst, src); \ + cycles -= (mod == 3) ? timing_rr : timing_mr; \ + break; \ + case 0x08: /*OR ea, #*/ \ + dst |= src; \ + setea ## ea_width(dst); if (abrt) return 0; \ + setznp ## flag_width(dst); \ + cycles -= (mod == 3) ? timing_rr : timing_mr; \ + break; \ + case 0x10: /*ADC ea, #*/ \ + setea ## ea_width(dst + src + tempc); if (abrt) return 0; \ + setadc ## flag_width(dst, src); \ + cycles -= (mod == 3) ? timing_rr : timing_mr; \ + break; \ + case 0x18: /*SBB ea, #*/ \ + setea ## ea_width(dst - (src + tempc)); if (abrt) return 0; \ + setsbc ## flag_width(dst, src); \ + cycles -= (mod == 3) ? timing_rr : timing_mr; \ + break; \ + case 0x20: /*AND ea, #*/ \ + dst &= src; \ + setea ## ea_width(dst); if (abrt) return 0; \ + setznp ## flag_width(dst); \ + cycles -= (mod == 3) ? timing_rr : timing_mr; \ + break; \ + case 0x28: /*SUB ea, #*/ \ + setea ## ea_width(dst - src); if (abrt) return 0; \ + setsub ## flag_width(dst, src); \ + cycles -= (mod == 3) ? timing_rr : timing_mr; \ + break; \ + case 0x30: /*XOR ea, #*/ \ + dst ^= src; \ + setea ## ea_width(dst); if (abrt) return 0; \ + setznp ## flag_width(dst); \ + cycles -= (mod == 3) ? timing_rr : timing_mr; \ + break; \ + case 0x38: /*CMP ea, #*/ \ + setsub ## flag_width(dst, src); \ + if (is486) cycles -= ((mod == 3) ? 1 : 2); \ + else cycles -= ((mod == 3) ? 2 : 7); \ + break; \ + } + + +static int op80_a16(uint32_t fetchdat) +{ + uint8_t src, dst; + + fetch_ea_16(fetchdat); + src = getbyte(); if (abrt) return 0; + ARITH_MULTI(b, 8); + + return 0; +} +static int op80_a32(uint32_t fetchdat) +{ + uint8_t src, dst; + + fetch_ea_32(fetchdat); + src = getbyte(); if (abrt) return 0; + ARITH_MULTI(b, 8); + + return 0; +} +static int op81_w_a16(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_16(fetchdat); + src = getword(); if (abrt) return 0; + ARITH_MULTI(w, 16); + + return 0; +} +static int op81_w_a32(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_32(fetchdat); + src = getword(); if (abrt) return 0; + ARITH_MULTI(w, 16); + + return 0; +} +static int op81_l_a16(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_16(fetchdat); + src = getlong(); if (abrt) return 0; + ARITH_MULTI(l, 32); + + return 0; +} +static int op81_l_a32(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_32(fetchdat); + src = getlong(); if (abrt) return 0; + ARITH_MULTI(l, 32); + + return 0; +} + +static int op83_w_a16(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_16(fetchdat); + src = getbyte(); if (abrt) return 0; + if (src & 0x80) src |= 0xff00; + ARITH_MULTI(w, 16); + + return 0; +} +static int op83_w_a32(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_32(fetchdat); + src = getbyte(); if (abrt) return 0; + if (src & 0x80) src |= 0xff00; + ARITH_MULTI(w, 16); + + return 0; +} + +static int op83_l_a16(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_16(fetchdat); + src = getbyte(); if (abrt) return 0; + if (src & 0x80) src |= 0xffffff00; + ARITH_MULTI(l, 32); + + return 0; +} +static int op83_l_a32(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_32(fetchdat); + src = getbyte(); if (abrt) return 0; + if (src & 0x80) src |= 0xffffff00; + ARITH_MULTI(l, 32); + + return 0; +} + diff --git a/src/x86_ops_atomic.h b/src/x86_ops_atomic.h new file mode 100644 index 0000000..0f8c8ee --- /dev/null +++ b/src/x86_ops_atomic.h @@ -0,0 +1,209 @@ +static int opCMPXCHG_b_a16(uint32_t fetchdat) +{ + uint8_t temp, temp2 = AL; + if (!is486) + { + pc = oldpc; + x86illegal(); + return 0; + } + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 0; + if (AL == temp) seteab(getr8(reg)); + else AL = temp; + if (abrt) return 0; + setsub8(temp2, temp); + cycles -= (mod == 3) ? 6 : 10; + return 0; +} +static int opCMPXCHG_b_a32(uint32_t fetchdat) +{ + uint8_t temp, temp2 = AL; + if (!is486) + { + pc = oldpc; + x86illegal(); + return 0; + } + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 0; + if (AL == temp) seteab(getr8(reg)); + else AL = temp; + if (abrt) return 0; + setsub8(temp2, temp); + cycles -= (mod == 3) ? 6 : 10; + return 0; +} + +static int opCMPXCHG_w_a16(uint32_t fetchdat) +{ + uint16_t temp, temp2 = AX; + if (!is486) + { + pc = oldpc; + x86illegal(); + return 0; + } + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 0; + if (AX == temp) seteaw(regs[reg].w); + else AX = temp; + if (abrt) return 0; + setsub16(temp2, temp); + cycles -= (mod == 3) ? 6 : 10; + return 0; +} +static int opCMPXCHG_w_a32(uint32_t fetchdat) +{ + uint16_t temp, temp2 = AX; + if (!is486) + { + pc = oldpc; + x86illegal(); + return 0; + } + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 0; + if (AX == temp) seteaw(regs[reg].w); + else AX = temp; + if (abrt) return 0; + setsub16(temp2, temp); + cycles -= (mod == 3) ? 6 : 10; + return 0; +} + +static int opCMPXCHG_l_a16(uint32_t fetchdat) +{ + uint32_t temp, temp2 = EAX; + if (!is486) + { + pc = oldpc; + x86illegal(); + return 0; + } + fetch_ea_16(fetchdat); + temp = geteal(); if (abrt) return 0; + if (EAX == temp) seteal(regs[reg].l); + else EAX = temp; + if (abrt) return 0; + setsub32(temp2, temp); + cycles -= (mod == 3) ? 6 : 10; + return 0; +} +static int opCMPXCHG_l_a32(uint32_t fetchdat) +{ + uint32_t temp, temp2 = EAX; + if (!is486) + { + pc = oldpc; + x86illegal(); + return 0; + } + fetch_ea_32(fetchdat); + temp = geteal(); if (abrt) return 0; + if (EAX == temp) seteal(regs[reg].l); + else EAX = temp; + if (abrt) return 0; + setsub32(temp2, temp); + cycles -= (mod == 3) ? 6 : 10; + return 0; +} + +static int opXADD_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + if (!is486) + { + pc = oldpc; + x86illegal(); + return 0; + } + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 0; + seteab(temp + getr8(reg)); if (abrt) return 0; + setadd8(temp, getr8(reg)); + setr8(reg, temp); + return 0; +} +static int opXADD_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + if (!is486) + { + pc = oldpc; + x86illegal(); + return 0; + } + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 0; + seteab(temp + getr8(reg)); if (abrt) return 0; + setadd8(temp, getr8(reg)); + setr8(reg, temp); + return 0; +} + +static int opXADD_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + if (!is486) + { + pc = oldpc; + x86illegal(); + return 0; + } + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 0; + seteaw(temp + regs[reg].w); if (abrt) return 0; + setadd16(temp, regs[reg].w); + regs[reg].w = temp; + return 0; +} +static int opXADD_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + if (!is486) + { + pc = oldpc; + x86illegal(); + return 0; + } + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 0; + seteaw(temp + regs[reg].w); if (abrt) return 0; + setadd16(temp, regs[reg].w); + regs[reg].w = temp; + return 0; +} + +static int opXADD_l_a16(uint32_t fetchdat) +{ + uint32_t temp; + if (!is486) + { + pc = oldpc; + x86illegal(); + return 0; + } + fetch_ea_16(fetchdat); + temp = geteal(); if (abrt) return 0; + seteal(temp + regs[reg].l); if (abrt) return 0; + setadd32(temp, regs[reg].l); + regs[reg].l = temp; + return 0; +} +static int opXADD_l_a32(uint32_t fetchdat) +{ + uint32_t temp; + if (!is486) + { + pc = oldpc; + x86illegal(); + return 0; + } + fetch_ea_32(fetchdat); + temp = geteal(); if (abrt) return 0; + seteal(temp + regs[reg].l); if (abrt) return 0; + setadd32(temp, regs[reg].l); + regs[reg].l = temp; + return 0; +} diff --git a/src/x86_ops_bcd.h b/src/x86_ops_bcd.h new file mode 100644 index 0000000..2627402 --- /dev/null +++ b/src/x86_ops_bcd.h @@ -0,0 +1,105 @@ +static int opAAA(uint32_t fetchdat) +{ + flags_rebuild(); + if ((flags & A_FLAG) || ((AL & 0xF) > 9)) + { + AL += 6; + AH++; + flags |= (A_FLAG | C_FLAG); + } + else + flags &= ~(A_FLAG | C_FLAG); + AL &= 0xF; + cycles -= is486 ? 3 : 4; + return 0; +} + +static int opAAD(uint32_t fetchdat) +{ + int base = getbytef(); + if (cpu_manufacturer != MANU_INTEL) base = 10; + AL = (AH * base) + AL; + AH = 0; + setznp16(AX); + cycles -= (is486) ? 14 : 19; + return 0; +} + +static int opAAM(uint32_t fetchdat) +{ + int base = getbytef(); + if (!base || cpu_manufacturer != MANU_INTEL) base = 10; + AH = AL / base; + AL %= base; + setznp16(AX); + cycles -= (is486) ? 15 : 17; + return 0; +} + +static int opAAS(uint32_t fetchdat) +{ + flags_rebuild(); + if ((flags & A_FLAG) || ((AL & 0xF) > 9)) + { + AL -= 6; + AH--; + flags |= (A_FLAG | C_FLAG); + } + else + flags &= ~(A_FLAG | C_FLAG); + AL &= 0xF; + cycles -= is486 ? 3 : 4; + return 0; +} + +static int opDAA(uint32_t fetchdat) +{ + uint16_t tempw; + + flags_rebuild(); + if ((flags & A_FLAG) || ((AL & 0xf) > 9)) + { + int tempi = ((uint16_t)AL) + 6; + AL += 6; + flags |= A_FLAG; + if (tempi & 0x100) flags |= C_FLAG; + } + if ((flags & C_FLAG) || (AL > 0x9f)) + { + AL += 0x60; + flags |= C_FLAG; + } + + tempw = flags & (C_FLAG | A_FLAG); + setznp8(AL); + flags |= tempw; + cycles -= 4; + + return 0; +} + +static int opDAS(uint32_t fetchdat) +{ + uint16_t tempw; + + flags_rebuild(); + if ((flags & A_FLAG) || ((AL & 0xf) > 9)) + { + int tempi = ((uint16_t)AL) - 6; + AL -= 6; + flags |= A_FLAG; + if (tempi & 0x100) flags |= C_FLAG; + } + if ((flags & C_FLAG) || (AL > 0x9f)) + { + AL -= 0x60; + flags |= C_FLAG; + } + + tempw = flags & (C_FLAG | A_FLAG); + setznp8(AL); + flags |= tempw; + cycles -= 4; + + return 0; +} diff --git a/src/x86_ops_bit.h b/src/x86_ops_bit.h new file mode 100644 index 0000000..df0e2c7 --- /dev/null +++ b/src/x86_ops_bit.h @@ -0,0 +1,297 @@ +static int opBT_w_r_a16(uint32_t fetchdat) +{ + int tempc; + uint16_t temp; + + fetch_ea_16(fetchdat); + eaaddr += ((regs[reg].w / 16) * 2); eal_r = 0; + temp = geteaw(); if (abrt) return 0; + flags_rebuild(); + if (temp & (1 << (regs[reg].w & 15))) flags |= C_FLAG; + else flags &= ~C_FLAG; + + cycles -= 3; + return 0; +} +static int opBT_w_r_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + eaaddr += ((regs[reg].w / 16) * 2); eal_r = 0; + temp = geteaw(); if (abrt) return 0; + flags_rebuild(); + if (temp & (1 << (regs[reg].w & 15))) flags |= C_FLAG; + else flags &= ~C_FLAG; + + cycles -= 3; + return 0; +} +static int opBT_l_r_a16(uint32_t fetchdat) +{ + uint32_t temp; + + fetch_ea_16(fetchdat); + eaaddr += ((regs[reg].l / 32) * 4); eal_r = 0; + temp = geteal(); if (abrt) return 0; + flags_rebuild(); + if (temp & (1 << (regs[reg].l & 31))) flags |= C_FLAG; + else flags &= ~C_FLAG; + + cycles -= 3; + return 0; +} +static int opBT_l_r_a32(uint32_t fetchdat) +{ + uint32_t temp; + + fetch_ea_32(fetchdat); + eaaddr += ((regs[reg].l / 32) * 4); eal_r = 0; + temp = geteal(); if (abrt) return 0; + flags_rebuild(); + if (temp & (1 << (regs[reg].l & 31))) flags |= C_FLAG; + else flags &= ~C_FLAG; + + cycles -= 3; + return 0; +} + +#define opBT(name, operation) \ + static int opBT ## name ## _w_r_a16(uint32_t fetchdat) \ + { \ + int tempc; \ + uint16_t temp; \ + \ + fetch_ea_16(fetchdat); \ + eaaddr += ((regs[reg].w / 16) * 2); eal_r = eal_w = 0; \ + temp = geteaw(); if (abrt) return 0; \ + tempc = (temp & (1 << (regs[reg].w & 15))) ? 1 : 0; \ + temp operation (1 << (regs[reg].w & 15)); \ + seteaw(temp); if (abrt) return 0; \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + else flags &= ~C_FLAG; \ + \ + cycles -= 6; \ + return 0; \ + } \ + static int opBT ## name ## _w_r_a32(uint32_t fetchdat) \ + { \ + int tempc; \ + uint16_t temp; \ + \ + fetch_ea_32(fetchdat); \ + eaaddr += ((regs[reg].w / 16) * 2); eal_r = eal_w = 0; \ + temp = geteaw(); if (abrt) return 0; \ + tempc = (temp & (1 << (regs[reg].w & 15))) ? 1 : 0; \ + temp operation (1 << (regs[reg].w & 15)); \ + seteaw(temp); if (abrt) return 0; \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + else flags &= ~C_FLAG; \ + \ + cycles -= 6; \ + return 0; \ + } \ + static int opBT ## name ## _l_r_a16(uint32_t fetchdat) \ + { \ + int tempc; \ + uint32_t temp; \ + \ + fetch_ea_16(fetchdat); \ + eaaddr += ((regs[reg].l / 32) * 4); eal_r = eal_w = 0; \ + temp = geteal(); if (abrt) return 0; \ + tempc = (temp & (1 << (regs[reg].l & 31))) ? 1 : 0; \ + temp operation (1 << (regs[reg].l & 31)); \ + seteal(temp); if (abrt) return 0; \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + else flags &= ~C_FLAG; \ + \ + cycles -= 6; \ + return 0; \ + } \ + static int opBT ## name ## _l_r_a32(uint32_t fetchdat) \ + { \ + int tempc; \ + uint32_t temp; \ + \ + fetch_ea_32(fetchdat); \ + eaaddr += ((regs[reg].l / 32) * 4); eal_r = eal_w = 0; \ + temp = geteal(); if (abrt) return 0; \ + tempc = (temp & (1 << (regs[reg].l & 31))) ? 1 : 0; \ + temp operation (1 << (regs[reg].l & 31)); \ + seteal(temp); if (abrt) return 0; \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + else flags &= ~C_FLAG; \ + \ + cycles -= 6; \ + return 0; \ + } + +opBT(C, ^=) +opBT(R, &=~) +opBT(S, |=) + +static int opBA_w_a16(uint32_t fetchdat) +{ + int tempc, count; + uint16_t temp; + + fetch_ea_16(fetchdat); + + temp = geteaw(); + count = getbyte(); if (abrt) return 0; + tempc = temp & (1 << count); + flags_rebuild(); + switch (rmdat & 0x38) + { + case 0x20: /*BT w,imm*/ + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + cycles -= 3; + return 0; + case 0x28: /*BTS w,imm*/ + temp |= (1 << count); + break; + case 0x30: /*BTR w,imm*/ + temp &= ~(1 << count); + break; + case 0x38: /*BTC w,imm*/ + temp ^= (1 << count); + break; + + default: + pclog("Bad 0F BA opcode %02X\n", rmdat & 0x38); + pc = oldpc; + x86illegal(); + break; + } + seteaw(temp); if (abrt) return 0; + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + cycles -= 6; + return 0; +} +static int opBA_w_a32(uint32_t fetchdat) +{ + int tempc, count; + uint16_t temp; + + fetch_ea_32(fetchdat); + + temp = geteaw(); + count = getbyte(); if (abrt) return 0; + tempc = temp & (1 << count); + flags_rebuild(); + switch (rmdat & 0x38) + { + case 0x20: /*BT w,imm*/ + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + cycles -= 3; + return 0; + case 0x28: /*BTS w,imm*/ + temp |= (1 << count); + break; + case 0x30: /*BTR w,imm*/ + temp &= ~(1 << count); + break; + case 0x38: /*BTC w,imm*/ + temp ^= (1 << count); + break; + + default: + pclog("Bad 0F BA opcode %02X\n", rmdat & 0x38); + pc = oldpc; + x86illegal(); + break; + } + seteaw(temp); if (abrt) return 0; + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + cycles -= 6; + return 0; +} + +static int opBA_l_a16(uint32_t fetchdat) +{ + int tempc, count; + uint32_t temp; + + fetch_ea_16(fetchdat); + + temp = geteal(); + count = getbyte(); if (abrt) return 0; + tempc = temp & (1 << count); + flags_rebuild(); + switch (rmdat & 0x38) + { + case 0x20: /*BT w,imm*/ + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + cycles -= 3; + return 0; + case 0x28: /*BTS w,imm*/ + temp |= (1 << count); + break; + case 0x30: /*BTR w,imm*/ + temp &= ~(1 << count); + break; + case 0x38: /*BTC w,imm*/ + temp ^= (1 << count); + break; + + default: + pclog("Bad 0F BA opcode %02X\n", rmdat & 0x38); + pc = oldpc; + x86illegal(); + break; + } + seteal(temp); if (abrt) return 0; + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + cycles -= 6; + return 0; +} +static int opBA_l_a32(uint32_t fetchdat) +{ + int tempc, count; + uint32_t temp; + + fetch_ea_32(fetchdat); + + temp = geteal(); + count = getbyte(); if (abrt) return 0; + tempc = temp & (1 << count); + flags_rebuild(); + switch (rmdat & 0x38) + { + case 0x20: /*BT w,imm*/ + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + cycles -= 3; + return 0; + case 0x28: /*BTS w,imm*/ + temp |= (1 << count); + break; + case 0x30: /*BTR w,imm*/ + temp &= ~(1 << count); + break; + case 0x38: /*BTC w,imm*/ + temp ^= (1 << count); + break; + + default: + pclog("Bad 0F BA opcode %02X\n", rmdat & 0x38); + pc = oldpc; + x86illegal(); + break; + } + seteal(temp); if (abrt) return 0; + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + cycles -= 6; + return 0; +} diff --git a/src/x86_ops_bitscan.h b/src/x86_ops_bitscan.h new file mode 100644 index 0000000..4c4a3db --- /dev/null +++ b/src/x86_ops_bitscan.h @@ -0,0 +1,117 @@ +#define BS_common(start, end, dir, dest, time) \ + flags_rebuild(); \ + if (temp) \ + { \ + int c; \ + flags &= ~Z_FLAG; \ + for (c = start; c != end; c += dir) \ + { \ + cycles -= time; \ + if (temp & (1 << c)) \ + { \ + dest = c; \ + break; \ + } \ + } \ + } \ + else \ + flags |= Z_FLAG; + +static int opBSF_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 0; + + BS_common(0, 16, 1, regs[reg].w, (is486) ? 1 : 3); + + cycles -= (is486) ? 6 : 10; + return 0; +} +static int opBSF_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 0; + + BS_common(0, 16, 1, regs[reg].w, (is486) ? 1 : 3); + + cycles -= (is486) ? 6 : 10; + return 0; +} +static int opBSF_l_a16(uint32_t fetchdat) +{ + uint32_t temp; + + fetch_ea_16(fetchdat); + temp = geteal(); if (abrt) return 0; + + BS_common(0, 32, 1, regs[reg].l, (is486) ? 1 : 3); + + cycles -= (is486) ? 6 : 10; + return 0; +} +static int opBSF_l_a32(uint32_t fetchdat) +{ + uint32_t temp; + + fetch_ea_32(fetchdat); + temp = geteal(); if (abrt) return 0; + + BS_common(0, 32, 1, regs[reg].l, (is486) ? 1 : 3); + + cycles -= (is486) ? 6 : 10; + return 0; +} + +static int opBSR_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 0; + + BS_common(15, -1, -1, regs[reg].w, 3); + + cycles -= (is486) ? 6 : 10; + return 0; +} +static int opBSR_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 0; + + BS_common(15, -1, -1, regs[reg].w, 3); + + cycles -= (is486) ? 6 : 10; + return 0; +} +static int opBSR_l_a16(uint32_t fetchdat) +{ + uint32_t temp; + + fetch_ea_16(fetchdat); + temp = geteal(); if (abrt) return 0; + + BS_common(31, -1, -1, regs[reg].l, 3); + + cycles -= (is486) ? 6 : 10; + return 0; +} +static int opBSR_l_a32(uint32_t fetchdat) +{ + uint32_t temp; + + fetch_ea_32(fetchdat); + temp = geteal(); if (abrt) return 0; + + BS_common(31, -1, -1, regs[reg].l, 3); + + cycles -= (is486) ? 6 : 10; + return 0; +} + diff --git a/src/x86_ops_call.h b/src/x86_ops_call.h new file mode 100644 index 0000000..c97860a --- /dev/null +++ b/src/x86_ops_call.h @@ -0,0 +1,366 @@ +#define CALL_FAR_w(new_seg, new_pc) \ + old_cs = CS; \ + old_pc = pc; \ + if (ssegs) ss = oldss; \ + oxpc = pc; \ + pc = new_pc; \ + optype = CALL; \ + cgate16 = cgate32 = 0; \ + if (msw & 1) loadcscall(new_seg); \ + else loadcs(new_seg); \ + optype = 0; \ + if (abrt) { cgate16 = cgate32 = 0; return 0; } \ + oldss = ss; \ + if (cgate32) \ + { \ + PUSH_L(old_cs); if (abrt) { cgate16 = cgate32 = 0; return 0; } \ + PUSH_L(old_pc); \ + } \ + else \ + { \ + PUSH_W(old_cs); if (abrt) { cgate16 = cgate32 = 0; return 0; } \ + PUSH_W(old_pc); \ + } + +#define CALL_FAR_l(new_seg, new_pc) \ + old_cs = CS; \ + old_pc = pc; \ + if (ssegs) ss = oldss; \ + oxpc = pc; \ + pc = new_pc; \ + optype = CALL; \ + cgate16 = cgate32 = 0; \ + if (msw & 1) loadcscall(new_seg); \ + else loadcs(new_seg); \ + optype = 0; \ + if (abrt) { cgate16 = cgate32 = 0; return 0; } \ + oldss = ss; \ + if (cgate16) \ + { \ + PUSH_W(old_cs); if (abrt) { cgate16 = cgate32 = 0; return 0; } \ + PUSH_W(old_pc); \ + } \ + else \ + { \ + PUSH_L(old_cs); if (abrt) { cgate16 = cgate32 = 0; return 0; } \ + PUSH_L(old_pc); \ + } + + +#define CALL_FAR_nr(new_seg, new_pc) \ + old_cs = CS; \ + old_pc = pc; \ + if (ssegs) ss = oldss; \ + oxpc = pc; \ + pc = new_pc; \ + optype = CALL; \ + cgate16 = cgate32 = 0; \ + if (msw & 1) loadcscall(new_seg); \ + else loadcs(new_seg); \ + optype = 0; \ + if (abrt) { cgate16 = cgate32 = 0; break; } \ + oldss = ss; \ + if (cgate32) \ + { \ + PUSH_L(old_cs); if (abrt) { cgate16 = cgate32 = 0; break; } \ + PUSH_L(old_pc); \ + } \ + else \ + { \ + PUSH_W(old_cs); if (abrt) { cgate16 = cgate32 = 0; break; } \ + PUSH_W(old_pc); \ + } \ + +static int opCALL_far_w(uint32_t fetchdat) +{ + uint32_t old_cs, old_pc; + uint16_t new_cs, new_pc; + + new_pc = getwordf(); + new_cs = getword(); if (abrt) return 0; + + CALL_FAR_w(new_cs, new_pc); + + cycles -= is486 ? 18 : 17; + return 0; +} +static int opCALL_far_l(uint32_t fetchdat) +{ + uint32_t old_cs, old_pc; + uint32_t new_cs, new_pc; + + new_pc = getlong(); + new_cs = getword(); if (abrt) return 0; + + CALL_FAR_l(new_cs, new_pc); + + cycles -= is486 ? 18 : 17; + return 0; +} + + +static int opFF_w_a16(uint32_t fetchdat) +{ + uint16_t old_cs, new_cs; + uint32_t old_pc, new_pc; + + uint16_t temp; + + fetch_ea_16(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*INC w*/ + temp = geteaw(); if (abrt) return 0; + seteaw(temp + 1); if (abrt) return 0; + setadd16nc(temp, 1); + cycles -= (mod == 3) ? timing_rr : timing_mm; + break; + case 0x08: /*DEC w*/ + temp = geteaw(); if (abrt) return 0; + seteaw(temp - 1); if (abrt) return 0; + setsub16nc(temp, 1); + cycles -= (mod == 3) ? timing_rr : timing_mm; + break; + case 0x10: /*CALL*/ + new_pc = geteaw(); if (abrt) return 0; + if (ssegs) ss = oldss; + PUSH_W(pc); + pc = new_pc; + if (is486) cycles -= 5; + else cycles -= ((mod == 3) ? 7 : 10); + break; + case 0x18: /*CALL far*/ + new_pc = readmemw(easeg, eaaddr); + new_cs = readmemw(easeg, (eaaddr + 2)); if (abrt) return 0; + + CALL_FAR_w(new_cs, new_pc); + + cycles -= is486 ? 17 : 22; + break; + case 0x20: /*JMP*/ + new_pc = geteaw(); if (abrt) return 0; + pc = new_pc; + if (is486) cycles -= 5; + else cycles -= ((mod == 3) ? 7 : 10); + break; + case 0x28: /*JMP far*/ + oxpc = pc; + new_pc = readmemw(easeg, eaaddr); + new_cs = readmemw(easeg, eaaddr + 2); if (abrt) return 0; + pc = new_pc; + loadcsjmp(new_cs, oxpc); if (abrt) return 0; + cycles -= is486 ? 13 : 12; + break; + case 0x30: /*PUSH w*/ + temp = geteaw(); if (abrt) return 0; + if (ssegs) ss = oldss; + PUSH_W(temp); + cycles -= ((mod == 3) ? 2 : 5); + break; + + default: + fatal("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + return 0; +} +static int opFF_w_a32(uint32_t fetchdat) +{ + uint16_t old_cs, new_cs; + uint32_t old_pc, new_pc; + + uint16_t temp; + + fetch_ea_32(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*INC w*/ + temp = geteaw(); if (abrt) return 0; + seteaw(temp + 1); if (abrt) return 0; + setadd16nc(temp, 1); + cycles -= (mod == 3) ? timing_rr : timing_mm; + break; + case 0x08: /*DEC w*/ + temp = geteaw(); if (abrt) return 0; + seteaw(temp - 1); if (abrt) return 0; + setsub16nc(temp, 1); + cycles -= (mod == 3) ? timing_rr : timing_mm; + break; + case 0x10: /*CALL*/ + new_pc = geteaw(); if (abrt) return 0; + if (ssegs) ss = oldss; + PUSH_W(pc); + pc = new_pc; + if (is486) cycles -= 5; + else cycles -= ((mod == 3) ? 7 : 10); + break; + case 0x18: /*CALL far*/ + new_pc = readmemw(easeg, eaaddr); + new_cs = readmemw(easeg, (eaaddr + 2)); if (abrt) return 0; + + CALL_FAR_w(new_cs, new_pc); + + cycles -= is486 ? 17 : 22; + break; + case 0x20: /*JMP*/ + new_pc = geteaw(); if (abrt) return 0; + pc = new_pc; + if (is486) cycles -= 5; + else cycles -= ((mod == 3) ? 7 : 10); + break; + case 0x28: /*JMP far*/ + oxpc = pc; + new_pc = readmemw(easeg, eaaddr); + new_cs = readmemw(easeg, eaaddr + 2); if (abrt) return 0; + pc = new_pc; + loadcsjmp(new_cs, oxpc); if (abrt) return 0; + cycles -= is486 ? 13 : 12; + break; + case 0x30: /*PUSH w*/ + temp = geteaw(); if (abrt) return 0; + if (ssegs) ss = oldss; + PUSH_W(temp); + cycles -= ((mod == 3) ? 2 : 5); + break; + + default: + fatal("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + return 0; +} + +static int opFF_l_a16(uint32_t fetchdat) +{ + uint16_t old_cs, new_cs; + uint32_t old_pc, new_pc; + + uint32_t temp; + + fetch_ea_16(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*INC l*/ + temp = geteal(); if (abrt) return 0; + seteal(temp + 1); if (abrt) return 0; + setadd32nc(temp, 1); + cycles -= (mod == 3) ? timing_rr : timing_mm; + break; + case 0x08: /*DEC l*/ + temp = geteal(); if (abrt) return 0; + seteal(temp - 1); if (abrt) return 0; + setsub32nc(temp, 1); + cycles -= (mod == 3) ? timing_rr : timing_mm; + break; + case 0x10: /*CALL*/ + new_pc = geteal(); if (abrt) return 0; + if (ssegs) ss = oldss; + PUSH_L(pc); + pc = new_pc; + if (is486) cycles -= 5; + else cycles -= ((mod == 3) ? 7 : 10); + break; + case 0x18: /*CALL far*/ + new_pc = readmeml(easeg, eaaddr); + new_cs = readmemw(easeg, (eaaddr + 4)); if (abrt) return 0; + + CALL_FAR_l(new_cs, new_pc); + + cycles -= is486 ? 17 : 22; + break; + case 0x20: /*JMP*/ + new_pc = geteal(); if (abrt) return 0; + pc = new_pc; + if (is486) cycles -= 5; + else cycles -= ((mod == 3) ? 7 : 10); + break; + case 0x28: /*JMP far*/ + oxpc = pc; + new_pc = readmeml(easeg, eaaddr); + new_cs = readmemw(easeg, eaaddr + 4); if (abrt) return 0; + pc = new_pc; + loadcsjmp(new_cs, oxpc); if (abrt) return 0; + cycles -= is486 ? 13 : 12; + break; + case 0x30: /*PUSH l*/ + temp = geteal(); if (abrt) return 0; + if (ssegs) ss = oldss; + PUSH_L(temp); + cycles -= ((mod == 3) ? 2 : 5); + break; + + default: + fatal("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + return 0; +} +static int opFF_l_a32(uint32_t fetchdat) +{ + uint16_t old_cs, new_cs; + uint32_t old_pc, new_pc; + + uint32_t temp; + + fetch_ea_32(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*INC l*/ + temp = geteal(); if (abrt) return 0; + seteal(temp + 1); if (abrt) return 0; + setadd32nc(temp, 1); + cycles -= (mod == 3) ? timing_rr : timing_mm; + break; + case 0x08: /*DEC l*/ + temp = geteal(); if (abrt) return 0; + seteal(temp - 1); if (abrt) return 0; + setsub32nc(temp, 1); + cycles -= (mod == 3) ? timing_rr : timing_mm; + break; + case 0x10: /*CALL*/ + new_pc = geteal(); if (abrt) return 0; + if (ssegs) ss = oldss; + PUSH_L(pc); if (abrt) return 0; + pc = new_pc; + if (is486) cycles -= 5; + else cycles -= ((mod == 3) ? 7 : 10); + break; + case 0x18: /*CALL far*/ + new_pc = readmeml(easeg, eaaddr); + new_cs = readmemw(easeg, (eaaddr + 4)); if (abrt) return 0; + + CALL_FAR_l(new_cs, new_pc); + + cycles -= is486 ? 17 : 22; + break; + case 0x20: /*JMP*/ + new_pc = geteal(); if (abrt) return 0; + pc = new_pc; + if (is486) cycles -= 5; + else cycles -= ((mod == 3) ? 7 : 10); + break; + case 0x28: /*JMP far*/ + oxpc = pc; + new_pc = readmeml(easeg, eaaddr); + new_cs = readmemw(easeg, eaaddr + 4); if (abrt) return 0; + pc = new_pc; + loadcsjmp(new_cs, oxpc); if (abrt) return 0; + cycles -= is486 ? 13 : 12; + break; + case 0x30: /*PUSH l*/ + temp = geteal(); if (abrt) return 0; + if (ssegs) ss = oldss; + PUSH_L(temp); + cycles -= ((mod == 3) ? 2 : 5); + break; + + default: + fatal("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + return 0; +} diff --git a/src/x86_ops_flag.h b/src/x86_ops_flag.h new file mode 100644 index 0000000..b0a44d9 --- /dev/null +++ b/src/x86_ops_flag.h @@ -0,0 +1,178 @@ +static int opCMC(uint32_t fetchdat) +{ + flags_rebuild(); + flags ^= C_FLAG; + cycles -= 2; + return 0; +} + + +static int opCLC(uint32_t fetchdat) +{ + flags_rebuild(); + flags &= ~C_FLAG; + cycles -= 2; + return 0; +} +static int opCLD(uint32_t fetchdat) +{ + flags &= ~D_FLAG; + cycles -= 2; + return 0; +} +static int opCLI(uint32_t fetchdat) +{ + if (!IOPLp) + { + x86gpf(NULL,0); + } + else + flags &= ~I_FLAG; + + cycles -= 3; + return 0; +} + +static int opSTC(uint32_t fetchdat) +{ + flags_rebuild(); + flags |= C_FLAG; + cycles -= 2; + return 0; +} +static int opSTD(uint32_t fetchdat) +{ + flags |= D_FLAG; + cycles -= 2; + return 0; +} +static int opSTI(uint32_t fetchdat) +{ + if (!IOPLp) + { + x86gpf(NULL,0); + } + else + flags |= I_FLAG; + + cycles -= 2; + return 0; +} + +static int opSAHF(uint32_t fetchdat) +{ + flags_rebuild(); + flags = (flags & 0xff00) | (AH & 0xd5) | 2; + cycles -= 3; + return 0; +} +static int opLAHF(uint32_t fetchdat) +{ + flags_rebuild(); + AH = flags & 0xff; + cycles -= 3; + return 0; +} + +static int opPUSHF(uint32_t fetchdat) +{ + if (ssegs) ss = oldss; + if ((eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL,0); + return 0; + } + flags_rebuild(); + PUSH_W(flags); + cycles -= 4; + return 0; +} +static int opPUSHFD(uint32_t fetchdat) +{ + uint16_t tempw; + if (ssegs) ss=oldss; + if ((eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL, 0); + return 0; + } + if (CPUID) tempw = eflags & 0x24; + else tempw = eflags & 4; + flags_rebuild(); + PUSH_L(flags | (tempw << 16)); + cycles -= 4; + return 0; +} + +static int opPOPF_286(uint32_t fetchdat) +{ + uint16_t tempw; + if (ssegs) ss = oldss; + + if ((eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL, 0); + return 0; + } + + tempw = POP_W(); if (abrt) return 0; + + pclog("POPF_286 %04X:%04X %04X\n", CS, pc, tempw); + if (!(msw & 1)) flags = (flags & 0x7000) | (tempw & 0x0fd5) | 2; + else if (!(CPL)) flags = (tempw & 0x7fd5) | 2; + else if (IOPLp) flags = (flags & 0x3000) | (tempw & 0x4fd5) | 2; + else flags = (flags & 0x3200) | (tempw & 0x4dd5) | 2; + flags_extract(); + + cycles -= 5; + return 0; +} +static int opPOPF(uint32_t fetchdat) +{ + uint16_t tempw; + if (ssegs) ss = oldss; + + if ((eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL, 0); + return 0; + } + + tempw = POP_W(); if (abrt) return 0; + + if (!(CPL) || !(msw & 1)) flags = (tempw & 0xffd5) | 2; + else if (IOPLp) flags = (flags & 0x3000) | (tempw & 0xcfd5) | 2; + else flags = (flags & 0x3200) | (tempw & 0xcdd5) | 2; + flags_extract(); + + cycles -= 5; + return 0; +} +static int opPOPFD(uint32_t fetchdat) +{ + uint32_t templ; + if (ssegs) ss = oldss; + + if ((eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL, 0); + return 0; + } + + templ = POP_L(); if (abrt) return 0; + + if (!(CPL) || !(msw & 1)) flags = (templ & 0xffd5) | 2; + else if (IOPLp) flags = (flags & 0x3000) | (templ & 0xcfd5) | 2; + else flags = (flags & 0x3200) | (templ & 0xcdd5) | 2; + + templ &= is486 ? 0x240000 : 0; + templ |= ((eflags&3) << 16); + if (CPUID) eflags = (templ >> 16) & 0x27; + else if (is486) eflags = (templ >> 16) & 7; + else eflags = (templ >> 16) & 3; + + flags_extract(); + + cycles -= 5; + return 0; +} diff --git a/src/x86_ops_fpu.h b/src/x86_ops_fpu.h new file mode 100644 index 0000000..a5430f8 --- /dev/null +++ b/src/x86_ops_fpu.h @@ -0,0 +1,60 @@ +#define opESCAPE(num) \ + static int opESCAPE_ ## num ##_a16(uint32_t fetchdat) \ + { \ + flags_rebuild(); \ + if ((cr0 & 6) == 4) \ + { \ + x86_int(7); \ + } \ + else \ + { \ + fpucount++; \ + fetch_ea_16(fetchdat); \ + if (hasfpu) \ + { \ + x87_pc_off = oldpc; \ + x87_pc_seg = CS; \ + x87_op_off = eaaddr; \ + x87_op_seg = ea_rseg; \ + x87_ ## num(); \ + } \ + } \ + return 0; \ + } \ + static int opESCAPE_ ## num ## _a32(uint32_t fetchdat) \ + { \ + flags_rebuild(); \ + if ((cr0 & 6) == 4) \ + { \ + x86_int(7); \ + } \ + else \ + { \ + fpucount++; \ + fetch_ea_32(fetchdat); \ + if (hasfpu) \ + { \ + x87_pc_off = oldpc; \ + x87_pc_seg = CS; \ + x87_op_off = eaaddr; \ + x87_op_seg = ea_rseg; \ + x87_ ## num(); \ + } \ + } \ + return 0; \ + } + +opESCAPE(d8); +opESCAPE(d9); +opESCAPE(da); +opESCAPE(db); +opESCAPE(dc); +opESCAPE(dd); +opESCAPE(de); +opESCAPE(df); + +static int opWAIT(uint32_t fetchdat) +{ + cycles -= 4; + return 0; +} diff --git a/src/x86_ops_inc_dec.h b/src/x86_ops_inc_dec.h new file mode 100644 index 0000000..1e8accf --- /dev/null +++ b/src/x86_ops_inc_dec.h @@ -0,0 +1,86 @@ +#define INC_DEC_OP(name, reg, inc, setflags) \ + static int op ## name (uint32_t fetchdat) \ + { \ + setflags(reg, 1); \ + reg += inc; \ + cycles -= timing_rr; \ + return 0; \ + } + +INC_DEC_OP(INC_AX, AX, 1, setadd16nc) +INC_DEC_OP(INC_BX, BX, 1, setadd16nc) +INC_DEC_OP(INC_CX, CX, 1, setadd16nc) +INC_DEC_OP(INC_DX, DX, 1, setadd16nc) +INC_DEC_OP(INC_SI, SI, 1, setadd16nc) +INC_DEC_OP(INC_DI, DI, 1, setadd16nc) +INC_DEC_OP(INC_BP, BP, 1, setadd16nc) +INC_DEC_OP(INC_SP, SP, 1, setadd16nc) + +INC_DEC_OP(INC_EAX, EAX, 1, setadd32nc) +INC_DEC_OP(INC_EBX, EBX, 1, setadd32nc) +INC_DEC_OP(INC_ECX, ECX, 1, setadd32nc) +INC_DEC_OP(INC_EDX, EDX, 1, setadd32nc) +INC_DEC_OP(INC_ESI, ESI, 1, setadd32nc) +INC_DEC_OP(INC_EDI, EDI, 1, setadd32nc) +INC_DEC_OP(INC_EBP, EBP, 1, setadd32nc) +INC_DEC_OP(INC_ESP, ESP, 1, setadd32nc) + +INC_DEC_OP(DEC_AX, AX, -1, setsub16nc) +INC_DEC_OP(DEC_BX, BX, -1, setsub16nc) +INC_DEC_OP(DEC_CX, CX, -1, setsub16nc) +INC_DEC_OP(DEC_DX, DX, -1, setsub16nc) +INC_DEC_OP(DEC_SI, SI, -1, setsub16nc) +INC_DEC_OP(DEC_DI, DI, -1, setsub16nc) +INC_DEC_OP(DEC_BP, BP, -1, setsub16nc) +INC_DEC_OP(DEC_SP, SP, -1, setsub16nc) + +INC_DEC_OP(DEC_EAX, EAX, -1, setsub32nc) +INC_DEC_OP(DEC_EBX, EBX, -1, setsub32nc) +INC_DEC_OP(DEC_ECX, ECX, -1, setsub32nc) +INC_DEC_OP(DEC_EDX, EDX, -1, setsub32nc) +INC_DEC_OP(DEC_ESI, ESI, -1, setsub32nc) +INC_DEC_OP(DEC_EDI, EDI, -1, setsub32nc) +INC_DEC_OP(DEC_EBP, EBP, -1, setsub32nc) +INC_DEC_OP(DEC_ESP, ESP, -1, setsub32nc) + + +static int opINCDEC_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + temp=geteab(); if (abrt) return 0; + + if (rmdat&0x38) + { + seteab(temp - 1); if (abrt) return 0; + setsub8nc(temp, 1); + } + else + { + seteab(temp + 1); if (abrt) return 0; + setadd8nc(temp, 1); + } + cycles -= (mod == 3) ? timing_rr : timing_mm; + return 0; +} +static int opINCDEC_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + temp=geteab(); if (abrt) return 0; + + if (rmdat&0x38) + { + seteab(temp - 1); if (abrt) return 0; + setsub8nc(temp, 1); + } + else + { + seteab(temp + 1); if (abrt) return 0; + setadd8nc(temp, 1); + } + cycles -= (mod == 3) ? timing_rr : timing_mm; + return 0; +} diff --git a/src/x86_ops_int.h b/src/x86_ops_int.h new file mode 100644 index 0000000..11507ec --- /dev/null +++ b/src/x86_ops_int.h @@ -0,0 +1,46 @@ +static int opINT3(uint32_t fetchdat) +{ + oldpc = pc; + //fatal("INT3\n"); + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 0; + } + x86_int_sw(3); + cycles -= (is486) ? 44 : 59; + return 0; +} + +static int opINT(uint32_t fetchdat) +{ + uint8_t temp; + + /*if (msw&1) pclog("INT %i %i %i\n",cr0&1,eflags&VM_FLAG,IOPL);*/ + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 0; + } + temp = getbytef(); + if (temp == 0x10 && AH == 0xe) pclog("INT %02X : %04X %04X %04X %04X %c %04X:%04X\n", temp, AX, BX, CX, DX, (AL < 32) ? ' ' : AL, CS, pc); + x86_int_sw(temp); + return 0; +} + +static int opINTO(uint32_t fetchdat) +{ + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 0; + } + if (VF_SET()) + { + oldpc = pc; + x86_int_sw(4); + } + cycles -= 3; + return 0; +} + diff --git a/src/x86_ops_io.h b/src/x86_ops_io.h new file mode 100644 index 0000000..f7b1569 --- /dev/null +++ b/src/x86_ops_io.h @@ -0,0 +1,110 @@ +int opIN_AL_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + AL = inb(port); + cycles -= 12; + return 0; +} +int opIN_AX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + AX = inw(port); + cycles -= 12; + return 0; +} +int opIN_EAX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + check_io_perm(port + 2); + check_io_perm(port + 3); + EAX = inl(port); + cycles -= 12; + return 0; +} + +int opOUT_AL_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + outb(port, AL); + cycles -= 10; + return 0; +} +int opOUT_AX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + outw(port, AX); + cycles -= 10; + return 0; +} +int opOUT_EAX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + check_io_perm(port + 2); + check_io_perm(port + 3); + outl(port, EAX); + cycles -= 10; + return 0; +} + +int opIN_AL_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + AL = inb(DX); + cycles -= 12; + return 0; +} +int opIN_AX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + AX = inw(DX); + cycles -= 12; + return 0; +} +int opIN_EAX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + EAX = inl(DX); + cycles -= 12; + return 0; +} + +int opOUT_AL_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + outb(DX, AL); + cycles -= 11; + return 0; +} +int opOUT_AX_DX(uint32_t fetchdat) +{ + //pclog("OUT_AX_DX %04X %04X\n", DX, AX); + check_io_perm(DX); + check_io_perm(DX + 1); + outw(DX, AX); + cycles -= 11; + return 0; +} +int opOUT_EAX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + outl(DX, EAX); + cycles -= 11; + return 0; +} diff --git a/src/x86_ops_jump.h b/src/x86_ops_jump.h new file mode 100644 index 0000000..7e1e882 --- /dev/null +++ b/src/x86_ops_jump.h @@ -0,0 +1,268 @@ +#define cond_O ( VF_SET()) +#define cond_NO (!VF_SET()) +#define cond_B ( CF_SET()) +#define cond_NB (!CF_SET()) +#define cond_E ( ZF_SET()) +#define cond_NE (!ZF_SET()) +#define cond_BE ( CF_SET() || ZF_SET()) +#define cond_NBE (!CF_SET() && !ZF_SET()) +#define cond_S ( NF_SET()) +#define cond_NS (!NF_SET()) +#define cond_P ( PF_SET()) +#define cond_NP (!PF_SET()) +#define cond_L (((NF_SET()) ? 1 : 0) != ((VF_SET()) ? 1 : 0)) +#define cond_NL (((NF_SET()) ? 1 : 0) == ((VF_SET()) ? 1 : 0)) +#define cond_LE (((NF_SET()) ? 1 : 0) != ((VF_SET()) ? 1 : 0) || (ZF_SET())) +#define cond_NLE (((NF_SET()) ? 1 : 0) == ((VF_SET()) ? 1 : 0) && (!ZF_SET())) + +#define opJ(condition) \ + static int opJ ## condition(uint32_t fetchdat) \ + { \ + int8_t offset = (int8_t)getbytef(); \ + if (cond_ ## condition) \ + { \ + pc += offset; \ + cycles -= timing_bt; \ + } \ + cycles -= timing_bnt; \ + return 0; \ + } \ + \ + static int opJ ## condition ## _w(uint32_t fetchdat) \ + { \ + int16_t offset = (int16_t)getwordf(); \ + if (cond_ ## condition) \ + { \ + pc += offset; \ + cycles -= timing_bt; \ + } \ + cycles -= timing_bnt; \ + return 0; \ + } \ + \ + static int opJ ## condition ## _l(uint32_t fetchdat) \ + { \ + uint32_t offset = getlong(); \ + if (cond_ ## condition) \ + { \ + pc += offset; \ + cycles -= timing_bt; \ + } \ + cycles -= timing_bnt; \ + return 0; \ + } \ + +opJ(O) +opJ(NO) +opJ(B) +opJ(NB) +opJ(E) +opJ(NE) +opJ(BE) +opJ(NBE) +opJ(S) +opJ(NS) +opJ(P) +opJ(NP) +opJ(L) +opJ(NL) +opJ(LE) +opJ(NLE) + + + +static int opLOOPNE_w(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CX--; + if (CX && !ZF_SET()) + pc += offset; + cycles -= (is486) ? 7 : 11; + return 0; +} +static int opLOOPNE_l(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + ECX--; + if (ECX && !ZF_SET()) + pc += offset; + cycles -= (is486) ? 7 : 11; + return 0; +} + +static int opLOOPE_w(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CX--; + if (CX && ZF_SET()) + pc += offset; + cycles -= (is486) ? 7 : 11; + return 0; +} +static int opLOOPE_l(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + ECX--; + if (ECX && ZF_SET()) + pc += offset; + cycles -= (is486) ? 7 : 11; + return 0; +} + +static int opLOOP_w(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CX--; + if (CX) + pc += offset; + cycles -= (is486) ? 7 : 11; + return 0; +} +static int opLOOP_l(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + ECX--; + if (ECX) + pc += offset; + cycles -= (is486) ? 7 : 11; + return 0; +} + +static int opJCXZ(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + if (!CX) + { + pc += offset; + cycles -= 4; + } + cycles -= 5; + return 0; +} +static int opJECXZ(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + if (!ECX) + { + pc += offset; + cycles -= 4; + } + cycles -= 5; + return 0; +} + + +static int opJMP_r8(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + pc += offset; + cycles -= (is486) ? 3 : 7; + return 0; +} +static int opJMP_r16(uint32_t fetchdat) +{ + int16_t offset = (int16_t)getwordf(); + pc += offset; + cycles -= (is486) ? 3 : 7; + return 0; +} +static int opJMP_r32(uint32_t fetchdat) +{ + int32_t offset = (int32_t)getlong(); if (abrt) return 0; + pc += offset; + cycles -= (is486) ? 3 : 7; + return 0; +} + +static int opJMP_far_a16(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + uint16_t seg = getword(); if (abrt) return 0; + uint32_t oxpc = pc; + pc = addr; + loadcsjmp(seg, oxpc); + cycles -= (is486) ? 17 : 12; + return 0; +} +static int opJMP_far_a32(uint32_t fetchdat) +{ + uint32_t addr = getlong(); + uint16_t seg = getword(); if (abrt) return 0; + uint32_t oxpc = pc; + pc = addr; + loadcsjmp(seg, oxpc); + cycles -= (is486) ? 17 : 12; + return 0; +} + +int opCALL_r16(uint32_t fetchdat) +{ + int16_t addr = (int16_t)getwordf(); + if (ssegs) ss=oldss; + PUSH_W(pc); + pc += addr; + cycles -= (is486) ? 3 : 7; + return 0; +} +int opCALL_r32(uint32_t fetchdat) +{ + int32_t addr = getlong(); if (abrt) return 0; + if (ssegs) ss=oldss; + PUSH_L(pc); + pc += addr; + cycles -= (is486) ? 3 : 7; + return 0; +} + +int opRET_w(uint32_t fetchdat) +{ + uint16_t ret; + + if (ssegs) ss=oldss; + ret = POP_W(); if (abrt) return 0; + pc = ret; + + cycles -= (is486) ? 5 : 10; + return 0; +} +int opRET_l(uint32_t fetchdat) +{ + uint32_t ret; + + if (ssegs) ss=oldss; + ret = POP_L(); if (abrt) return 0; + pc = ret; + + cycles -= (is486) ? 5 : 10; + return 0; +} + +int opRET_w_imm(uint32_t fetchdat) +{ + uint16_t offset = getwordf(); + uint16_t ret; + + if (ssegs) ss=oldss; + ret = POP_W(); if (abrt) return 0; + if (stack32) ESP += offset; + else SP += offset; + pc = ret; + + cycles -= (is486) ? 5 : 10; + return 0; +} +int opRET_l_imm(uint32_t fetchdat) +{ + uint16_t offset = getwordf(); + uint32_t ret; + + if (ssegs) ss=oldss; + ret = POP_L(); if (abrt) return 0; + if (stack32) ESP += offset; + else SP += offset; + pc = ret; + + cycles -= (is486) ? 5 : 10; + return 0; +} + diff --git a/src/x86_ops_misc.h b/src/x86_ops_misc.h new file mode 100644 index 0000000..d9f6fb2 --- /dev/null +++ b/src/x86_ops_misc.h @@ -0,0 +1,678 @@ +static int opCBW(uint32_t fetchdat) +{ + AH = (AL & 0x80) ? 0xff : 0; + cycles -= 3; + return 0; +} +static int opCWDE(uint32_t fetchdat) +{ + EAX = (AX & 0x8000) ? (0xffff0000 | AX) : AX; + cycles -= 3; + return 0; +} +static int opCWD(uint32_t fetchdat) +{ + DX = (AX & 0x8000) ? 0xFFFF : 0; + cycles -= 2; + return 0; +} +static int opCDQ(uint32_t fetchdat) +{ + EDX = (EAX & 0x80000000) ? 0xffffffff : 0; + cycles -= 2; + return 0; +} + +static int opNOP(uint32_t fetchdat) +{ + cycles -= (is486) ? 1 : 3; + return 0; +} + +static int opSETALC(uint32_t fetchdat) +{ + AL = (CF_SET()) ? 0xff : 0; + cycles -= timing_rr; + return 0; +} + + + +static int opF6_a16(uint32_t fetchdat) +{ + int tempws, tempws2; + uint16_t tempw, src16; + uint8_t src, dst; + int8_t temps; + + fetch_ea_16(fetchdat); + dst = geteab(); if (abrt) return 0; + switch (rmdat & 0x38) + { + case 0x00: /*TEST b,#8*/ + src = readmemb(cs, pc); pc++; if (abrt) return 0; + setznp8(src & dst); + if (is486) cycles -= ((mod == 3) ? 1 : 2); + else cycles -= ((mod == 3) ? 2 : 5); + break; + case 0x10: /*NOT b*/ + seteab(~dst); + cycles -= (mod == 3) ? timing_rr : timing_mm; + break; + case 0x18: /*NEG b*/ + setsub8(0, dst); + seteab(0 - dst); + cycles -= (mod == 3) ? timing_rr : timing_mm; + break; + case 0x20: /*MUL AL,b*/ + AX = AL * dst; + flags_rebuild(); + if (AH) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + cycles -= 13; + break; + case 0x28: /*IMUL AL,b*/ + tempws = (int)((int8_t)AL) * (int)((int8_t)dst); + AX = tempws & 0xffff; + flags_rebuild(); + if (AH && AH != 0xff) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + cycles -= 14; + break; + case 0x30: /*DIV AL,b*/ + src16 = AX; + if (dst) tempw = src16 / dst; + if (dst && !(tempw & 0xff00)) + { + AH = src16 % dst; + AL = (src16 / dst) &0xff; + if (!cpu_iscyrix) + { + flags_rebuild(); + flags |= 0x8D5; /*Not a Cyrix*/ + } + } + else + { + x86_int(0); + } + cycles -= is486 ? 16 : 14; + break; + case 0x38: /*IDIV AL,b*/ + tempws = (int)(int16_t)AX; + if (dst != 0) tempws2 = tempws / (int)((int8_t)dst); + temps = tempws2 & 0xff; + if (dst && ((int)temps == tempws2)) + { + AH = (tempws % (int)((int8_t)dst)) & 0xff; + AL = tempws2 & 0xff; + if (!cpu_iscyrix) + { + flags_rebuild(); + flags|=0x8D5; /*Not a Cyrix*/ + } + } + else + { +// pclog("IDIVb exception - %X / %08X = %X\n", tempws, dst, tempws2); + x86_int(0); + } + cycles -= 19; + break; + + default: + pclog("Bad F6 opcode %02X\n", rmdat & 0x38); + x86illegal(); + } + return 0; +} +static int opF6_a32(uint32_t fetchdat) +{ + int tempws, tempws2; + uint16_t tempw, src16; + uint8_t src, dst; + int8_t temps; + + fetch_ea_32(fetchdat); + dst = geteab(); if (abrt) return 0; + switch (rmdat & 0x38) + { + case 0x00: /*TEST b,#8*/ + src = readmemb(cs, pc); pc++; if (abrt) return 0; + setznp8(src & dst); + if (is486) cycles -= ((mod == 3) ? 1 : 2); + else cycles -= ((mod == 3) ? 2 : 5); + break; + case 0x10: /*NOT b*/ + seteab(~dst); + cycles -= (mod == 3) ? timing_rr : timing_mm; + break; + case 0x18: /*NEG b*/ + setsub8(0, dst); + seteab(0 - dst); + cycles -= (mod == 3) ? timing_rr : timing_mm; + break; + case 0x20: /*MUL AL,b*/ + AX = AL * dst; + flags_rebuild(); + if (AH) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + cycles -= 13; + break; + case 0x28: /*IMUL AL,b*/ + tempws = (int)((int8_t)AL) * (int)((int8_t)dst); + AX = tempws & 0xffff; + flags_rebuild(); + if (AH && AH != 0xff) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + cycles -= 14; + break; + case 0x30: /*DIV AL,b*/ + src16 = AX; + if (dst) tempw = src16 / dst; + if (dst && !(tempw & 0xff00)) + { + AH = src16 % dst; + AL = (src16 / dst) &0xff; + if (!cpu_iscyrix) + { + flags_rebuild(); + flags |= 0x8D5; /*Not a Cyrix*/ + } + } + else + { + x86_int(0); + } + cycles -= is486 ? 16 : 14; + break; + case 0x38: /*IDIV AL,b*/ + tempws = (int)(int16_t)AX; + if (dst != 0) tempws2 = tempws / (int)((int8_t)dst); + temps = tempws2 & 0xff; + if (dst && ((int)temps == tempws2)) + { + AH = (tempws % (int)((int8_t)dst)) & 0xff; + AL = tempws2 & 0xff; + if (!cpu_iscyrix) + { + flags_rebuild(); + flags|=0x8D5; /*Not a Cyrix*/ + } + } + else + { +// pclog("IDIVb exception - %X / %08X = %X\n", tempws, dst, tempws2); + x86_int(0); + } + cycles -= 19; + break; + + default: + pclog("Bad F6 opcode %02X\n", rmdat & 0x38); + x86illegal(); + } + return 0; +} + + + +static int opF7_w_a16(uint32_t fetchdat) +{ + uint32_t templ, templ2; + int tempws, tempws2; + int16_t temps16; + uint16_t src, dst; + + fetch_ea_16(fetchdat); + dst = geteaw(); if (abrt) return 0; + switch (rmdat & 0x38) + { + case 0x00: /*TEST w*/ + src = getword(); if (abrt) return 0; + setznp16(src & dst); + if (is486) cycles -= ((mod == 3) ? 1 : 2); + else cycles -= ((mod == 3) ? 2 : 5); + break; + case 0x10: /*NOT w*/ + seteaw(~dst); + cycles -= (mod == 3) ? timing_rr : timing_mm; + break; + case 0x18: /*NEG w*/ + setsub16(0, dst); + seteaw(0 - dst); + cycles -= (mod == 3) ? timing_rr : timing_mm; + break; + case 0x20: /*MUL AX,w*/ + templ = AX * dst; + AX = templ & 0xFFFF; + DX = templ >> 16; + flags_rebuild(); + if (DX) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + cycles -= 21; + break; + case 0x28: /*IMUL AX,w*/ + templ = (int)((int16_t)AX) * (int)((int16_t)dst); + AX = templ & 0xFFFF; + DX = templ >> 16; + flags_rebuild(); + if (DX && DX != 0xFFFF) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + cycles -= 22; + break; + case 0x30: /*DIV AX,w*/ + templ = (DX << 16) | AX; + if (dst) templ2 = templ / dst; + if (dst && !(templ2 & 0xffff0000)) + { + DX = templ % dst; + AX = (templ / dst) & 0xffff; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { +// fatal("DIVw BY 0 %04X:%04X %i\n",cs>>4,pc,ins); + x86_int(0); + } + cycles -= is486 ? 24 : 22; + break; + case 0x38: /*IDIV AX,w*/ + tempws = (int)((DX << 16)|AX); + if (dst) tempws2 = tempws / (int)((int16_t)dst); + temps16 = tempws2 & 0xffff; + if ((dst != 0) && ((int)temps16 == tempws2)) + { + DX = tempws % (int)((int16_t)dst); + AX = tempws2 & 0xffff; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { +// pclog("IDIVw exception - %X / %08X = %X\n",tempws, dst, tempws2); + x86_int(0); + } + cycles -= 27; + break; + + default: + pclog("Bad F7 opcode %02X\n", rmdat & 0x38); + x86illegal(); + } + return 0; +} +static int opF7_w_a32(uint32_t fetchdat) +{ + uint32_t templ, templ2; + int tempws, tempws2; + int16_t temps16; + uint16_t src, dst; + + fetch_ea_32(fetchdat); + dst = geteaw(); if (abrt) return 0; + switch (rmdat & 0x38) + { + case 0x00: /*TEST w*/ + src = getword(); if (abrt) return 0; + setznp16(src & dst); + if (is486) cycles -= ((mod == 3) ? 1 : 2); + else cycles -= ((mod == 3) ? 2 : 5); + break; + case 0x10: /*NOT w*/ + seteaw(~dst); + cycles -= (mod == 3) ? timing_rr : timing_mm; + break; + case 0x18: /*NEG w*/ + setsub16(0, dst); + seteaw(0 - dst); + cycles -= (mod == 3) ? timing_rr : timing_mm; + break; + case 0x20: /*MUL AX,w*/ + templ = AX * dst; + AX = templ & 0xFFFF; + DX = templ >> 16; + flags_rebuild(); + if (DX) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + cycles -= 21; + break; + case 0x28: /*IMUL AX,w*/ + templ = (int)((int16_t)AX) * (int)((int16_t)dst); + AX = templ & 0xFFFF; + DX = templ >> 16; + flags_rebuild(); + if (DX && DX != 0xFFFF) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + cycles -= 22; + break; + case 0x30: /*DIV AX,w*/ + templ = (DX << 16) | AX; + if (dst) templ2 = templ / dst; + if (dst && !(templ2 & 0xffff0000)) + { + DX = templ % dst; + AX = (templ / dst) & 0xffff; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { +// fatal("DIVw BY 0 %04X:%04X %i\n",cs>>4,pc,ins); + x86_int(0); + } + cycles -= is486 ? 24 : 22; + break; + case 0x38: /*IDIV AX,w*/ + tempws = (int)((DX << 16)|AX); + if (dst) tempws2 = tempws / (int)((int16_t)dst); + temps16 = tempws2 & 0xffff; + if ((dst != 0) && ((int)temps16 == tempws2)) + { + DX = tempws % (int)((int16_t)dst); + AX = tempws2 & 0xffff; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { +// pclog("IDIVw exception - %X / %08X = %X\n", tempws, dst, tempws2); + x86_int(0); + } + cycles -= 27; + break; + + default: + pclog("Bad F7 opcode %02X\n", rmdat & 0x38); + x86illegal(); + } + return 0; +} + +static int opF7_l_a16(uint32_t fetchdat) +{ + uint64_t temp64; + uint32_t src, dst; + + fetch_ea_16(fetchdat); + dst = geteal(); if (abrt) return 0; + + switch (rmdat & 0x38) + { + case 0x00: /*TEST l*/ + src = getlong(); if (abrt) return 0; + setznp32(src & dst); + if (is486) cycles -= ((mod == 3) ? 1 : 2); + else cycles -= ((mod == 3) ? 2 : 5); + break; + case 0x10: /*NOT l*/ + seteal(~dst); + cycles -= (mod == 3) ? timing_rr : timing_mml; + break; + case 0x18: /*NEG l*/ + setsub32(0, dst); + seteal(0 - dst); + cycles -= (mod == 3) ? timing_rr : timing_mml; + break; + case 0x20: /*MUL EAX,l*/ + temp64 = (uint64_t)EAX * (uint64_t)dst; + EAX = temp64 & 0xffffffff; + EDX = temp64 >> 32; + flags_rebuild(); + if (EDX) flags |= (C_FLAG|V_FLAG); + else flags &= ~(C_FLAG|V_FLAG); + cycles -= 21; + break; + case 0x28: /*IMUL EAX,l*/ + temp64 = (int64_t)(int32_t)EAX * (int64_t)(int32_t)dst; + EAX = temp64 & 0xffffffff; + EDX = temp64 >> 32; + flags_rebuild(); + if (EDX && EDX != 0xffffffff) flags |= (C_FLAG|V_FLAG); + else flags &= ~(C_FLAG|V_FLAG); + cycles -= 38; + break; + case 0x30: /*DIV EAX,l*/ + divl(dst); + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + cycles -= (is486) ? 40 : 38; + break; + case 0x38: /*IDIV EAX,l*/ + idivl((int32_t)dst); + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + cycles -= 43; + break; + + default: + pclog("Bad F7 opcode %02X\n", rmdat & 0x38); + x86illegal(); + } + return 0; +} +static int opF7_l_a32(uint32_t fetchdat) +{ + uint64_t temp64; + uint32_t src, dst; + + fetch_ea_32(fetchdat); + dst = geteal(); if (abrt) return 0; + + switch (rmdat & 0x38) + { + case 0x00: /*TEST l*/ + src = getlong(); if (abrt) return 0; + setznp32(src & dst); + if (is486) cycles -= ((mod == 3) ? 1 : 2); + else cycles -= ((mod == 3) ? 2 : 5); + break; + case 0x10: /*NOT l*/ + seteal(~dst); + cycles -= (mod == 3) ? timing_rr : timing_mml; + break; + case 0x18: /*NEG l*/ + setsub32(0, dst); + seteal(0 - dst); + cycles -= (mod == 3) ? timing_rr : timing_mml; + break; + case 0x20: /*MUL EAX,l*/ + temp64 = (uint64_t)EAX * (uint64_t)dst; + EAX = temp64 & 0xffffffff; + EDX = temp64 >> 32; + flags_rebuild(); + if (EDX) flags |= (C_FLAG|V_FLAG); + else flags &= ~(C_FLAG|V_FLAG); + cycles -= 21; + break; + case 0x28: /*IMUL EAX,l*/ + temp64 = (int64_t)(int32_t)EAX * (int64_t)(int32_t)dst; + EAX = temp64 & 0xffffffff; + EDX = temp64 >> 32; + flags_rebuild(); + if (EDX && EDX != 0xffffffff) flags |= (C_FLAG|V_FLAG); + else flags &= ~(C_FLAG|V_FLAG); + cycles -= 38; + break; + case 0x30: /*DIV EAX,l*/ + divl(dst); + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + cycles -= (is486) ? 40 : 38; + break; + case 0x38: /*IDIV EAX,l*/ + idivl((int32_t)dst); + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + cycles -= 43; + break; + + default: + pclog("Bad F7 opcode %02X\n", rmdat & 0x38); + x86illegal(); + } + return 0; +} + + +static int opHLT(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL,0); + return 0; + } + if (!((flags&I_FLAG) && pic_intpending && !ssegs)) + { + cycles -= 100; + pc--; + } + else + cycles -= 5; + return 0; +} + + +static int opLOCK(uint32_t fetchdat) +{ + cycles -= 4; + return 0; +} + + + +static int opBOUND_w_a16(uint32_t fetchdat) +{ + int16_t low, high; + + fetch_ea_16(fetchdat); + low = geteaw(); + high = readmemw(easeg, eaaddr + 2); if (abrt) return 0; + + if (((int16_t)regs[reg].w < low) || ((int16_t)regs[reg].w > high)) + { + x86_int(5); + } + + cycles -= is486 ? 7 : 10; + return 0; +} +static int opBOUND_w_a32(uint32_t fetchdat) +{ + int16_t low, high; + + fetch_ea_32(fetchdat); + low = geteaw(); + high = readmemw(easeg, eaaddr + 2); if (abrt) return 0; + + if (((int16_t)regs[reg].w < low) || ((int16_t)regs[reg].w > high)) + { + x86_int(5); + } + + cycles -= is486 ? 7 : 10; + return 0; +} + +static int opBOUND_l_a16(uint32_t fetchdat) +{ + int32_t low, high; + + fetch_ea_16(fetchdat); + low = geteal(); + high = readmeml(easeg, eaaddr + 4); if (abrt) return 0; + + if (((int32_t)regs[reg].l < low) || ((int32_t)regs[reg].l > high)) + { + x86_int(5); + } + + cycles -= is486 ? 7 : 10; + return 0; +} +static int opBOUND_l_a32(uint32_t fetchdat) +{ + int32_t low, high; + + fetch_ea_32(fetchdat); + low = geteal(); + high = readmeml(easeg, eaaddr + 4); if (abrt) return 0; + + if (((int32_t)regs[reg].l < low) || ((int32_t)regs[reg].l > high)) + { + x86_int(5); + } + + cycles -= is486 ? 7 : 10; + return 0; +} + + +static int opCLTS(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't CLTS\n"); + x86gpf(NULL,0); + return 0; + } + cr0 &= ~8; + cycles -= 5; + return 0; +} + +static int opINVD(uint32_t fetchdat) +{ + if (!is486) + { + x86illegal(); + return 0; + } + cycles -= 1000; + return 0; +} +static int opWBINVD(uint32_t fetchdat) +{ + if (!is486) + { + x86illegal(); + return 0; + } + cycles -= 10000; + return 0; +} + + + +static int opLOADALL(uint32_t fetchdat) +{ + flags = (readmemw(0, 0x818) & 0xffd5) | 2; + flags_extract(); + pc = readmemw(0, 0x81A); + DS = readmemw(0, 0x81E); + SS = readmemw(0, 0x820); + CS = readmemw(0, 0x822); + ES = readmemw(0, 0x824); + DI = readmemw(0, 0x826); + SI = readmemw(0, 0x828); + BP = readmemw(0, 0x82A); + SP = readmemw(0, 0x82C); + BX = readmemw(0, 0x82E); + DX = readmemw(0, 0x830); + CX = readmemw(0, 0x832); + AX = readmemw(0, 0x834); + es = readmemw(0, 0x836) | (readmemb(0, 0x838) << 16); + cs = readmemw(0, 0x83C) | (readmemb(0, 0x83E) << 16); + ss = readmemw(0, 0x842) | (readmemb(0, 0x844) << 16); + ds = readmemw(0, 0x848) | (readmemb(0, 0x84A) << 16); + cycles-=195; + return 0; +} + +static int opCPUID(uint32_t fetchdat) +{ + if (CPUID) + { + cpu_CPUID(); + cycles -= 9; + return 0; + } + pc = oldpc; + x86illegal(); + return 0; +} + + diff --git a/src/x86_ops_mov.h b/src/x86_ops_mov.h new file mode 100644 index 0000000..ce00745 --- /dev/null +++ b/src/x86_ops_mov.h @@ -0,0 +1,559 @@ +static int opMOV_AL_imm(uint32_t fetchdat) +{ + AL = getbytef(); + cycles -= timing_rr; + return 0; +} +static int opMOV_AH_imm(uint32_t fetchdat) +{ + AH = getbytef(); + cycles -= timing_rr; + return 0; +} +static int opMOV_BL_imm(uint32_t fetchdat) +{ + BL = getbytef(); + cycles -= timing_rr; + return 0; +} +static int opMOV_BH_imm(uint32_t fetchdat) +{ + BH = getbytef(); + cycles -= timing_rr; + return 0; +} +static int opMOV_CL_imm(uint32_t fetchdat) +{ + CL = getbytef(); + cycles -= timing_rr; + return 0; +} +static int opMOV_CH_imm(uint32_t fetchdat) +{ + CH = getbytef(); + cycles -= timing_rr; + return 0; +} +static int opMOV_DL_imm(uint32_t fetchdat) +{ + DL = getbytef(); + cycles -= timing_rr; + return 0; +} +static int opMOV_DH_imm(uint32_t fetchdat) +{ + DH = getbytef(); + cycles -= timing_rr; + return 0; +} + +static int opMOV_AX_imm(uint32_t fetchdat) +{ + AX = getwordf(); + cycles -= timing_rr; + return 0; +} +static int opMOV_BX_imm(uint32_t fetchdat) +{ + BX = getwordf(); + cycles -= timing_rr; + return 0; +} +static int opMOV_CX_imm(uint32_t fetchdat) +{ + CX = getwordf(); + cycles -= timing_rr; + return 0; +} +static int opMOV_DX_imm(uint32_t fetchdat) +{ + DX = getwordf(); + cycles -= timing_rr; + return 0; +} +static int opMOV_SI_imm(uint32_t fetchdat) +{ + SI = getwordf(); + cycles -= timing_rr; + return 0; +} +static int opMOV_DI_imm(uint32_t fetchdat) +{ + DI = getwordf(); + cycles -= timing_rr; + return 0; +} +static int opMOV_BP_imm(uint32_t fetchdat) +{ + BP = getwordf(); + cycles -= timing_rr; + return 0; +} +static int opMOV_SP_imm(uint32_t fetchdat) +{ + SP = getwordf(); + cycles -= timing_rr; + return 0; +} + +static int opMOV_EAX_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (abrt) return 0; + EAX = templ; + cycles -= timing_rr; + return 0; +} +static int opMOV_EBX_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (abrt) return 0; + EBX = templ; + cycles -= timing_rr; + return 0; +} +static int opMOV_ECX_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (abrt) return 0; + ECX = templ; + cycles -= timing_rr; + return 0; +} +static int opMOV_EDX_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (abrt) return 0; + EDX = templ; + cycles -= timing_rr; + return 0; +} +static int opMOV_ESI_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (abrt) return 0; + ESI = templ; + cycles -= timing_rr; + return 0; +} +static int opMOV_EDI_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (abrt) return 0; + EDI = templ; + cycles -= timing_rr; + return 0; +} +static int opMOV_EBP_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (abrt) return 0; + EBP = templ; + cycles -= timing_rr; + return 0; +} +static int opMOV_ESP_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (abrt) return 0; + ESP = templ; + cycles -= timing_rr; + return 0; +} + +static int opMOV_b_imm_a16(uint32_t fetchdat) +{ + uint8_t temp; + fetch_ea_16(fetchdat); + temp = readmemb(cs,pc); pc++; if (abrt) return 0; + seteab(temp); + cycles -= timing_rr; + return 0; +} +static int opMOV_b_imm_a32(uint32_t fetchdat) +{ + uint8_t temp; + fetch_ea_32(fetchdat); + temp = getbyte(); if (abrt) return 0; + seteab(temp); + cycles -= timing_rr; + return 0; +} + +static int opMOV_w_imm_a16(uint32_t fetchdat) +{ + uint16_t temp; + fetch_ea_16(fetchdat); + temp = getword(); if (abrt) return 0; + seteaw(temp); + cycles -= timing_rr; + return 0; +} +static int opMOV_w_imm_a32(uint32_t fetchdat) +{ + uint16_t temp; + fetch_ea_32(fetchdat); + temp = getword(); if (abrt) return 0; + seteaw(temp); + cycles -= timing_rr; + return 0; +} +static int opMOV_l_imm_a16(uint32_t fetchdat) +{ + uint32_t temp; + fetch_ea_16(fetchdat); + temp = getlong(); if (abrt) return 0; + seteal(temp); + cycles -= timing_rr; + return 0; +} +static int opMOV_l_imm_a32(uint32_t fetchdat) +{ + uint32_t temp; + fetch_ea_32(fetchdat); + temp = getlong(); if (abrt) return 0; + seteal(temp); + cycles -= timing_rr; + return 0; +} + + +static int opMOV_AL_a16(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + uint8_t temp = readmemb(ds, addr); if (abrt) return 0; + AL = temp; + cycles -= (is486) ? 1 : 4; + return 0; +} +static int opMOV_AL_a32(uint32_t fetchdat) +{ + uint32_t addr = getlong(); + uint8_t temp = readmemb(ds, addr); if (abrt) return 0; + AL = temp; + cycles -= (is486) ? 1 : 4; + return 0; +} +static int opMOV_AX_a16(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + uint16_t temp = readmemw(ds, addr); if (abrt) return 0; + AX = temp; + cycles -= (is486) ? 1 : 4; + return 0; +} +static int opMOV_AX_a32(uint32_t fetchdat) +{ + uint32_t addr = getlong(); + uint16_t temp = readmemw(ds, addr); if (abrt) return 0; + AX = temp; + cycles -= (is486) ? 1 : 4; + return 0; +} +static int opMOV_EAX_a16(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); if (abrt) return 0; + uint32_t temp = readmeml(ds, addr); if (abrt) return 0; + EAX = temp; + cycles -= (is486) ? 1 : 4; + return 0; +} +static int opMOV_EAX_a32(uint32_t fetchdat) +{ + uint32_t addr = getlong(); if (abrt) return 0; + uint32_t temp = readmeml(ds, addr); if (abrt) return 0; + EAX = temp; + cycles -= (is486) ? 1 : 4; + return 0; +} + +static int opMOV_a16_AL(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + writememb(ds, addr, AL); + cycles -= (is486) ? 1 : 2; + return 0; +} +static int opMOV_a32_AL(uint32_t fetchdat) +{ + uint32_t addr = getlong(); + writememb(ds, addr, AL); + cycles -= (is486) ? 1 : 2; + return 0; +} +static int opMOV_a16_AX(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + writememw(ds, addr, AX); + cycles -= (is486) ? 1 : 2; + return 0; +} +static int opMOV_a32_AX(uint32_t fetchdat) +{ + uint32_t addr = getlong(); + writememw(ds, addr, AX); + cycles -= (is486) ? 1 : 2; + return 0; +} +static int opMOV_a16_EAX(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + writememl(ds, addr, EAX); + cycles -= (is486) ? 1 : 2; + return 0; +} +static int opMOV_a32_EAX(uint32_t fetchdat) +{ + uint32_t addr = getlong(); + writememl(ds, addr, EAX); + cycles -= (is486) ? 1 : 2; + return 0; +} + + +static int opLEA_w_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + regs[reg].w = eaaddr; + cycles -= timing_rr; + return 0; +} +static int opLEA_w_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + regs[reg].w = eaaddr; + cycles -= timing_rr; + return 0; +} + +static int opLEA_l_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + regs[reg].l = eaaddr & 0xffff; + cycles -= timing_rr; + return 0; +} +static int opLEA_l_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + regs[reg].l = eaaddr; + cycles -= timing_rr; + return 0; +} + + + +int opXLAT_a16(uint32_t fetchdat) +{ + uint32_t addr = (BX + AL)&0xFFFF; + uint8_t temp = readmemb(ds, addr); if (abrt) return 0; + AL = temp; + cycles -= 5; + return 0; +} +int opXLAT_a32(uint32_t fetchdat) +{ + uint32_t addr = EBX + AL; + uint8_t temp = readmemb(ds, addr); if (abrt) return 0; + AL = temp; + cycles -= 5; + return 0; +} + +static int opMOV_b_r_a16(uint32_t fetchdat) +{ + if ((uint8_t)fetchdat >= 0xc0) + { + pc++; + setr8(fetchdat & 7, getr8((fetchdat >> 3) & 7)); + cycles -= timing_rr; + } + else + { + fetch_ea_16(fetchdat); + seteab(getr8(reg)); + cycles -= is486 ? 1 : 2; + } + return 0; +} +static int opMOV_b_r_a32(uint32_t fetchdat) +{ + if ((uint8_t)fetchdat >= 0xc0) + { + pc++; + setr8(fetchdat & 7, getr8((fetchdat >> 3) & 7)); + cycles -= timing_rr; + } + else + { + fetch_ea_32(fetchdat); + seteab(getr8(reg)); + cycles -= is486 ? 1 : 2; + } + return 0; +} +static int opMOV_w_r_a16(uint32_t fetchdat) +{ + if ((uint8_t)fetchdat >= 0xc0) + { + pc++; + regs[fetchdat & 7].w = regs[(fetchdat >> 3) & 7].w; + cycles -= timing_rr; + } + else + { + fetch_ea_16(fetchdat); + seteaw(regs[reg].w); + cycles -= is486 ? 1 : 2; + } + return 0; +} +static int opMOV_w_r_a32(uint32_t fetchdat) +{ + if ((uint8_t)fetchdat >= 0xc0) + { + pc++; + regs[fetchdat & 7].w = regs[(fetchdat >> 3) & 7].w; + cycles -= timing_rr; + } + else + { + fetch_ea_32(fetchdat); + seteaw(regs[reg].w); + cycles -= is486 ? 1 : 2; + } + return 0; +} +static int opMOV_l_r_a16(uint32_t fetchdat) +{ + if ((uint8_t)fetchdat >= 0xc0) + { + pc++; + regs[fetchdat & 7].l = regs[(fetchdat >> 3) & 7].l; + cycles -= timing_rr; + } + else + { + fetch_ea_16(fetchdat); + seteal(regs[reg].l); + cycles -= is486 ? 1 : 2; + } + return 0; +} +static int opMOV_l_r_a32(uint32_t fetchdat) +{ + if ((uint8_t)fetchdat >= 0xc0) + { + pc++; + regs[fetchdat & 7].l = regs[(fetchdat >> 3) & 7].l; + cycles -= timing_rr; + } + else + { + fetch_ea_32(fetchdat); + seteal(regs[reg].l); + cycles -= is486 ? 1 : 2; + } + return 0; +} + +static int opMOV_r_b_a16(uint32_t fetchdat) +{ + if ((uint8_t)fetchdat >= 0xc0) + { + pc++; + setr8((fetchdat >> 3) & 7, getr8(fetchdat & 7)); + cycles -= timing_rr; + } + else + { + uint8_t temp; + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 0; + setr8(reg, temp); + cycles -= is486 ? 1 : 4; + } + return 0; +} +static int opMOV_r_b_a32(uint32_t fetchdat) +{ + if ((uint8_t)fetchdat >= 0xc0) + { + pc++; + setr8((fetchdat >> 3) & 7, getr8(fetchdat & 7)); + cycles -= timing_rr; + } + else + { + uint8_t temp; + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 0; + setr8(reg, temp); + cycles -= is486 ? 1 : 4; + } + return 0; +} +static int opMOV_r_w_a16(uint32_t fetchdat) +{ + if ((uint8_t)fetchdat >= 0xc0) + { + pc++; + regs[(fetchdat >> 3) & 7].w = regs[fetchdat & 7].w; + cycles -= timing_rr; + } + else + { + uint16_t temp; + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 0; + regs[reg].w = temp; + cycles -= (is486) ? 1 : 4; + } + return 0; +} +static int opMOV_r_w_a32(uint32_t fetchdat) +{ + if ((uint8_t)fetchdat >= 0xc0) + { + pc++; + regs[(fetchdat >> 3) & 7].w = regs[fetchdat & 7].w; + cycles -= timing_rr; + } + else + { + uint16_t temp; + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 0; + regs[reg].w = temp; + cycles -= (is486) ? 1 : 4; + } + return 0; +} +static int opMOV_r_l_a16(uint32_t fetchdat) +{ + if ((uint8_t)fetchdat >= 0xc0) + { + pc++; + regs[(fetchdat >> 3) & 7].l = regs[fetchdat & 7].l; + cycles -= timing_rr; + } + else + { + uint32_t temp; + fetch_ea_16(fetchdat); + temp = geteal(); if (abrt) return 0; + regs[reg].l = temp; + cycles -= is486 ? 1 : 4; + } + return 0; +} +static int opMOV_r_l_a32(uint32_t fetchdat) +{ + if ((uint8_t)fetchdat >= 0xc0) + { + pc++; + regs[(fetchdat >> 3) & 7].l = regs[fetchdat & 7].l; + cycles -= timing_rr; + } + else + { + uint32_t temp; + fetch_ea_32(fetchdat); + temp = geteal(); if (abrt) return 0; + regs[reg].l = temp; + cycles -= is486 ? 1 : 4; + } + return 0; +} diff --git a/src/x86_ops_mov_ctrl.h b/src/x86_ops_mov_ctrl.h new file mode 100644 index 0000000..e227108 --- /dev/null +++ b/src/x86_ops_mov_ctrl.h @@ -0,0 +1,232 @@ +static int opMOV_r_CRx_a16(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from CRx\n"); + x86gpf(NULL, 0); + return 0; + } + fetch_ea_16(fetchdat); + switch (reg) + { + case 0: + regs[rm].l = cr0; + if (is486) regs[rm].l |= 0x10; /*ET hardwired on 486*/ + break; + case 2: + regs[rm].l = cr2; + break; + case 3: + regs[rm].l = cr3; + break; + default: + pclog("Bad read of CR%i %i\n",rmdat&7,reg); + pc = oldpc; + x86illegal(); + break; + } + cycles -= 6; + return 0; +} +static int opMOV_r_CRx_a32(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from CRx\n"); + x86gpf(NULL, 0); + return 0; + } + fetch_ea_32(fetchdat); + switch (reg) + { + case 0: + regs[rm].l = cr0; + if (is486) regs[rm].l |= 0x10; /*ET hardwired on 486*/ + break; + case 2: + regs[rm].l = cr2; + break; + case 3: + regs[rm].l = cr3; + break; + default: + pclog("Bad read of CR%i %i\n",rmdat&7,reg); + pc = oldpc; + x86illegal(); + break; + } + cycles -= 6; + return 0; +} + +static int opMOV_r_DRx_a16(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from DRx\n"); + x86gpf(NULL, 0); + return 0; + } + fetch_ea_16(fetchdat); + regs[rm].l = 0; + cycles -= 6; + return 0; +} +static int opMOV_r_DRx_a32(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from DRx\n"); + x86gpf(NULL, 0); + return 0; + } + fetch_ea_32(fetchdat); + regs[rm].l = 0; + cycles -= 6; + return 0; +} + +static int opMOV_CRx_r_a16(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load CRx\n"); + x86gpf(NULL,0); + return 0; + } + fetch_ea_16(fetchdat); + switch (reg) + { + case 0: + if ((regs[rm].l ^ cr0) & 0x80000001) flushmmucache(); + cr0 = regs[rm].l; + if (cpu_16bitbus) cr0 |= 0x10; + if (!(cr0 & 0x80000000)) mmu_perm=4; + break; + case 2: + cr2 = regs[rm].l; + break; + case 3: + cr3 = regs[rm].l & ~0xfff; + flushmmucache(); + break; + default: + pclog("Bad load CR%i\n", reg); + pc = oldpc; + x86illegal(); + break; + } + cycles -= 10; + return 0; +} +static int opMOV_CRx_r_a32(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load CRx\n"); + x86gpf(NULL,0); + return 0; + } + fetch_ea_32(fetchdat); + switch (reg) + { + case 0: + if ((regs[rm].l ^ cr0) & 0x80000001) flushmmucache(); + cr0 = regs[rm].l; + if (cpu_16bitbus) cr0 |= 0x10; + if (!(cr0 & 0x80000000)) mmu_perm=4; + break; + case 2: + cr2 = regs[rm].l; + break; + case 3: + cr3 = regs[rm].l & ~0xfff; + flushmmucache(); + break; + default: + pclog("Bad load CR%i\n", reg); + pc = oldpc; + x86illegal(); + break; + } + cycles -= 10; + return 0; +} + +static int opMOV_DRx_r_a16(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load DRx\n"); + x86gpf(NULL, 0); + return 0; + } + fetch_ea_16(fetchdat); + cycles -= 6; + return 0; +} +static int opMOV_DRx_r_a32(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load DRx\n"); + x86gpf(NULL, 0); + return 0; + } + fetch_ea_16(fetchdat); + cycles -= 6; + return 0; +} + +static int opMOV_r_TRx_a16(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from TRx\n"); + x86gpf(NULL, 0); + return 0; + } + fetch_ea_16(fetchdat); + regs[rm].l = 0; + cycles -= 6; + return 0; +} +static int opMOV_r_TRx_a32(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from TRx\n"); + x86gpf(NULL, 0); + return 0; + } + fetch_ea_32(fetchdat); + regs[rm].l = 0; + cycles -= 6; + return 0; +} + +static int opMOV_TRx_r_a16(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load TRx\n"); + x86gpf(NULL, 0); + return 0; + } + fetch_ea_16(fetchdat); + cycles -= 6; + return 0; +} +static int opMOV_TRx_r_a32(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load TRx\n"); + x86gpf(NULL, 0); + return 0; + } + fetch_ea_16(fetchdat); + cycles -= 6; + return 0; +} + diff --git a/src/x86_ops_mov_seg.h b/src/x86_ops_mov_seg.h new file mode 100644 index 0000000..9ec20de --- /dev/null +++ b/src/x86_ops_mov_seg.h @@ -0,0 +1,396 @@ +static int opMOV_w_seg_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + seteaw(ES); + break; + case 0x08: /*CS*/ + seteaw(CS); + break; + case 0x18: /*DS*/ + if (ssegs) ds = oldds; + seteaw(DS); + break; + case 0x10: /*SS*/ + if (ssegs) ss = oldss; + seteaw(SS); + break; + case 0x20: /*FS*/ + seteaw(FS); + break; + case 0x28: /*GS*/ + seteaw(GS); + break; + } + + cycles -= ((mod == 3) ? 2 : 3); + return 0; +} +static int opMOV_w_seg_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + seteaw(ES); + break; + case 0x08: /*CS*/ + seteaw(CS); + break; + case 0x18: /*DS*/ + if (ssegs) ds = oldds; + seteaw(DS); + break; + case 0x10: /*SS*/ + if (ssegs) ss = oldss; + seteaw(SS); + break; + case 0x20: /*FS*/ + seteaw(FS); + break; + case 0x28: /*GS*/ + seteaw(GS); + break; + } + + cycles -= ((mod == 3) ? 2 : 3); + return 0; +} + +static int opMOV_l_seg_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + if (mod == 3) regs[rm].l = ES; + else seteaw(ES); + break; + case 0x08: /*CS*/ + if (mod == 3) regs[rm].l = CS; + else seteaw(CS); + break; + case 0x18: /*DS*/ + if (ssegs) ds = oldds; + if (mod == 3) regs[rm].l = DS; + else seteaw(DS); + break; + case 0x10: /*SS*/ + if (ssegs) ss = oldss; + if (mod == 3) regs[rm].l = SS; + else seteaw(SS); + break; + case 0x20: /*FS*/ + if (mod == 3) regs[rm].l = FS; + else seteaw(FS); + break; + case 0x28: /*GS*/ + if (mod == 3) regs[rm].l = GS; + else seteaw(GS); + break; + } + + cycles -= ((mod == 3) ? 2 : 3); + return 0; +} +static int opMOV_l_seg_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + if (mod == 3) regs[rm].l = ES; + else seteaw(ES); + break; + case 0x08: /*CS*/ + if (mod == 3) regs[rm].l = CS; + else seteaw(CS); + break; + case 0x18: /*DS*/ + if (ssegs) ds = oldds; + if (mod == 3) regs[rm].l = DS; + else seteaw(DS); + break; + case 0x10: /*SS*/ + if (ssegs) ss = oldss; + if (mod == 3) regs[rm].l = SS; + else seteaw(SS); + break; + case 0x20: /*FS*/ + if (mod == 3) regs[rm].l = FS; + else seteaw(FS); + break; + case 0x28: /*GS*/ + if (mod == 3) regs[rm].l = GS; + else seteaw(GS); + break; + } + + cycles -= ((mod == 3) ? 2 : 3); + return 0; +} + +static int opMOV_seg_w_a16(uint32_t fetchdat) +{ + uint16_t new_seg; + + fetch_ea_16(fetchdat); + + new_seg=geteaw(); if (abrt) return 0; + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + loadseg(new_seg, &_es); + break; + case 0x18: /*DS*/ + loadseg(new_seg, &_ds); + if (ssegs) oldds = ds; + break; + case 0x10: /*SS*/ + loadseg(new_seg, &_ss); + if (ssegs) + { + ds = oldds; + rds = DS; + ssegs = 0; + } + op32 = use32; + return 1; + case 0x20: /*FS*/ + loadseg(new_seg, &_fs); + break; + case 0x28: /*GS*/ + loadseg(new_seg, &_gs); + break; + } + + cycles -= ((mod == 3) ? 2 : 5); + return 0; +} +static int opMOV_seg_w_a32(uint32_t fetchdat) +{ + uint16_t new_seg; + + fetch_ea_32(fetchdat); + + new_seg=geteaw(); if (abrt) return 0; + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + loadseg(new_seg, &_es); + break; + case 0x18: /*DS*/ + loadseg(new_seg, &_ds); + if (ssegs) oldds = ds; + break; + case 0x10: /*SS*/ + loadseg(new_seg, &_ss); + if (ssegs) + { + ds = oldds; + rds = DS; + ssegs = 0; + } + op32 = use32; + return 1; + case 0x20: /*FS*/ + loadseg(new_seg, &_fs); + break; + case 0x28: /*GS*/ + loadseg(new_seg, &_gs); + break; + } + + cycles -= ((mod == 3) ? 2 : 5); + return 0; +} + + +static int opLDS_w_a16(uint32_t fetchdat) +{ + uint16_t addr, seg; + + fetch_ea_16(fetchdat); + addr = readmemw(easeg, eaaddr); + seg = readmemw(easeg, eaaddr + 2); if (abrt) return 0; + loadseg(seg, &_ds); if (abrt) return 0; + regs[reg].w = addr; + if (ssegs) oldds = ds; + + cycles -= 7; + return 0; +} +static int opLDS_w_a32(uint32_t fetchdat) +{ + uint16_t addr, seg; + + fetch_ea_32(fetchdat); + addr = readmemw(easeg, eaaddr); + seg = readmemw(easeg, eaaddr + 2); if (abrt) return 0; + loadseg(seg, &_ds); if (abrt) return 0; + regs[reg].w = addr; + if (ssegs) oldds = ds; + + cycles -= 7; + return 0; +} +static int opLDS_l_a16(uint32_t fetchdat) +{ + uint32_t addr; + uint16_t seg; + + fetch_ea_16(fetchdat); + addr = readmeml(easeg, eaaddr); + seg = readmemw(easeg, eaaddr + 4); if (abrt) return 0; + loadseg(seg, &_ds); if (abrt) return 0; + regs[reg].l = addr; + if (ssegs) oldds = ds; + + cycles -= 7; + return 0; +} +static int opLDS_l_a32(uint32_t fetchdat) +{ + uint32_t addr; + uint16_t seg; + + fetch_ea_32(fetchdat); + addr = readmeml(easeg, eaaddr); + seg = readmemw(easeg, eaaddr + 4); if (abrt) return 0; + loadseg(seg, &_ds); if (abrt) return 0; + regs[reg].l = addr; + if (ssegs) oldds = ds; + + cycles -= 7; + return 0; +} + +static int opLSS_w_a16(uint32_t fetchdat) +{ + uint16_t addr, seg; + + fetch_ea_16(fetchdat); + addr = readmemw(easeg, eaaddr); + seg = readmemw(easeg, eaaddr + 2); if (abrt) return 0; + loadseg(seg, &_ss); if (abrt) return 0; + regs[reg].w = addr; + oldss = ss; + + cycles -= 7; + return 0; +} +static int opLSS_w_a32(uint32_t fetchdat) +{ + uint16_t addr, seg; + + fetch_ea_32(fetchdat); + addr = readmemw(easeg, eaaddr); + seg = readmemw(easeg, eaaddr + 2); if (abrt) return 0; + loadseg(seg, &_ss); if (abrt) return 0; + regs[reg].w = addr; + oldss = ss; + + cycles -= 7; + return 0; +} +static int opLSS_l_a16(uint32_t fetchdat) +{ + uint32_t addr; + uint16_t seg; + + fetch_ea_16(fetchdat); + addr = readmeml(easeg, eaaddr); + seg = readmemw(easeg, eaaddr + 4); if (abrt) return 0; + loadseg(seg, &_ss); if (abrt) return 0; + regs[reg].l = addr; + oldss = ss; + + cycles -= 7; + return 0; +} +static int opLSS_l_a32(uint32_t fetchdat) +{ + uint32_t addr; + uint16_t seg; + + fetch_ea_32(fetchdat); + addr = readmeml(easeg, eaaddr); + seg = readmemw(easeg, eaaddr + 4); if (abrt) return 0; + loadseg(seg, &_ss); if (abrt) return 0; + regs[reg].l = addr; + oldss = ss; + + cycles -= 7; + return 0; +} + +#define opLsel(name, sel) \ + static int opL ## name ## _w_a16(uint32_t fetchdat) \ + { \ + uint16_t addr, seg; \ + \ + fetch_ea_16(fetchdat); \ + addr = readmemw(easeg, eaaddr); \ + seg = readmemw(easeg, eaaddr + 2); if (abrt) return 0; \ + loadseg(seg, &sel); if (abrt) return 0; \ + regs[reg].w = addr; \ + \ + cycles -= 7; \ + return 0; \ + } \ + \ + static int opL ## name ## _w_a32(uint32_t fetchdat) \ + { \ + uint16_t addr, seg; \ + \ + fetch_ea_32(fetchdat); \ + addr = readmemw(easeg, eaaddr); \ + seg = readmemw(easeg, eaaddr + 2); if (abrt) return 0; \ + loadseg(seg, &sel); if (abrt) return 0; \ + regs[reg].w = addr; \ + \ + cycles -= 7; \ + return 0; \ + } \ + \ + static int opL ## name ## _l_a16(uint32_t fetchdat) \ + { \ + uint32_t addr; \ + uint16_t seg; \ + \ + fetch_ea_16(fetchdat); \ + addr = readmeml(easeg, eaaddr); \ + seg = readmemw(easeg, eaaddr + 4); if (abrt) return 0; \ + loadseg(seg, &sel); if (abrt) return 0; \ + regs[reg].l = addr; \ + \ + cycles -= 7; \ + return 0; \ + } \ + \ + static int opL ## name ## _l_a32(uint32_t fetchdat) \ + { \ + uint32_t addr; \ + uint16_t seg; \ + \ + fetch_ea_32(fetchdat); \ + addr = readmeml(easeg, eaaddr); \ + seg = readmemw(easeg, eaaddr + 4); if (abrt) return 0; \ + loadseg(seg, &sel); if (abrt) return 0; \ + regs[reg].l = addr; \ + \ + cycles -= 7; \ + return 0; \ + } + +opLsel(ES, _es) +opLsel(FS, _fs) +opLsel(GS, _gs) diff --git a/src/x86_ops_movx.h b/src/x86_ops_movx.h new file mode 100644 index 0000000..e41f22e --- /dev/null +++ b/src/x86_ops_movx.h @@ -0,0 +1,145 @@ +static int opMOVZX_w_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 0; + regs[reg].w = (uint16_t)temp; + + cycles -= 3; + return 0; +} +static int opMOVZX_w_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 0; + regs[reg].w = (uint16_t)temp; + + cycles -= 3; + return 0; +} +static int opMOVZX_l_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 0; + regs[reg].l = (uint32_t)temp; + + cycles -= 3; + return 0; +} +static int opMOVZX_l_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 0; + regs[reg].l = (uint32_t)temp; + + cycles -= 3; + return 0; +} +static int opMOVZX_l_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 0; + regs[reg].l = (uint32_t)temp; + + cycles -= 3; + return 0; +} +static int opMOVZX_l_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 0; + regs[reg].l = (uint32_t)temp; + + cycles -= 3; + return 0; +} + +static int opMOVSX_w_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 0; + regs[reg].w = (uint16_t)temp; + if (temp & 0x80) + regs[reg].w |= 0xff00; + + cycles -= 3; + return 0; +} +static int opMOVSX_w_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 0; + regs[reg].w = (uint16_t)temp; + if (temp & 0x80) + regs[reg].w |= 0xff00; + + cycles -= 3; + return 0; +} +static int opMOVSX_l_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 0; + regs[reg].l = (uint32_t)temp; + if (temp & 0x80) + regs[reg].l |= 0xffffff00; + + cycles -= 3; + return 0; +} +static int opMOVSX_l_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 0; + regs[reg].l = (uint32_t)temp; + if (temp & 0x80) + regs[reg].l |= 0xffffff00; + + cycles -= 3; + return 0; +} +static int opMOVSX_l_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 0; + regs[reg].l = (uint32_t)temp; + if (temp & 0x8000) + regs[reg].l |= 0xffff0000; + + cycles -= 3; + return 0; +} +static int opMOVSX_l_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 0; + regs[reg].l = (uint32_t)temp; + if (temp & 0x8000) + regs[reg].l |= 0xffff0000; + + cycles -= 3; + return 0; +} diff --git a/src/x86_ops_msr.h b/src/x86_ops_msr.h new file mode 100644 index 0000000..4ca1503 --- /dev/null +++ b/src/x86_ops_msr.h @@ -0,0 +1,13 @@ +static int opRDTSC(uint32_t fetchdat) +{ + if (!cpu_hasrdtsc) + { + pc = oldpc; + x86illegal(); + return 0; + } + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + cycles--; + return 0; +} diff --git a/src/x86_ops_mul.h b/src/x86_ops_mul.h new file mode 100644 index 0000000..c4983fd --- /dev/null +++ b/src/x86_ops_mul.h @@ -0,0 +1,222 @@ +static int opIMUL_w_iw_a16(uint32_t fetchdat) +{ + uint32_t templ; + int16_t tempw, tempw2; + + fetch_ea_16(fetchdat); + + tempw = geteaw(); if (abrt) return 0; + tempw2 = getword(); if (abrt) return 0; + + templ = ((int)tempw) * ((int)tempw2); + flags_rebuild(); + if ((templ >> 16) != 0 && (templ >> 16) != 0xffff) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + regs[reg].w = templ & 0xffff; + + cycles -= (mod == 3) ? 14 : 17; + return 0; +} +static int opIMUL_w_iw_a32(uint32_t fetchdat) +{ + uint32_t templ; + int16_t tempw, tempw2; + + fetch_ea_32(fetchdat); + + tempw = geteaw(); if (abrt) return 0; + tempw2 = getword(); if (abrt) return 0; + + templ = ((int)tempw) * ((int)tempw2); + flags_rebuild(); + if ((templ >> 16) != 0 && (templ >> 16) != 0xffff) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + regs[reg].w = templ & 0xffff; + + cycles -= (mod == 3) ? 14 : 17; + return 0; +} + +static int opIMUL_l_il_a16(uint32_t fetchdat) +{ + int64_t temp64; + int32_t templ, templ2; + + fetch_ea_16(fetchdat); + + templ = geteal(); if (abrt) return 0; + templ2 = getlong(); if (abrt) return 0; + + temp64 = ((int64_t)templ) * ((int64_t)templ2); + flags_rebuild(); + if ((temp64 >> 32) != 0 && (temp64 >> 32) != 0xffffffff) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + regs[reg].l = temp64 & 0xffffffff; + + cycles-=25; + return 0; +} +static int opIMUL_l_il_a32(uint32_t fetchdat) +{ + int64_t temp64; + int32_t templ, templ2; + + fetch_ea_32(fetchdat); + + templ = geteal(); if (abrt) return 0; + templ2 = getlong(); if (abrt) return 0; + + temp64 = ((int64_t)templ) * ((int64_t)templ2); + flags_rebuild(); + if ((temp64 >> 32) != 0 && (temp64 >> 32) != 0xffffffff) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + regs[reg].l = temp64 & 0xffffffff; + + cycles-=25; + return 0; +} + +static int opIMUL_w_ib_a16(uint32_t fetchdat) +{ + uint32_t templ; + int16_t tempw, tempw2; + + fetch_ea_16(fetchdat); + + tempw = geteaw(); if (abrt) return 0; + tempw2 = getbyte(); if (abrt) return 0; + if (tempw2 & 0x80) tempw2 |= 0xff00; + + templ = ((int)tempw) * ((int)tempw2); + flags_rebuild(); + if ((templ >> 16) != 0 && ((templ >> 16) & 0xffff) != 0xffff) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + regs[reg].w = templ & 0xffff; + + cycles -= (mod == 3) ? 14 : 17; + return 0; +} +static int opIMUL_w_ib_a32(uint32_t fetchdat) +{ + uint32_t templ; + int16_t tempw, tempw2; + + fetch_ea_32(fetchdat); + + tempw = geteaw(); if (abrt) return 0; + tempw2 = getbyte(); if (abrt) return 0; + if (tempw2 & 0x80) tempw2 |= 0xff00; + + templ = ((int)tempw) * ((int)tempw2); + flags_rebuild(); + if ((templ >> 16) != 0 && ((templ >> 16) & 0xffff) != 0xffff) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + regs[reg].w = templ & 0xffff; + + cycles -= (mod == 3) ? 14 : 17; + return 0; +} + +static int opIMUL_l_ib_a16(uint32_t fetchdat) +{ + uint64_t temp64; + int32_t templ, templ2; + + fetch_ea_16(fetchdat); + templ = geteal(); if (abrt) return 0; + templ2 = getbyte(); if (abrt) return 0; + if (templ2 & 0x80) templ2 |= 0xffffff00; + + temp64 = ((int64_t)templ)*((int64_t)templ2); + flags_rebuild(); + if ((temp64 >> 32) != 0 && (temp64 >> 32) != 0xffffffff) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + regs[reg].l = temp64 & 0xffffffff; + + cycles -= 20; + return 0; +} +static int opIMUL_l_ib_a32(uint32_t fetchdat) +{ + uint64_t temp64; + int32_t templ, templ2; + + fetch_ea_32(fetchdat); + templ = geteal(); if (abrt) return 0; + templ2 = getbyte(); if (abrt) return 0; + if (templ2 & 0x80) templ2 |= 0xffffff00; + + temp64 = ((int64_t)templ)*((int64_t)templ2); + flags_rebuild(); + if ((temp64 >> 32) != 0 && (temp64 >> 32) != 0xffffffff) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + regs[reg].l = temp64 & 0xffffffff; + + cycles -= 20; + return 0; +} + + + +static int opIMUL_w_w_a16(uint32_t fetchdat) +{ + int32_t templ; + + fetch_ea_16(fetchdat); + templ = (int32_t)(int16_t)regs[reg].w * (int32_t)(int16_t)geteaw(); + if (abrt) return 0; + regs[reg].w = templ & 0xFFFF; + flags_rebuild(); + if ((templ >> 16) && (templ >> 16) != 0xFFFF) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + + cycles -= 18; + return 0; +} +static int opIMUL_w_w_a32(uint32_t fetchdat) +{ + int32_t templ; + + fetch_ea_32(fetchdat); + templ = (int32_t)(int16_t)regs[reg].w * (int32_t)(int16_t)geteaw(); + if (abrt) return 0; + regs[reg].w = templ & 0xFFFF; + flags_rebuild(); + if ((templ >> 16) && (templ >> 16) != 0xFFFF) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + + cycles -= 18; + return 0; +} + +static int opIMUL_l_l_a16(uint32_t fetchdat) +{ + int64_t temp64; + + fetch_ea_16(fetchdat); + temp64 = (int64_t)(int32_t)regs[reg].l * (int64_t)(int32_t)geteal(); + if (abrt) return 0; + regs[reg].l = temp64 & 0xFFFFFFFF; + flags_rebuild(); + if ((temp64 >> 32) && (temp64 >> 32) != 0xFFFFFFFF) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + + cycles -= 30; + return 0; +} +static int opIMUL_l_l_a32(uint32_t fetchdat) +{ + int64_t temp64; + + fetch_ea_32(fetchdat); + temp64 = (int64_t)(int32_t)regs[reg].l * (int64_t)(int32_t)geteal(); + if (abrt) return 0; + regs[reg].l = temp64 & 0xFFFFFFFF; + flags_rebuild(); + if ((temp64 >> 32) && (temp64 >> 32) != 0xFFFFFFFF) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + + cycles -= 30; + return 0; +} + diff --git a/src/x86_ops_pmode.h b/src/x86_ops_pmode.h new file mode 100644 index 0000000..f51dc9f --- /dev/null +++ b/src/x86_ops_pmode.h @@ -0,0 +1,404 @@ +static int opARPL_a16(uint32_t fetchdat) +{ + uint16_t temp_seg; + + NOTRM + fetch_ea_16(fetchdat); + + temp_seg = geteaw(); if (abrt) return 0; + + flags_rebuild(); + if ((temp_seg & 3) < (regs[reg].w & 3)) + { + temp_seg = (temp_seg & 0xfffc) | (regs[reg].w & 3); + seteaw(temp_seg); if (abrt) return 0; + flags |= Z_FLAG; + } + else + flags &= ~Z_FLAG; + + cycles -= is486 ? 9 : 20; + return 0; +} +static int opARPL_a32(uint32_t fetchdat) +{ + uint16_t temp_seg; + + NOTRM + fetch_ea_32(fetchdat); + + temp_seg = geteaw(); if (abrt) return 0; + + flags_rebuild(); + if ((temp_seg & 3) < (regs[reg].w & 3)) + { + temp_seg = (temp_seg & 0xfffc) | (regs[reg].w & 3); + seteaw(temp_seg); if (abrt) return 0; + flags |= Z_FLAG; + } + else + flags &= ~Z_FLAG; + + cycles -= is486 ? 9 : 20; + return 0; +} + +#define opLAR(name, fetch_ea, is32) \ + static int opLAR_ ## name(uint32_t fetchdat) \ + { \ + int valid; \ + uint16_t sel, desc; \ + \ + NOTRM \ + fetch_ea(fetchdat); \ + \ + sel = geteaw(); if (abrt) return 0; \ + \ + flags_rebuild(); \ + if (!(sel & 0xfffc)) { flags &= ~Z_FLAG; return 0; } /*Null selector*/ \ + valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); \ + if (valid) \ + { \ + cpl_override = 1; \ + desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); \ + cpl_override = 0; if (abrt) return 0; \ + } \ + flags &= ~Z_FLAG; \ + if ((desc & 0x1f00) == 0x000) valid = 0; \ + if ((desc & 0x1f00) == 0x800) valid = 0; \ + if ((desc & 0x1f00) == 0xa00) valid = 0; \ + if ((desc & 0x1f00) == 0xd00) valid = 0; \ + if ((desc & 0x1c00) < 0x1c00) /*Exclude conforming code segments*/ \ + { \ + int dpl = (desc >> 13) & 3; \ + if (dpl < CPL || dpl < (sel & 3)) valid = 0; \ + } \ + if (valid) \ + { \ + flags |= Z_FLAG; \ + cpl_override = 1; \ + if (is32) \ + regs[reg].l = readmeml(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4) & 0xffff00; \ + else \ + regs[reg].w = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4) & 0xff00; \ + cpl_override = 0; \ + } \ + cycles -= 11; \ + return 0; \ + } + +opLAR(w_a16, fetch_ea_16, 0) +opLAR(w_a32, fetch_ea_32, 0) +opLAR(l_a16, fetch_ea_16, 1) +opLAR(l_a32, fetch_ea_32, 1) + +#define opLSL(name, fetch_ea, is32) \ + static int opLSL_ ## name(uint32_t fetchdat) \ + { \ + int valid; \ + uint16_t sel, desc; \ + \ + NOTRM \ + fetch_ea(fetchdat); \ + \ + sel = geteaw(); if (abrt) return 0; \ + flags_rebuild(); \ + flags &= ~Z_FLAG; \ + if (!(sel & 0xfffc)) return 0; /*Null selector*/ \ + valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); \ + if (valid) \ + { \ + cpl_override = 1; \ + desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); \ + cpl_override = 0; if (abrt) return 0; \ + } \ + if ((desc & 0x1400) == 0x400) valid = 0; /*Interrupt or trap or call gate*/ \ + if ((desc & 0x1f00) == 0x000) valid = 0; /*Invalid*/ \ + if ((desc & 0x1f00) == 0xa00) valid = 0; /*Invalid*/ \ + if ((desc & 0x1c00) != 0x1c00) /*Exclude conforming code segments*/ \ + { \ + int rpl = (desc >> 13) & 3; \ + if (rpl < CPL || rpl < (sel & 3)) valid = 0; \ + } \ + if (valid) \ + { \ + flags |= Z_FLAG; \ + cpl_override = 1; \ + if (is32) \ + { \ + regs[reg].l = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7)); \ + regs[reg].l |= (readmemb(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 6) & 0xF) << 16; \ + if (readmemb(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 6) & 0x80) \ + { \ + regs[reg].l <<= 12; \ + regs[reg].l |= 0xFFF; \ + } \ + } \ + else \ + regs[reg].w = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7)); \ + cpl_override = 0; \ + } \ + cycles -= 10; \ + return 0; \ + } + +opLSL(w_a16, fetch_ea_16, 0) +opLSL(w_a32, fetch_ea_32, 0) +opLSL(l_a16, fetch_ea_16, 1) +opLSL(l_a32, fetch_ea_32, 1) + + +static inline int op0F00_common(uint32_t fetchdat) +{ + int dpl, valid, granularity; + uint32_t addr, base, limit; + uint16_t desc, sel; + uint8_t access; + +// pclog("op0F00 %02X %04X:%04X\n", rmdat & 0x38, CS, pc); + switch (rmdat & 0x38) + { + case 0x00: /*SLDT*/ + seteaw(ldt.seg); + cycles -= 4; + break; + case 0x08: /*STR*/ + seteaw(tr.seg); + cycles -= 4; + break; + case 0x10: /*LLDT*/ + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid LLDT!\n"); + x86gpf(NULL,0); + return 0; + } + sel = geteaw(); if (abrt) return 0; + addr = (sel & ~7) + gdt.base; + limit = readmemw(0, addr) + ((readmemb(0, addr + 6) & 0xf) << 16); + base = (readmemw(0, addr + 2)) | (readmemb(0, addr + 4) << 16) | (readmemb(0, addr + 7) << 24); + access = readmemb(0, addr + 5); + granularity = readmemb(0, addr + 6) & 0x80; + if (abrt) return 0; + ldt.limit = limit; + ldt.access = access; + if (granularity) + { + ldt.limit <<= 12; + ldt.limit |= 0xfff; + } + ldt.base = base; + ldt.seg = sel; + cycles -= 20; + break; + case 0x18: /*LTR*/ + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid LTR!\n"); + x86gpf(NULL,0); + break; + } + sel = geteaw(); if (abrt) return 0; + addr = (sel & ~7) + gdt.base; + limit = readmemw(0, addr) + ((readmemb(0, addr + 6) & 0xf) << 16); + base = (readmemw(0, addr + 2)) | (readmemb(0, addr + 4) << 16) | (readmemb(0, addr + 7) << 24); + access = readmemb(0, addr + 5); + granularity = readmemb(0, addr + 6) & 0x80; + if (abrt) return 0; + tr.seg = sel; + tr.limit = limit; + tr.access = access; + if (granularity) + { + tr.limit <<= 12; + tr.limit |= 0xFFF; + } + tr.base = base; + cycles -= 20; + break; + case 0x20: /*VERR*/ + sel = geteaw(); if (abrt) return 0; + flags_rebuild(); + flags &= ~Z_FLAG; + if (!(sel & 0xfffc)) return 0; /*Null selector*/ + cpl_override = 1; + valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); + desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); + cpl_override = 0; if (abrt) return 0; + if (!(desc & 0x1000)) valid = 0; + if ((desc & 0xC00) != 0xC00) /*Exclude conforming code segments*/ + { + dpl = (desc >> 13) & 3; /*Check permissions*/ + if (dpl < CPL || dpl < (sel & 3)) valid = 0; + } + if ((desc & 0x0800) && !(desc & 0x0200)) valid = 0; /*Non-readable code*/ + if (valid) flags |= Z_FLAG; + cycles -= 20; + break; + case 0x28: /*VERW*/ + sel = geteaw(); if (abrt) return 0; + flags_rebuild(); + flags &= ~Z_FLAG; + if (!(sel & 0xfffc)) return 0; /*Null selector*/ + cpl_override = 1; + valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); + desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); + cpl_override = 0; if (abrt) return 0; + if (!(desc & 0x1000)) valid = 0; + dpl = (desc >> 13) & 3; /*Check permissions*/ + if (dpl < CPL || dpl < (sel & 3)) valid = 0; + if (desc & 0x0800) valid = 0; /*Code*/ + if (!(desc & 0x0200)) valid = 0; /*Read-only data*/ + if (valid) flags |= Z_FLAG; + cycles -= 20; + break; + + default: + pclog("Bad 0F 00 opcode %02X\n", rmdat & 0x38); + pc -= 3; + x86illegal(); + break; + } + return 0; +} + +static inline op0F00_a16(uint32_t fetchdat) +{ + NOTRM + + fetch_ea_16(fetchdat); + + op0F00_common(fetchdat); + return 0; +} +static inline op0F00_a32(uint32_t fetchdat) +{ + NOTRM + + fetch_ea_32(fetchdat); + + op0F00_common(fetchdat); + return 0; +} + +static inline op0F01_common(uint32_t fetchdat, int is32) +{ + uint32_t base; + uint16_t limit, tempw; +// pclog("op0F01 %02X %04X:%04X\n", rmdat & 0x38, CS, pc); + switch (rmdat & 0x38) + { + case 0x00: /*SGDT*/ + seteaw(gdt.limit); + base = is32 ? gdt.base : (gdt.base & 0xffffff); + writememl(easeg, eaaddr + 2, base); + cycles -= 7; + break; + case 0x08: /*SIDT*/ + seteaw(idt.limit); + base = is32 ? idt.base : (idt.base & 0xffffff); + writememl(easeg, eaaddr + 2, base); + cycles -= 7; + break; + case 0x10: /*LGDT*/ + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid LGDT!\n"); + x86gpf(NULL,0); + break; + } +// pclog("LGDT %08X:%08X\n", easeg, eaaddr); + limit = geteaw(); + base = readmeml(0, easeg + eaaddr + 2); if (abrt) return 0; +// pclog(" %08X %04X\n", base, limit); + gdt.limit = limit; + gdt.base = base; + if (!is32) gdt.base &= 0xffffff; + cycles -= 11; + break; + case 0x18: /*LIDT*/ + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid LIDT!\n"); + x86gpf(NULL,0); + break; + } +// pclog("LIDT %08X:%08X\n", easeg, eaaddr); + limit = geteaw(); + base = readmeml(0, easeg + eaaddr + 2); if (abrt) return 0; +// pclog(" %08X %04X\n", base, limit); + idt.limit = limit; + idt.base = base; + if (!is32) idt.base &= 0xffffff; + cycles -= 11; + break; + + case 0x20: /*SMSW*/ + if (is486) seteaw(msw); + else seteaw(msw | 0xFF00); + cycles -= 2; + break; + case 0x30: /*LMSW*/ + if ((CPL || eflags&VM_FLAG) && (msw&1)) + { + pclog("LMSW - ring not zero!\n"); + x86gpf(NULL, 0); + break; + } + tempw = geteaw(); if (abrt) return 0; + if (msw & 1) tempw |= 1; + msw = tempw; + break; + + case 0x38: /*INVLPG*/ + if (is486) + { + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid INVLPG!\n"); + x86gpf(NULL, 0); + break; + } + mmu_invalidate(ds + eaaddr); + cycles -= 12; + break; + } + + default: + pclog("Bad 0F 01 opcode %02X\n", rmdat & 0x38); + pc -= 3; + x86illegal(); + break; + } + return 0; +} + +static inline op0F01_w_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + op0F01_common(fetchdat, 0); + return 0; +} +static inline op0F01_w_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + + op0F01_common(fetchdat, 0); + return 0; +} +static inline op0F01_l_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + op0F01_common(fetchdat, 1); + return 0; +} +static inline op0F01_l_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + + op0F01_common(fetchdat, 1); + return 0; +} + diff --git a/src/x86_ops_prefix.h b/src/x86_ops_prefix.h new file mode 100644 index 0000000..c042e46 --- /dev/null +++ b/src/x86_ops_prefix.h @@ -0,0 +1,73 @@ +static int op_CS(uint32_t fetchdat) +{ + oldss = ss; + oldds = ds; + ds = ss = cs; + rds = CS; + ssegs = 2; + cycles -= 4; + return 1; +} +static int op_DS(uint32_t fetchdat) +{ + oldss = ss; + oldds = ds; + ds = ss = ds; + ssegs = 2; + cycles -= 4; + return 1; +} +static int op_ES(uint32_t fetchdat) +{ + oldss = ss; + oldds = ds; + ds = ss = es; + rds = ES; + ssegs = 2; + cycles -= 4; + return 1; +} +static int op_FS(uint32_t fetchdat) +{ + oldss = ss; + oldds = ds; + rds = FS; + ds = ss = fs; + ssegs = 2; + cycles -= 4; + return 1; +} +static int op_GS(uint32_t fetchdat) +{ + oldss = ss; + oldds = ds; + rds = GS; + ds = ss = gs; + ssegs = 2; + cycles -= 4; + return 1; +} +static int op_SS(uint32_t fetchdat) +{ + oldss = ss; + oldds = ds; + ds = ss = ss; + rds = SS; + ssegs = 2; + cycles -= 4; + return 1; +} + + +static int op_66(uint32_t fetchdat) /*Data size select*/ +{ + op32 = ((use32 & 0x100) ^ 0x100) | (op32 & 0x200); + cycles -= 2; + return 1; +} +static int op_67(uint32_t fetchdat) /*Address size select*/ +{ + op32 = ((use32 & 0x200) ^ 0x200) | (op32 & 0x100); + cycles -= 2; + return 1; +} diff --git a/src/x86_ops_rep.h b/src/x86_ops_rep.h new file mode 100644 index 0000000..e941ebb --- /dev/null +++ b/src/x86_ops_rep.h @@ -0,0 +1,11 @@ +static int opREPNE(uint32_t fetchdat) +{ + rep386(0); + return 0; +} +static int opREPE(uint32_t fetchdat) +{ + rep386(1); + return 0; +} + diff --git a/src/x86_ops_ret.h b/src/x86_ops_ret.h new file mode 100644 index 0000000..21eb3a8 --- /dev/null +++ b/src/x86_ops_ret.h @@ -0,0 +1,152 @@ +#define RETF_a16(stack_offset) \ + if ((msw&1) && !(eflags&VM_FLAG)) \ + { \ + pmoderetf(0, stack_offset); \ + return 0; \ + } \ + if (ssegs) ss = oldss; \ + oxpc = pc; \ + if (stack32) \ + { \ + pc = readmemw(ss, ESP); \ + loadcs(readmemw(ss, ESP + 2)); \ + } \ + else \ + { \ + pc = readmemw(ss, SP); \ + loadcs(readmemw(ss, SP + 2)); \ + } \ + if (abrt) return 0; \ + if (stack32) ESP += 4 + stack_offset; \ + else SP += 4 + stack_offset; \ + cycles -= is486 ? 13 : 18; + +#define RETF_a32(stack_offset) \ + if ((msw&1) && !(eflags&VM_FLAG)) \ + { \ + pmoderetf(1, stack_offset); \ + return 0; \ + } \ + if (ssegs) ss = oldss; \ + oxpc = pc; \ + if (stack32) \ + { \ + pc = readmeml(ss, ESP); \ + loadcs(readmeml(ss, ESP + 4) & 0xffff); \ + } \ + else \ + { \ + pc = readmeml(ss, SP); \ + loadcs(readmeml(ss, SP + 4) & 0xffff); \ + } \ + if (abrt) return 0; \ + if (stack32) ESP += 8 + stack_offset; \ + else SP += 8 + stack_offset; \ + cycles -= is486 ? 13 : 18; + +static int opRETF_a16(uint32_t fetchdat) +{ + RETF_a16(0); + return 0; +} +static int opRETF_a32(uint32_t fetchdat) +{ + RETF_a32(0); + return 0; +} + +static int opRETF_a16_imm(uint32_t fetchdat) +{ + uint16_t offset = getwordf(); + RETF_a16(offset); + return 0; +} +static int opRETF_a32_imm(uint32_t fetchdat) +{ + uint16_t offset = getwordf(); + RETF_a32(offset); + return 0; +} + +static int opIRET(uint32_t fetchdat) +{ + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 0; + } + if (ssegs) ss = oldss; + if (msw&1) + { + optype = IRET; + pmodeiret(0); + optype = 0; + } + else + { + uint16_t new_cs; + oxpc = pc; + if (stack32) + { + pc = readmemw(ss, ESP); + new_cs = readmemw(ss, ESP + 2); + flags = (readmemw(ss, ESP + 4) & 0xffd5) | 2; + ESP += 6; + } + else + { + pc = readmemw(ss, SP); + new_cs = readmemw(ss, ((SP + 2) & 0xffff)); + flags = (readmemw(ss, ((SP + 4) & 0xffff)) & 0xffd5) | 2; + SP += 6; + } + loadcs(new_cs); + } + flags_extract(); + cycles -= is486 ? 15 : 22; + nmi_enable = 1; + return 0; +} + +static int opIRETD(uint32_t fetchdat) +{ + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 0; + } + if (ssegs) ss = oldss; + if (msw & 1) + { + optype = IRET; + pmodeiret(1); + optype = 0; + } + else + { + uint16_t new_cs; + oxpc = pc; + if (stack32) + { + pc = readmeml(ss, ESP); + new_cs = readmemw(ss, ESP + 4); + flags = (readmemw(ss, ESP + 8) & 0xffd5) | 2; + eflags = readmemw(ss, ESP + 10); + ESP += 12; + } + else + { + pc = readmeml(ss, SP); + new_cs = readmemw(ss, ((SP + 4) & 0xffff)); + flags = (readmemw(ss,(SP + 8) & 0xffff) & 0xffd5) | 2; + eflags = readmemw(ss, (SP + 10) & 0xffff); + SP += 12; + } + loadcs(new_cs); + } + flags_extract(); + cycles -= is486 ? 15 : 22; + nmi_enable = 1; + return 0; +} + diff --git a/src/x86_ops_set.h b/src/x86_ops_set.h new file mode 100644 index 0000000..45dfb14 --- /dev/null +++ b/src/x86_ops_set.h @@ -0,0 +1,33 @@ +#define opSET(condition) \ + static int opSET ## condition ## _a16(uint32_t fetchdat) \ + { \ + fetch_ea_16(fetchdat); \ + seteab((cond_ ## condition) ? 1 : 0); \ + cycles -= 4; \ + return 0; \ + } \ + \ + static int opSET ## condition ## _a32(uint32_t fetchdat) \ + { \ + fetch_ea_32(fetchdat); \ + seteab((cond_ ## condition) ? 1 : 0); \ + cycles -= 4; \ + return 0; \ + } + +opSET(O) +opSET(NO) +opSET(B) +opSET(NB) +opSET(E) +opSET(NE) +opSET(BE) +opSET(NBE) +opSET(S) +opSET(NS) +opSET(P) +opSET(NP) +opSET(L) +opSET(NL) +opSET(LE) +opSET(NLE) diff --git a/src/x86_ops_shift.h b/src/x86_ops_shift.h new file mode 100644 index 0000000..953550c --- /dev/null +++ b/src/x86_ops_shift.h @@ -0,0 +1,595 @@ +#define OP_SHIFT_b(c) \ + if (!c) return 0; \ + flags_rebuild(); \ + switch (rmdat & 0x38) \ + { \ + case 0x00: /*ROL b, c*/ \ + while (c > 0) \ + { \ + temp2 = (temp & 0x80) ? 1 : 0; \ + temp = (temp << 1) | temp2; \ + c--; \ + } \ + seteab(temp); if (abrt) return 0; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((flags & C_FLAG) ^ (temp >> 7)) flags |= V_FLAG; \ + cycles -= ((mod == 3) ? 3 : 7); \ + break; \ + case 0x08: /*ROR b,CL*/ \ + while (c > 0) \ + { \ + temp2 = temp & 1; \ + temp >>= 1; \ + if (temp2) temp |= 0x80; \ + c--; \ + } \ + seteab(temp); if (abrt) return 0; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40) flags |= V_FLAG; \ + cycles -= ((mod == 3) ? 3 : 7); \ + break; \ + case 0x10: /*RCL b,CL*/ \ + temp2 = flags & C_FLAG; \ + while (c > 0) \ + { \ + tempc = temp2 ? 1 : 0; \ + temp2 = temp & 0x80; \ + temp = (temp << 1) | tempc; \ + c--; \ + if (is486) cycles--; \ + } \ + seteab(temp); if (abrt) return 0; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((flags & C_FLAG) ^ (temp >> 7)) flags |= V_FLAG; \ + cycles -= ((mod == 3) ? 9 : 10); \ + break; \ + case 0x18: /*RCR b,CL*/ \ + temp2 = flags & C_FLAG; \ + while (c > 0) \ + { \ + tempc = temp2 ? 0x80 : 0; \ + temp2 = temp & 1; \ + temp = (temp >> 1) | tempc; \ + c--; \ + if (is486) cycles--; \ + } \ + seteab(temp); if (abrt) return 0; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40) flags |= V_FLAG; \ + cycles -= ((mod == 3) ? 9 : 10); \ + break; \ + case 0x20: case 0x30: /*SHL b,CL*/ \ + seteab(temp << c); if (abrt) return 0; \ + setznp8(temp << c); \ + if ((temp << (c - 1)) & 0x80) flags |= C_FLAG; \ + if (((temp << c) ^ (temp << (c - 1))) & 0x80) flags |= V_FLAG; \ + cycles -= ((mod == 3) ? 3 : 7); \ + break; \ + case 0x28: /*SHR b,CL*/ \ + seteab(temp >> c); if (abrt) return 0; \ + setznp8(temp >> c); \ + if ((temp >> (c - 1)) & 1) flags |= C_FLAG; \ + if (c == 1 && temp & 0x80) flags |= V_FLAG; \ + cycles -= ((mod == 3) ? 3 : 7); \ + break; \ + case 0x38: /*SAR b,CL*/ \ + tempc = ((temp >> (c - 1)) & 1); \ + while (c > 0) \ + { \ + temp >>= 1; \ + if (temp & 0x40) temp |= 0x80; \ + c--; \ + } \ + seteab(temp); if (abrt) return 0; \ + setznp8(temp); \ + if (tempc) flags |= C_FLAG; \ + cycles -= ((mod == 3) ? 3 : 7); \ + break; \ + } + +#define OP_SHIFT_w(c) \ + if (!c) return 0; \ + flags_rebuild(); \ + switch (rmdat & 0x38) \ + { \ + case 0x00: /*ROL w, c*/ \ + while (c > 0) \ + { \ + temp2 = (temp & 0x8000) ? 1 : 0; \ + temp = (temp << 1) | temp2; \ + c--; \ + } \ + seteaw(temp); if (abrt) return 0; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((flags & C_FLAG) ^ (temp >> 15)) flags |= V_FLAG; \ + cycles -= ((mod == 3) ? 3 : 7); \ + break; \ + case 0x08: /*ROR w, c*/ \ + while (c > 0) \ + { \ + temp2 = temp & 1; \ + temp >>= 1; \ + if (temp2) temp |= 0x8000; \ + c--; \ + } \ + seteaw(temp); if (abrt) return 0; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x4000) flags |= V_FLAG; \ + cycles -= ((mod == 3) ? 3 : 7); \ + break; \ + case 0x10: /*RCL w, c*/ \ + temp2 = flags & C_FLAG; \ + while (c > 0) \ + { \ + tempc = temp2 ? 1 : 0; \ + temp2 = temp & 0x8000; \ + temp = (temp << 1) | tempc; \ + c--; \ + if (is486) cycles--; \ + } \ + seteaw(temp); if (abrt) return 0; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((flags & C_FLAG) ^ (temp >> 15)) flags |= V_FLAG; \ + cycles -= ((mod == 3) ? 9 : 10); \ + break; \ + case 0x18: /*RCR w, c*/ \ + temp2 = flags & C_FLAG; \ + while (c > 0) \ + { \ + tempc = temp2 ? 0x8000 : 0; \ + temp2 = temp & 1; \ + temp = (temp >> 1) | tempc; \ + c--; \ + if (is486) cycles--; \ + } \ + seteaw(temp); if (abrt) return 0; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x4000) flags |= V_FLAG; \ + cycles -= ((mod == 3) ? 9 : 10); \ + break; \ + case 0x20: case 0x30: /*SHL w, c*/ \ + seteaw(temp << c); if (abrt) return 0; \ + setznp16(temp << c); \ + if ((temp << (c - 1)) & 0x8000) flags |= C_FLAG; \ + if (((temp << c) ^ (temp << (c - 1))) & 0x8000) flags |= V_FLAG;\ + cycles -= ((mod == 3) ? 3 : 7); \ + break; \ + case 0x28: /*SHR w, c*/ \ + seteaw(temp >> c); if (abrt) return 0; \ + setznp16(temp >> c); \ + if ((temp >> (c - 1)) & 1) flags |= C_FLAG; \ + if (c == 1 && temp & 0x8000) flags |= V_FLAG; \ + cycles -= ((mod == 3) ? 3 : 7); \ + break; \ + case 0x38: /*SAR w, c*/ \ + tempc = ((temp >> (c - 1)) & 1); \ + while (c > 0) \ + { \ + temp >>= 1; \ + if (temp & 0x4000) temp |= 0x8000; \ + c--; \ + } \ + seteaw(temp); if (abrt) return 0; \ + setznp16(temp); \ + if (tempc) flags |= C_FLAG; \ + cycles -= ((mod == 3) ? 3 : 7); \ + break; \ + } + +#define OP_SHIFT_l(c) \ + if (!c) return 0; \ + flags_rebuild(); \ + switch (rmdat & 0x38) \ + { \ + case 0x00: /*ROL l, c*/ \ + while (c > 0) \ + { \ + temp2 = (temp & 0x80000000) ? 1 : 0; \ + temp = (temp << 1) | temp2; \ + c--; \ + } \ + seteal(temp); if (abrt) return 0; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((flags & C_FLAG) ^ (temp >> 31)) flags |= V_FLAG; \ + cycles -= ((mod == 3) ? 3 : 7); \ + break; \ + case 0x08: /*ROR l, c*/ \ + while (c > 0) \ + { \ + temp2 = temp & 1; \ + temp >>= 1; \ + if (temp2) temp |= 0x80000000; \ + c--; \ + } \ + seteal(temp); if (abrt) return 0; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40000000) flags |= V_FLAG; \ + cycles -= ((mod == 3) ? 3 : 7); \ + break; \ + case 0x10: /*RCL l, c*/ \ + temp2 = flags & C_FLAG; \ + while (c > 0) \ + { \ + tempc = temp2 ? 1 : 0; \ + temp2 = temp & 0x80000000; \ + temp = (temp << 1) | tempc; \ + c--; \ + if (is486) cycles--; \ + } \ + seteal(temp); if (abrt) return 0; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((flags & C_FLAG) ^ (temp >> 31)) flags |= V_FLAG; \ + cycles -= ((mod == 3) ? 9 : 10); \ + break; \ + case 0x18: /*RCR l, c*/ \ + temp2 = flags & C_FLAG; \ + while (c > 0) \ + { \ + tempc = temp2 ? 0x80000000 : 0; \ + temp2 = temp & 1; \ + temp = (temp >> 1) | tempc; \ + c--; \ + if (is486) cycles--; \ + } \ + seteal(temp); if (abrt) return 0; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40000000) flags |= V_FLAG; \ + cycles -= ((mod == 3) ? 9 : 10); \ + break; \ + case 0x20: case 0x30: /*SHL l, c*/ \ + seteal(temp << c); if (abrt) return 0; \ + setznp32(temp << c); \ + if ((temp << (c - 1)) & 0x80000000) flags |= C_FLAG; \ + if (((temp << c) ^ (temp << (c - 1))) & 0x80000000) flags |= V_FLAG;\ + cycles -= ((mod == 3) ? 3 : 7); \ + break; \ + case 0x28: /*SHR l, c*/ \ + seteal(temp >> c); if (abrt) return 0; \ + setznp32(temp >> c); \ + if ((temp >> (c - 1)) & 1) flags |= C_FLAG; \ + if (c == 1 && temp & 0x80000000) flags |= V_FLAG; \ + cycles -= ((mod == 3) ? 3 : 7); \ + break; \ + case 0x38: /*SAR l, c*/ \ + tempc = ((temp >> (c - 1)) & 1); \ + while (c > 0) \ + { \ + temp >>= 1; \ + if (temp & 0x40000000) temp |= 0x80000000; \ + c--; \ + } \ + seteal(temp); if (abrt) return 0; \ + setznp32(temp); \ + if (tempc) flags |= C_FLAG; \ + cycles -= ((mod == 3) ? 3 : 7); \ + break; \ + } + +static int opC0_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint8_t temp, temp2; + + fetch_ea_16(fetchdat); + c = readmemb(cs, pc) & 31; pc++; + temp = geteab(); if (abrt) return 0; + OP_SHIFT_b(c); + return 0; +} +static int opC0_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint8_t temp, temp2; + + fetch_ea_32(fetchdat); + c = readmemb(cs, pc) & 31; pc++; + temp = geteab(); if (abrt) return 0; + OP_SHIFT_b(c); + return 0; +} +static int opC1_w_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint16_t temp, temp2; + + fetch_ea_16(fetchdat); + c = readmemb(cs, pc) & 31; pc++; + temp = geteaw(); if (abrt) return 0; + OP_SHIFT_w(c); + return 0; +} +static int opC1_w_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint16_t temp, temp2; + + fetch_ea_32(fetchdat); + c = readmemb(cs, pc) & 31; pc++; + temp = geteaw(); if (abrt) return 0; + OP_SHIFT_w(c); + return 0; +} +static int opC1_l_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint32_t temp, temp2; + + fetch_ea_16(fetchdat); + c = readmemb(cs, pc) & 31; pc++; + temp = geteal(); if (abrt) return 0; + OP_SHIFT_l(c); + return 0; +} +static int opC1_l_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint32_t temp, temp2; + + fetch_ea_32(fetchdat); + c = readmemb(cs, pc) & 31; pc++; + temp = geteal(); if (abrt) return 0; + OP_SHIFT_l(c); + return 0; +} + +static int opD0_a16(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint8_t temp, temp2; + + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 0; + OP_SHIFT_b(c); + return 0; +} +static int opD0_a32(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint8_t temp, temp2; + + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 0; + OP_SHIFT_b(c); + return 0; +} +static int opD1_w_a16(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint16_t temp, temp2; + + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 0; + OP_SHIFT_w(c); + return 0; +} +static int opD1_w_a32(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint16_t temp, temp2; + + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 0; + OP_SHIFT_w(c); + return 0; +} +static int opD1_l_a16(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint32_t temp, temp2; + + fetch_ea_16(fetchdat); + temp = geteal(); if (abrt) return 0; + OP_SHIFT_l(c); + return 0; +} +static int opD1_l_a32(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint32_t temp, temp2; + + fetch_ea_32(fetchdat); + temp = geteal(); if (abrt) return 0; + OP_SHIFT_l(c); + return 0; +} + +static int opD2_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint8_t temp, temp2; + + fetch_ea_16(fetchdat); + c = CL & 31; + temp = geteab(); if (abrt) return 0; + OP_SHIFT_b(c); + return 0; +} +static int opD2_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint8_t temp, temp2; + + fetch_ea_32(fetchdat); + c = CL & 31; + temp = geteab(); if (abrt) return 0; + OP_SHIFT_b(c); + return 0; +} +static int opD3_w_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint16_t temp, temp2; + + fetch_ea_16(fetchdat); + c = CL & 31; + temp = geteaw(); if (abrt) return 0; + OP_SHIFT_w(c); + return 0; +} +static int opD3_w_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint16_t temp, temp2; + + fetch_ea_32(fetchdat); + c = CL & 31; + temp = geteaw(); if (abrt) return 0; + OP_SHIFT_w(c); + return 0; +} +static int opD3_l_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint32_t temp, temp2; + + fetch_ea_16(fetchdat); + c = CL & 31; + temp = geteal(); if (abrt) return 0; + OP_SHIFT_l(c); + return 0; +} +static int opD3_l_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint32_t temp, temp2; + + fetch_ea_32(fetchdat); + c = CL & 31; + temp = geteal(); if (abrt) return 0; + OP_SHIFT_l(c); + return 0; +} + + +#define SHLD_w() \ + if (count) \ + { \ + uint16_t tempw = geteaw(); if (abrt) return 0; \ + int tempc = ((tempw << (count - 1)) & (1 << 15)) ? 1 : 0; \ + uint32_t templ = (tempw << 16) | regs[reg].w; \ + if (count <= 16) tempw = templ >> (16 - count); \ + else tempw = (templ << count) >> 16; \ + seteaw(tempw); if (abrt) return 0; \ + setznp16(tempw); \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + } + +#define SHLD_l() \ + if (count) \ + { \ + uint32_t templ = geteal(); if (abrt) return 0; \ + int tempc = ((templ << (count - 1)) & (1 << 31)) ? 1 : 0; \ + templ = (templ << count) | (regs[reg].l >> (32 - count)); \ + seteal(templ); if (abrt) return 0; \ + setznp32(templ); \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + } + + +#define SHRD_w() \ + if (count) \ + { \ + uint16_t tempw = geteaw(); if (abrt) return 0; \ + int tempc = (tempw >> (count - 1)) & 1; \ + uint32_t templ = tempw | (regs[reg].w << 16); \ + tempw = templ >> count; \ + seteaw(tempw); if (abrt) return 0; \ + setznp16(tempw); \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + } + +#define SHRD_l() \ + if (count) \ + { \ + uint32_t templ = geteal(); if (abrt) return 0; \ + int tempc = (templ >> (count - 1)) & 1; \ + templ = (templ >> count) | (regs[reg].l << (32 - count)); \ + seteal(templ); if (abrt) return 0; \ + setznp32(templ); \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + } + +#define opSHxD(operation) \ + static int op ## operation ## _i_a16(uint32_t fetchdat) \ + { \ + int count; \ + \ + fetch_ea_16(fetchdat); \ + count = getbyte() & 31; \ + operation(); \ + \ + cycles -= 3; \ + return 0; \ + } \ + static int op ## operation ## _CL_a16(uint32_t fetchdat) \ + { \ + int count; \ + \ + fetch_ea_16(fetchdat); \ + count = CL & 31; \ + operation(); \ + \ + cycles -= 3; \ + return 0; \ + } \ + static int op ## operation ## _i_a32(uint32_t fetchdat) \ + { \ + int count; \ + \ + fetch_ea_32(fetchdat); \ + count = getbyte() & 31; \ + operation(); \ + \ + cycles -= 3; \ + return 0; \ + } \ + static int op ## operation ## _CL_a32(uint32_t fetchdat) \ + { \ + int count; \ + \ + fetch_ea_32(fetchdat); \ + count = CL & 31; \ + operation(); \ + \ + cycles -= 3; \ + return 0; \ + } + +opSHxD(SHLD_w) +opSHxD(SHLD_l) +opSHxD(SHRD_w) +opSHxD(SHRD_l) diff --git a/src/x86_ops_stack.h b/src/x86_ops_stack.h new file mode 100644 index 0000000..c2de948 --- /dev/null +++ b/src/x86_ops_stack.h @@ -0,0 +1,447 @@ +#define PUSH_W_OP(reg) \ + static int opPUSH_ ## reg (uint32_t fetchdat) \ + { \ + if (ssegs) ss=oldss; \ + PUSH_W(reg); \ + cycles -= (is486) ? 1 : 2; \ + return 0; \ + } + +#define PUSH_L_OP(reg) \ + static int opPUSH_ ## reg (uint32_t fetchdat) \ + { \ + if (ssegs) ss=oldss; \ + PUSH_L(reg); \ + cycles -= (is486) ? 1 : 2; \ + return 0; \ + } + +#define POP_W_OP(reg) \ + static int opPOP_ ## reg (uint32_t fetchdat) \ + { \ + if (ssegs) ss=oldss; \ + reg = POP_W(); \ + cycles -= (is486) ? 1 : 4; \ + return 0; \ + } + +#define POP_L_OP(reg) \ + static int opPOP_ ## reg (uint32_t fetchdat) \ + { \ + if (ssegs) ss=oldss; \ + reg = POP_L(); \ + cycles -= (is486) ? 1 : 4; \ + return 0; \ + } + +PUSH_W_OP(AX) +PUSH_W_OP(BX) +PUSH_W_OP(CX) +PUSH_W_OP(DX) +PUSH_W_OP(SI) +PUSH_W_OP(DI) +PUSH_W_OP(BP) +PUSH_W_OP(SP) + +PUSH_L_OP(EAX) +PUSH_L_OP(EBX) +PUSH_L_OP(ECX) +PUSH_L_OP(EDX) +PUSH_L_OP(ESI) +PUSH_L_OP(EDI) +PUSH_L_OP(EBP) +PUSH_L_OP(ESP) + +POP_W_OP(AX) +POP_W_OP(BX) +POP_W_OP(CX) +POP_W_OP(DX) +POP_W_OP(SI) +POP_W_OP(DI) +POP_W_OP(BP) +POP_W_OP(SP) + +POP_L_OP(EAX) +POP_L_OP(EBX) +POP_L_OP(ECX) +POP_L_OP(EDX) +POP_L_OP(ESI) +POP_L_OP(EDI) +POP_L_OP(EBP) +POP_L_OP(ESP) + + +static int opPUSHA_w(uint32_t fetchdat) +{ + if (stack32) + { + writememw(ss, ESP - 2, AX); + writememw(ss, ESP - 4, CX); + writememw(ss, ESP - 6, DX); + writememw(ss, ESP - 8, BX); + writememw(ss, ESP - 10, SP); + writememw(ss, ESP - 12, BP); + writememw(ss, ESP - 14, SI); + writememw(ss, ESP - 16, DI); + if (!abrt) ESP -= 16; + } + else + { + writememw(ss, ((SP - 2) & 0xFFFF), AX); + writememw(ss, ((SP - 4) & 0xFFFF), CX); + writememw(ss, ((SP - 6) & 0xFFFF), DX); + writememw(ss, ((SP - 8) & 0xFFFF), BX); + writememw(ss, ((SP - 10) & 0xFFFF), SP); + writememw(ss, ((SP - 12) & 0xFFFF), BP); + writememw(ss, ((SP - 14) & 0xFFFF), SI); + writememw(ss, ((SP - 16) & 0xFFFF), DI); + if (!abrt) SP -= 16; + } + cycles -= (is486) ? 11 : 18; + return 0; +} +static int opPUSHA_l(uint32_t fetchdat) +{ + if (stack32) + { + writememl(ss, ESP - 4, EAX); + writememl(ss, ESP - 8, ECX); + writememl(ss, ESP - 12, EDX); + writememl(ss, ESP - 16, EBX); + writememl(ss, ESP - 20, ESP); + writememl(ss, ESP - 24, EBP); + writememl(ss, ESP - 28, ESI); + writememl(ss, ESP - 32, EDI); + if (!abrt) ESP -= 32; + } + else + { + writememl(ss, ((SP - 4) & 0xFFFF), EAX); + writememl(ss, ((SP - 8) & 0xFFFF), ECX); + writememl(ss, ((SP - 12) & 0xFFFF), EDX); + writememl(ss, ((SP - 16) & 0xFFFF), EBX); + writememl(ss, ((SP - 20) & 0xFFFF), ESP); + writememl(ss, ((SP - 24) & 0xFFFF), EBP); + writememl(ss, ((SP - 28) & 0xFFFF), ESI); + writememl(ss, ((SP - 32) & 0xFFFF), EDI); + if (!abrt) SP -= 32; + } + cycles -= (is486) ? 11 : 18; + return 0; +} + +static int opPOPA_w(uint32_t fetchdat) +{ + if (stack32) + { + DI = readmemw(ss, ESP); if (abrt) return 0; + SI = readmemw(ss, ESP + 2); if (abrt) return 0; + BP = readmemw(ss, ESP + 4); if (abrt) return 0; + BX = readmemw(ss, ESP + 8); if (abrt) return 0; + DX = readmemw(ss, ESP + 10); if (abrt) return 0; + CX = readmemw(ss, ESP + 12); if (abrt) return 0; + AX = readmemw(ss, ESP + 14); if (abrt) return 0; + ESP += 16; + } + else + { + DI = readmemw(ss, ((SP) & 0xFFFF)); if (abrt) return 0; + SI = readmemw(ss, ((SP + 2) & 0xFFFF)); if (abrt) return 0; + BP = readmemw(ss, ((SP + 4) & 0xFFFF)); if (abrt) return 0; + BX = readmemw(ss, ((SP + 8) & 0xFFFF)); if (abrt) return 0; + DX = readmemw(ss, ((SP + 10) & 0xFFFF)); if (abrt) return 0; + CX = readmemw(ss, ((SP + 12) & 0xFFFF)); if (abrt) return 0; + AX = readmemw(ss, ((SP + 14) & 0xFFFF)); if (abrt) return 0; + SP += 16; + } + cycles -= (is486) ? 9 : 24; + return 0; +} +static int opPOPA_l(uint32_t fetchdat) +{ + if (stack32) + { + EDI = readmeml(ss, ESP); if (abrt) return 0; + ESI = readmeml(ss, ESP + 4); if (abrt) return 0; + EBP = readmeml(ss, ESP + 8); if (abrt) return 0; + EBX = readmeml(ss, ESP + 16); if (abrt) return 0; + EDX = readmeml(ss, ESP + 20); if (abrt) return 0; + ECX = readmeml(ss, ESP + 24); if (abrt) return 0; + EAX = readmeml(ss, ESP + 28); if (abrt) return 0; + ESP += 32; + } + else + { + EDI = readmeml(ss, ((SP) & 0xFFFF)); if (abrt) return 0; + ESI = readmeml(ss, ((SP + 4) & 0xFFFF)); if (abrt) return 0; + EBP = readmeml(ss, ((SP + 8) & 0xFFFF)); if (abrt) return 0; + EBX = readmeml(ss, ((SP + 16) & 0xFFFF)); if (abrt) return 0; + EDX = readmeml(ss, ((SP + 20) & 0xFFFF)); if (abrt) return 0; + ECX = readmeml(ss, ((SP + 24) & 0xFFFF)); if (abrt) return 0; + EAX = readmeml(ss, ((SP + 28) & 0xFFFF)); if (abrt) return 0; + SP += 32; + } + cycles -= (is486) ? 9 : 24; + return 0; +} + +static int opPUSH_imm_w(uint32_t fetchdat) +{ + uint16_t val = getwordf(); + if (ssegs) ss=oldss; + PUSH_W(val); + cycles -= 2; + return 0; +} +static int opPUSH_imm_l(uint32_t fetchdat) +{ + uint32_t val = getlong(); + if (ssegs) ss=oldss; + PUSH_L(val); + cycles -= 2; + return 0; +} + +static int opPUSH_imm_bw(uint32_t fetchdat) +{ + uint16_t tempw = getbytef(); + + if (tempw & 0x80) tempw |= 0xFF00; + PUSH_W(tempw); + + cycles -= 2; + return 0; +} +static int opPUSH_imm_bl(uint32_t fetchdat) +{ + uint32_t templ = getbytef(); + + if (templ & 0x80) templ |= 0xFFFFFF00; + PUSH_L(templ); + + cycles -= 2; + return 0; +} + +static int opPOPW_a16(uint32_t fetchdat) +{ + uint16_t temp; + + if (ssegs) ss=oldss; + temp = POP_W(); if (abrt) return 0; + fetch_ea_16(fetchdat); + seteaw(temp); + if (abrt) + { + if (stack32) ESP -= 2; + else SP -= 2; + } + + if (is486) cycles -= ((mod == 3) ? 1 : 6); + else cycles -= ((mod == 3) ? 4 : 5); + return 0; +} +static int opPOPW_a32(uint32_t fetchdat) +{ + uint16_t temp; + + if (ssegs) ss=oldss; + temp = POP_W(); if (abrt) return 0; + fetch_ea_32(fetchdat); + seteaw(temp); + if (abrt) + { + if (stack32) ESP -= 2; + else SP -= 2; + } + + if (is486) cycles -= ((mod == 3) ? 1 : 6); + else cycles -= ((mod == 3) ? 4 : 5); + return 0; +} + +static int opPOPL_a16(uint32_t fetchdat) +{ + uint32_t temp; + + if (ssegs) ss=oldss; + temp = POP_L(); if (abrt) return 0; + fetch_ea_16(fetchdat); + seteal(temp); + if (abrt) + { + if (stack32) ESP -= 4; + else SP -= 4; + } + + if (is486) cycles -= ((mod == 3) ? 1 : 6); + else cycles -= ((mod == 3) ? 4 : 5); + return 0; +} +static int opPOPL_a32(uint32_t fetchdat) +{ + uint32_t temp; + + if (ssegs) ss=oldss; + temp = POP_L(); if (abrt) return 0; + fetch_ea_32(fetchdat); + seteal(temp); + if (abrt) + { + if (stack32) ESP -= 4; + else SP -= 4; + } + + if (is486) cycles -= ((mod == 3) ? 1 : 6); + else cycles -= ((mod == 3) ? 4 : 5); + return 0; +} + + +static int opENTER_w(uint32_t fetchdat) +{ + uint16_t offset = getwordf(); + int count = (fetchdat >> 16) & 0xff; pc++; + uint32_t tempEBP = EBP, tempESP = ESP, frame_ptr; + + PUSH_W(BP); + frame_ptr = ESP; + + if (count > 0) + { + while (--count) + { + uint16_t tempw; + + BP -= 2; + tempw = readmemw(ss, BP); + if (abrt) { ESP = tempESP; EBP = tempEBP; return 0; } + PUSH_W(tempw); + if (abrt) { ESP = tempESP; EBP = tempEBP; return 0; } + cycles -= (is486) ? 3 : 4; + } + PUSH_W(frame_ptr); + if (abrt) { ESP = tempESP; EBP = tempEBP; return 0; } + cycles -= (is486) ? 3 : 5; + } + BP = frame_ptr; + + if (stack32) ESP -= offset; + else SP -= offset; + cycles -= (is486) ? 14 : 10; + return 0; +} +static int opENTER_l(uint32_t fetchdat) +{ + uint16_t offset = getwordf(); + int count = (fetchdat >> 16) & 0xff; pc++; + uint32_t tempEBP = EBP, tempESP = ESP, frame_ptr; + + PUSH_L(EBP); + frame_ptr = ESP; + + if (count > 0) + { + while (--count) + { + uint32_t templ; + + EBP -= 4; + templ = readmeml(ss, EBP); + if (abrt) { ESP = tempESP; EBP = tempEBP; return 0; } + PUSH_L(templ); + if (abrt) { ESP = tempESP; EBP = tempEBP; return 0; } + cycles -= (is486) ? 3 : 4; + } + PUSH_L(frame_ptr); + if (abrt) { ESP = tempESP; EBP = tempEBP; return 0; } + cycles -= (is486) ? 3 : 5; + } + EBP = frame_ptr; + + if (stack32) ESP -= offset; + else SP -= offset; + cycles -= (is486) ? 14 : 10; + return 0; +} + + +static int opLEAVE_w(uint32_t fetchdat) +{ + uint32_t tempESP = ESP; + uint16_t temp; + + SP = BP; + temp = POP_W(); + if (abrt) { ESP = tempESP; return 0; } + BP = temp; + + cycles -= 4; + return 0; +} +static int opLEAVE_l(uint32_t fetchdat) +{ + uint32_t tempESP = ESP; + uint32_t temp; + + ESP = EBP; + temp = POP_L(); + if (abrt) { ESP = tempESP; return 0; } + EBP = temp; + + cycles -= 4; + return 0; +} + + +#define PUSH_SEG_OPS(seg) \ + static int opPUSH_ ## seg ## _w(uint32_t fetchdat) \ + { \ + if (ssegs) ss=oldss; \ + PUSH_W(seg); \ + cycles -= 2; \ + return 0; \ + } \ + static int opPUSH_ ## seg ## _l(uint32_t fetchdat) \ + { \ + if (ssegs) ss=oldss; \ + PUSH_L(seg); \ + cycles -= 2; \ + return 0; \ + } + +#define POP_SEG_OPS(seg, realseg) \ + static int opPOP_ ## seg ## _w(uint32_t fetchdat) \ + { \ + uint16_t temp_seg; \ + uint32_t temp_esp = ESP; \ + if (ssegs) ss=oldss; \ + temp_seg = POP_W(); if (abrt) return 0; \ + loadseg(temp_seg, realseg); if (abrt) ESP = temp_esp; \ + cycles -= is486 ? 3 : 7; \ + return 0; \ + } \ + static int opPOP_ ## seg ## _l(uint32_t fetchdat) \ + { \ + uint32_t temp_seg; \ + uint32_t temp_esp = ESP; \ + if (ssegs) ss=oldss; \ + temp_seg = POP_L(); if (abrt) return 0; \ + loadseg(temp_seg & 0xffff, realseg); if (abrt) ESP = temp_esp; \ + cycles -= is486 ? 3 : 7; \ + return 0; \ + } + + +PUSH_SEG_OPS(CS); +PUSH_SEG_OPS(DS); +PUSH_SEG_OPS(ES); +PUSH_SEG_OPS(FS); +PUSH_SEG_OPS(GS); +PUSH_SEG_OPS(SS); + +POP_SEG_OPS(DS, &_ds); +POP_SEG_OPS(ES, &_es); +POP_SEG_OPS(FS, &_fs); +POP_SEG_OPS(GS, &_gs); +POP_SEG_OPS(SS, &_ss); diff --git a/src/x86_ops_string.h b/src/x86_ops_string.h new file mode 100644 index 0000000..553af9c --- /dev/null +++ b/src/x86_ops_string.h @@ -0,0 +1,435 @@ +static int opMOVSB_a16(uint32_t fetchdat) +{ + uint8_t temp = readmemb(ds,SI); if (abrt) return 0; + writememb(es, DI, temp); if (abrt) return 0; + if (flags & D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + cycles -= 7; + return 0; +} +static int opMOVSB_a32(uint32_t fetchdat) +{ + uint8_t temp = readmemb(ds,ESI); if (abrt) return 0; + writememb(es, EDI, temp); if (abrt) return 0; + if (flags & D_FLAG) { EDI--; ESI--; } + else { EDI++; ESI++; } + cycles -= 7; + return 0; +} + +static int opMOVSW_a16(uint32_t fetchdat) +{ + uint16_t temp = readmemw(ds,SI); if (abrt) return 0; + writememw(es, DI, temp); if (abrt) return 0; + if (flags & D_FLAG) { DI -= 2; SI -= 2; } + else { DI += 2; SI += 2; } + cycles -= 7; + return 0; +} +static int opMOVSW_a32(uint32_t fetchdat) +{ + uint16_t temp = readmemw(ds,ESI); if (abrt) return 0; + writememw(es, EDI, temp); if (abrt) return 0; + if (flags & D_FLAG) { EDI -= 2; ESI -= 2; } + else { EDI += 2; ESI += 2; } + cycles -= 7; + return 0; +} + +static int opMOVSL_a16(uint32_t fetchdat) +{ + uint32_t temp = readmeml(ds,SI); if (abrt) return 0; + writememl(es, DI, temp); if (abrt) return 0; + if (flags & D_FLAG) { DI -= 4; SI -= 4; } + else { DI += 4; SI += 4; } + cycles -= 7; + return 0; +} +static int opMOVSL_a32(uint32_t fetchdat) +{ + uint32_t temp = readmeml(ds,ESI); if (abrt) return 0; + writememl(es, EDI, temp); if (abrt) return 0; + if (flags & D_FLAG) { EDI -= 4; ESI -= 4; } + else { EDI += 4; ESI += 4; } + cycles -= 7; + return 0; +} + + +static int opCMPSB_a16(uint32_t fetchdat) +{ + uint8_t src = readmemb(ds, SI); + uint8_t dst = readmemb(es, DI); if (abrt) return 0; + setsub8(src, dst); + if (flags & D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + cycles -= (is486) ? 8 : 10; + return 0; +} +static int opCMPSB_a32(uint32_t fetchdat) +{ + uint8_t src = readmemb(ds, ESI); + uint8_t dst = readmemb(es, EDI); if (abrt) return 0; + setsub8(src, dst); + if (flags & D_FLAG) { EDI--; ESI--; } + else { EDI++; ESI++; } + cycles -= (is486) ? 8 : 10; + return 0; +} + +static int opCMPSW_a16(uint32_t fetchdat) +{ + uint16_t src = readmemw(ds, SI); + uint16_t dst = readmemw(es, DI); if (abrt) return 0; + setsub16(src, dst); + if (flags & D_FLAG) { DI -= 2; SI -= 2; } + else { DI += 2; SI += 2; } + cycles -= (is486) ? 8 : 10; + return 0; +} +static int opCMPSW_a32(uint32_t fetchdat) +{ + uint16_t src = readmemw(ds, ESI); + uint16_t dst = readmemw(es, EDI); if (abrt) return 0; + setsub16(src, dst); + if (flags & D_FLAG) { EDI -= 2; ESI -= 2; } + else { EDI += 2; ESI += 2; } + cycles -= (is486) ? 8 : 10; + return 0; +} + +static int opCMPSL_a16(uint32_t fetchdat) +{ + uint32_t src = readmeml(ds, SI); + uint32_t dst = readmeml(es, DI); if (abrt) return 0; + setsub32(src, dst); + if (flags & D_FLAG) { DI -= 4; SI -= 4; } + else { DI += 4; SI += 4; } + cycles -= (is486) ? 8 : 10; + return 0; +} +static int opCMPSL_a32(uint32_t fetchdat) +{ + uint32_t src = readmeml(ds, ESI); + uint32_t dst = readmeml(es, EDI); if (abrt) return 0; + setsub32(src, dst); + if (flags & D_FLAG) { EDI -= 4; ESI -= 4; } + else { EDI += 4; ESI += 4; } + cycles -= (is486) ? 8 : 10; + return 0; +} + +static int opSTOSB_a16(uint32_t fetchdat) +{ + writememb(es, DI, AL); if (abrt) return 0; + if (flags & D_FLAG) DI--; + else DI++; + cycles -= 4; + return 0; +} +static int opSTOSB_a32(uint32_t fetchdat) +{ + writememb(es, EDI, AL); if (abrt) return 0; + if (flags & D_FLAG) EDI--; + else EDI++; + cycles -= 4; + return 0; +} + +static int opSTOSW_a16(uint32_t fetchdat) +{ + writememw(es, DI, AX); if (abrt) return 0; + if (flags & D_FLAG) DI -= 2; + else DI += 2; + cycles -= 4; + return 0; +} +static int opSTOSW_a32(uint32_t fetchdat) +{ + writememw(es, EDI, AX); if (abrt) return 0; + if (flags & D_FLAG) EDI -= 2; + else EDI += 2; + cycles -= 4; + return 0; +} + +static int opSTOSL_a16(uint32_t fetchdat) +{ + writememl(es, DI, EAX); if (abrt) return 0; + if (flags & D_FLAG) DI -= 4; + else DI += 4; + cycles -= 4; + return 0; +} +static int opSTOSL_a32(uint32_t fetchdat) +{ + writememl(es, EDI, EAX); if (abrt) return 0; + if (flags & D_FLAG) EDI -= 4; + else EDI += 4; + cycles -= 4; + return 0; +} + + +static int opLODSB_a16(uint32_t fetchdat) +{ + uint8_t temp = readmemb(ds, SI); if (abrt) return 0; + AL = temp; + if (flags & D_FLAG) SI--; + else SI++; + cycles -= 5; + return 0; +} +static int opLODSB_a32(uint32_t fetchdat) +{ + uint8_t temp = readmemb(ds, ESI); if (abrt) return 0; + AL = temp; + if (flags & D_FLAG) ESI--; + else ESI++; + cycles -= 5; + return 0; +} + +static int opLODSW_a16(uint32_t fetchdat) +{ + uint16_t temp = readmemw(ds, SI); if (abrt) return 0; + AX = temp; + if (flags & D_FLAG) SI -= 2; + else SI += 2; + cycles -= 5; + return 0; +} +static int opLODSW_a32(uint32_t fetchdat) +{ + uint16_t temp = readmemw(ds, ESI); if (abrt) return 0; + AX = temp; + if (flags & D_FLAG) ESI -= 2; + else ESI += 2; + cycles -= 5; + return 0; +} + +static int opLODSL_a16(uint32_t fetchdat) +{ + uint32_t temp = readmeml(ds, SI); if (abrt) return 0; + EAX = temp; + if (flags & D_FLAG) SI -= 4; + else SI += 4; + cycles -= 5; + return 0; +} +static int opLODSL_a32(uint32_t fetchdat) +{ + uint32_t temp = readmeml(ds, ESI); if (abrt) return 0; + EAX = temp; + if (flags & D_FLAG) ESI -= 4; + else ESI += 4; + cycles -= 5; + return 0; +} + + +static int opSCASB_a16(uint32_t fetchdat) +{ + uint8_t temp = readmemb(es, DI); if (abrt) return 0; + setsub8(AL, temp); + if (flags & D_FLAG) DI--; + else DI++; + cycles -= 7; + return 0; +} +static int opSCASB_a32(uint32_t fetchdat) +{ + uint8_t temp = readmemb(es, EDI); if (abrt) return 0; + setsub8(AL, temp); + if (flags & D_FLAG) EDI--; + else EDI++; + cycles -= 7; + return 0; +} + +static int opSCASW_a16(uint32_t fetchdat) +{ + uint16_t temp = readmemw(es, DI); if (abrt) return 0; + setsub16(AX, temp); + if (flags & D_FLAG) DI -= 2; + else DI += 2; + cycles -= 7; + return 0; +} +static int opSCASW_a32(uint32_t fetchdat) +{ + uint16_t temp = readmemw(es, EDI); if (abrt) return 0; + setsub16(AX, temp); + if (flags & D_FLAG) EDI -= 2; + else EDI += 2; + cycles -= 7; + return 0; +} + +static int opSCASL_a16(uint32_t fetchdat) +{ + uint32_t temp = readmeml(es, DI); if (abrt) return 0; + setsub32(EAX, temp); + if (flags & D_FLAG) DI -= 4; + else DI += 4; + cycles -= 7; + return 0; +} +static int opSCASL_a32(uint32_t fetchdat) +{ + uint32_t temp = readmeml(es, EDI); if (abrt) return 0; + setsub32(EAX, temp); + if (flags & D_FLAG) EDI -= 4; + else EDI += 4; + cycles -= 7; + return 0; +} + +static int opINSB_a16(uint32_t fetchdat) +{ + uint8_t temp; + check_io_perm(DX); + temp = inb(DX); + writememb(es, DI, temp); if (abrt) return 0; + if (flags & D_FLAG) DI--; + else DI++; + cycles -= 15; + return 0; +} +static int opINSB_a32(uint32_t fetchdat) +{ + uint8_t temp; + check_io_perm(DX); + temp = inb(DX); + writememb(es, EDI, temp); if (abrt) return 0; + if (flags & D_FLAG) EDI--; + else EDI++; + cycles -= 15; + return 0; +} + +static int opINSW_a16(uint32_t fetchdat) +{ + uint16_t temp; + check_io_perm(DX); + check_io_perm(DX + 1); + temp = inw(DX); + writememw(es, DI, temp); if (abrt) return 0; + if (flags & D_FLAG) DI -= 2; + else DI += 2; + cycles -= 15; + return 0; +} +static int opINSW_a32(uint32_t fetchdat) +{ + uint16_t temp; + check_io_perm(DX); + check_io_perm(DX + 1); + temp = inw(DX); + writememw(es, EDI, temp); if (abrt) return 0; + if (flags & D_FLAG) EDI -= 2; + else EDI += 2; + cycles -= 15; + return 0; +} + +static int opINSL_a16(uint32_t fetchdat) +{ + uint32_t temp; + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + temp = inl(DX); + writememl(es, DI, temp); if (abrt) return 0; + if (flags & D_FLAG) DI -= 4; + else DI += 4; + cycles -= 15; + return 0; +} +static int opINSL_a32(uint32_t fetchdat) +{ + uint32_t temp; + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + temp = inl(DX); + writememl(es, EDI, temp); if (abrt) return 0; + if (flags & D_FLAG) EDI -= 4; + else EDI += 4; + cycles -= 15; + return 0; +} + +static int opOUTSB_a16(uint32_t fetchdat) +{ + uint8_t temp = readmemb(ds, SI); if (abrt) return 0; + check_io_perm(DX); + if (flags & D_FLAG) SI--; + else SI++; + outb(DX, temp); + cycles -= 14; + return 0; +} +static int opOUTSB_a32(uint32_t fetchdat) +{ + uint8_t temp = readmemb(ds, ESI); if (abrt) return 0; + check_io_perm(DX); + if (flags & D_FLAG) ESI--; + else ESI++; + outb(DX, temp); + cycles -= 14; + return 0; +} + +static int opOUTSW_a16(uint32_t fetchdat) +{ + uint16_t temp = readmemw(ds, SI); if (abrt) return 0; + check_io_perm(DX); + check_io_perm(DX + 1); + if (flags & D_FLAG) SI -= 2; + else SI += 2; + outw(DX, temp); + cycles -= 14; + return 0; +} +static int opOUTSW_a32(uint32_t fetchdat) +{ + uint16_t temp = readmemw(ds, ESI); if (abrt) return 0; + check_io_perm(DX); + check_io_perm(DX + 1); + if (flags & D_FLAG) ESI -= 2; + else ESI += 2; + outw(DX, temp); + cycles -= 14; + return 0; +} + +static int opOUTSL_a16(uint32_t fetchdat) +{ + uint32_t temp = readmeml(ds, SI); if (abrt) return 0; + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + if (flags & D_FLAG) SI -= 4; + else SI += 4; + outl(EDX, temp); + cycles -= 14; + return 0; +} +static int opOUTSL_a32(uint32_t fetchdat) +{ + uint32_t temp = readmeml(ds, ESI); if (abrt) return 0; + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + if (flags & D_FLAG) ESI -= 4; + else ESI += 4; + outl(EDX, temp); + cycles -= 14; + return 0; +} diff --git a/src/x86_ops_xchg.h b/src/x86_ops_xchg.h new file mode 100644 index 0000000..49174fb --- /dev/null +++ b/src/x86_ops_xchg.h @@ -0,0 +1,195 @@ +static int opXCHG_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 0; + seteab(getr8(reg)); if (abrt) return 0; + setr8(reg, temp); + cycles -= ((mod == 3) ? 3 : 5); + return 0; +} +static int opXCHG_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 0; + seteab(getr8(reg)); if (abrt) return 0; + setr8(reg, temp); + cycles -= ((mod == 3) ? 3 : 5); + return 0; +} + +static int opXCHG_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 0; + seteaw(regs[reg].w); if (abrt) return 0; + regs[reg].w = temp; + cycles -= ((mod == 3) ? 3 : 5); + return 0; +} +static int opXCHG_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 0; + seteaw(regs[reg].w); if (abrt) return 0; + regs[reg].w = temp; + cycles -= ((mod == 3) ? 3 : 5); + return 0; +} + +static int opXCHG_l_a16(uint32_t fetchdat) +{ + uint32_t temp; + fetch_ea_16(fetchdat); + temp = geteal(); if (abrt) return 0; + seteal(regs[reg].l); if (abrt) return 0; + regs[reg].l = temp; + cycles -= ((mod == 3) ? 3 : 5); + return 0; +} +static int opXCHG_l_a32(uint32_t fetchdat) +{ + uint32_t temp; + fetch_ea_32(fetchdat); + temp = geteal(); if (abrt) return 0; + seteal(regs[reg].l); if (abrt) return 0; + regs[reg].l = temp; + cycles -= ((mod == 3) ? 3 : 5); + return 0; +} + + +static int opXCHG_AX_BX(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = BX; + BX = temp; + cycles -= 3; + return 0; +} +static int opXCHG_AX_CX(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = CX; + CX = temp; + cycles -= 3; + return 0; +} +static int opXCHG_AX_DX(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = DX; + DX = temp; + cycles -= 3; + return 0; +} +static int opXCHG_AX_SI(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = SI; + SI = temp; + cycles -= 3; + return 0; +} +static int opXCHG_AX_DI(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = DI; + DI = temp; + cycles -= 3; + return 0; +} +static int opXCHG_AX_BP(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = BP; + BP = temp; + cycles -= 3; + return 0; +} +static int opXCHG_AX_SP(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = SP; + SP = temp; + cycles -= 3; + return 0; +} + +static int opXCHG_EAX_EBX(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = EBX; + EBX = temp; + cycles -= 3; + return 0; +} +static int opXCHG_EAX_ECX(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = ECX; + ECX = temp; + cycles -= 3; + return 0; +} +static int opXCHG_EAX_EDX(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = EDX; + EDX = temp; + cycles -= 3; + return 0; +} +static int opXCHG_EAX_ESI(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = ESI; + ESI = temp; + cycles -= 3; + return 0; +} +static int opXCHG_EAX_EDI(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = EDI; + EDI = temp; + cycles -= 3; + return 0; +} +static int opXCHG_EAX_EBP(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = EBP; + EBP = temp; + cycles -= 3; + return 0; +} +static int opXCHG_EAX_ESP(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = ESP; + ESP = temp; + cycles -= 3; + return 0; +} + + +#define opBSWAP(reg) \ + static int opBSWAP_ ## reg(uint32_t fetchdat) \ + { \ + reg = (reg >> 24) | ((reg >> 8) & 0xff00) | ((reg << 8) & 0xff0000) | ((reg << 24) & 0xff000000); \ + cycles--; \ + return 0; \ + } + +opBSWAP(EAX) +opBSWAP(EBX) +opBSWAP(ECX) +opBSWAP(EDX) +opBSWAP(ESI) +opBSWAP(EDI) +opBSWAP(EBP) +opBSWAP(ESP)