Update to v097r10 release.

byuu says:

All 256 instructions implemented fully. Fixed a major bug with
instructions that both read and write to ModRM with displacement.
Riviera now runs into an infinite loop ... possibly crashed, possibly
waiting on interrupts or in to return something. Added a bunch of PPU
settings registers, but nothing's actually rendering with them yet.
This commit is contained in:
Tim Allen 2016-02-04 21:29:08 +11:00
parent d158c8f293
commit 7a748e093e
26 changed files with 1412 additions and 909 deletions

View File

@ -6,7 +6,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
static const string Version = "097.09";
static const string Version = "097.10";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "http://byuu.org/";

View File

@ -1,6 +1,5 @@
//(0 = odd, 1 = even) number of bits set in value
auto V30MZ::parity(uint16 value) const -> bool {
value ^= value >> 8;
auto V30MZ::parity(uint8 value) const -> bool {
value ^= value >> 4;
value ^= value >> 2;
value ^= value >> 1;
@ -48,14 +47,14 @@ auto V30MZ::alDec(Size size, uint16 x) -> uint16 {
}
auto V30MZ::alDiv(Size size, uint32 x, uint32 y) -> uint32 {
if(y == 0) return 0; //todo: throw exception
if(y == 0) return interrupt(0), 0;
uint32 quotient = x / y;
uint32 remainder = x % y;
return (remainder & mask) << bits | (quotient & mask);
}
auto V30MZ::alDivi(Size size, int32 x, int32 y) -> uint32 {
if(y == 0) return 0; //todo: throw exception
if(y == 0) return interrupt(0), 0;
x = size == Byte ? (int8)x : (int16)x;
y = size == Byte ? (int8)y : (int16)y;
uint32 quotient = x / y;

View File

@ -237,6 +237,9 @@ auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers, bool bytes) -> str
case 0x98: s = {"cbw "}; break;
case 0x99: s = {"cwd "}; break;
case 0x9a: s = {"call {1}:{0}", format{readWord(), readWord()}}; break;
case 0x9b: s = {"wait "}; break;
case 0x9c: s = {"pushf "}; break;
case 0x9d: s = {"popf "}; break;
case 0x9e: s = {"sahf "}; break;
case 0x9f: s = {"lahf "}; break;
case 0xa0: s = {"mov al,{0}", format{readIndirectByte()}}; break;
@ -275,17 +278,26 @@ auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers, bool bytes) -> str
case 0xc1: s = {"{0} {1},{2}", format{readGroup(2), readMemWord(), readByte()}}; break;
case 0xc2: s = {"ret {0}", format{readWord()}}; break;
case 0xc3: s = {"ret "}; break;
case 0xc4: s = {"les {0}", format{readMemWord()}}; break;
case 0xc5: s = {"lds {0}", format{readMemWord()}}; break;
case 0xc6: s = {"mov {0},{1}", format{readMemByte(), readByte()}}; break;
case 0xc7: s = {"mov {0},{1}", format{readMemWord(), readWord()}}; break;
case 0xc8: s = {"enter {0},{1}", format{readWord(), readByte()}}; break;
case 0xc9: s = {"leave "}; break;
case 0xca: s = {"retf {0}", format{readWord()}}; break;
case 0xcb: s = {"retf "}; break;
case 0xcc: s = {"int3 "}; break;
case 0xcd: s = {"int ", format{readByte()}}; break;
case 0xce: s = {"into "}; break;
case 0xcf: s = {"iret "}; break;
case 0xd0: s = {"{0} {1},1", format{readGroup(2), readMemByte()}}; break;
case 0xd1: s = {"{0} {1},1", format{readGroup(2), readMemWord()}}; break;
case 0xd2: s = {"{0} {1},cl", format{readGroup(2), readMemByte()}}; break;
case 0xd3: s = {"{0} {1},cl", format{readGroup(2), readMemWord()}}; break;
case 0xd4: s = {"aam {0}", format{readByte()}}; break;
case 0xd5: s = {"aad {0}", format{readByte()}}; break;
//case 0xd6:
case 0xd7: s = {"xlat "}; break;
//case 0xd8:
//case 0xd9:
//case 0xda:
@ -303,6 +315,7 @@ auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers, bool bytes) -> str
case 0xe6: s = {"out {0},al", format{readByte()}}; break;
case 0xe7: s = {"out {0},ax", format{readByte()}}; break;
case 0xe8: s = {"call {0}", format{readRelativeWord()}}; break;
case 0xe9: s = {"jmp {0}", format{readRelativeWord()}}; break;
case 0xea: s = {"jmp {1}:{0}", format{readWord(), readWord()}}; break;
case 0xeb: s = {"jmp {0}", format{readRelativeByte()}}; break;
case 0xec: s = {"in al,dx"}; break;
@ -325,9 +338,7 @@ auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers, bool bytes) -> str
case 0xfd: s = {"std "}; break;
case 0xfe: s = {"{0} {1},{2}", format{readGroup(4), readMemByte(), readByte()}}; break;
case 0xff: s = {"{0} {1},{2}", format{readGroup(4), readMemWord(), readWord()}}; break;
default:
s = {"??? [", hex(opcode, 2L), "]"};
default: s = {"??? {0}", format{hex(opcode, 2L)}}; break;
}
while(s.size() < 24) s.append(" ");

View File

@ -0,0 +1,56 @@
//27 daa
//2f das
auto V30MZ::opDecimalAdjust(bool negate) {
wait(9);
uint8 al = r.al;
if(r.f.h || ((al & 0x0f) > 0x09)) {
r.al += negate ? -0x06 : 0x06;
r.f.h = 1;
}
if(r.f.c || (al > 0x99)) {
r.al += negate ? -0x06 : 0x60;
r.f.c = 1;
}
r.f.s = r.al & 0x80;
r.f.z = r.al == 0;
r.f.p = parity(r.al);
}
//37 aaa
//3f aas
auto V30MZ::opAsciiAdjust(bool negate) {
wait(8);
if(r.f.h || ((r.al & 0x0f) > 0x09)) {
r.al += negate ? -0x06 : 0x06;
r.ah += negate ? -0x01 : 0x01;
r.f.h = 1;
r.f.c = 1;
} else {
r.f.h = 0;
r.f.c = 0;
}
r.al &= 0x0f;
}
//d4 aam,immb
auto V30MZ::opAdjustAfterMultiply() {
wait(16);
auto imm = fetch();
if(imm == 0) return interrupt(0);
r.ah = r.al / imm;
r.al %= imm;
r.f.p = parity(r.al);
r.f.s = r.ax & 0x8000;
r.f.z = r.ax == 0;
}
//d5 aad,immw
auto V30MZ::opAdjustAfterDivide() {
wait(5);
auto imm = fetch();
r.al += r.ah * imm;
r.ah = 0;
r.f.p = parity(r.al);
r.f.s = r.ax & 0x8000;
r.f.z = r.ax == 0;
}

View File

@ -0,0 +1,172 @@
//00 addb mem,reg
//01 addw mem,reg
auto V30MZ::opAddMemReg(Size size) {
modRM();
setMem(size, alAdd(size, getMem(size), getReg(size)));
}
//02 addb reg,mem
//03 addw reg,mem
auto V30MZ::opAddRegMem(Size size) {
modRM();
setReg(size, alAdd(size, getReg(size), getMem(size)));
}
//04 add al,#imm
//05 add ax,#imm
auto V30MZ::opAddAccImm(Size size) {
setAcc(size, alAdd(size, getAcc(size), fetch(size)));
}
//08 orb mem,reg
//09 orb mem,reg
auto V30MZ::opOrMemReg(Size size) {
modRM();
setMem(size, alOr(size, getMem(size), getReg(size)));
}
//0a orb reg,mem
//0b orb reg,mem
auto V30MZ::opOrRegMem(Size size) {
modRM();
setReg(size, alOr(size, getReg(size), getMem(size)));
}
//0c or al,#imm
//0d or ax,#imm
auto V30MZ::opOrAccImm(Size size) {
setAcc(size, alOr(size, getAcc(size), fetch(size)));
}
auto V30MZ::opAdcMemReg(Size size) {
modRM();
setMem(size, alAdc(size, getMem(size), getReg(size)));
}
auto V30MZ::opAdcRegMem(Size size) {
modRM();
setReg(size, alAdc(size, getReg(size), getMem(size)));
}
auto V30MZ::opAdcAccImm(Size size) {
setAcc(size, alAdc(size, getAcc(size), fetch(size)));
}
auto V30MZ::opSbbMemReg(Size size) {
modRM();
setMem(size, alSbb(size, getMem(size), getReg(size)));
}
auto V30MZ::opSbbRegMem(Size size) {
modRM();
setReg(size, alSbb(size, getReg(size), getMem(size)));
}
auto V30MZ::opSbbAccImm(Size size) {
setAcc(size, alSbb(size, getAcc(size), fetch(size)));
}
auto V30MZ::opAndMemReg(Size size) {
modRM();
setMem(size, alAnd(size, getMem(size), getReg(size)));
}
auto V30MZ::opAndRegMem(Size size) {
modRM();
setReg(size, alAnd(size, getReg(size), getMem(size)));
}
auto V30MZ::opAndAccImm(Size size) {
setAcc(size, alAnd(size, getAcc(size), fetch(size)));
}
auto V30MZ::opSubMemReg(Size size) {
modRM();
setMem(size, alSub(size, getMem(size), getReg(size)));
}
auto V30MZ::opSubRegMem(Size size) {
modRM();
setReg(size, alSub(size, getReg(size), getMem(size)));
}
auto V30MZ::opSubAccImm(Size size) {
setAcc(size, alSub(size, getAcc(size), fetch(size)));
}
auto V30MZ::opXorMemReg(Size size) {
modRM();
setMem(size, alXor(size, getMem(size), getReg(size)));
}
auto V30MZ::opXorRegMem(Size size) {
modRM();
setReg(size, alXor(size, getReg(size), getMem(size)));
}
auto V30MZ::opXorAccImm(Size size) {
setAcc(size, alXor(size, getAcc(size), fetch(size)));
}
auto V30MZ::opCmpMemReg(Size size) {
modRM();
alSub(size, getMem(size), getReg(size));
}
auto V30MZ::opCmpRegMem(Size size) {
modRM();
alSub(size, getReg(size), getMem(size));
}
auto V30MZ::opCmpAccImm(Size size) {
alSub(size, getAcc(size), fetch(size));
}
auto V30MZ::opTestAcc(Size size) {
alAnd(size, getAcc(size), fetch(size));
}
auto V30MZ::opTestMemReg(Size size) {
modRM();
alAnd(size, getMem(size), getReg(size));
}
auto V30MZ::opMultiplySignedRegMemImm(Size size) {
wait(2);
modRM();
setReg(size, alMuli(size, getMem(size), size == Word ? (int16)fetch(Word) : (int8)fetch(Byte)));
}
//40 inc ax
//41 inc cx
//42 inc dx
//43 inc bx
//44 inc sp
//45 inc bp
//46 inc si
//47 inc di
auto V30MZ::opIncReg(uint16& reg) {
reg++;
}
//48 dec ax
//49 dec cx
//4a dec dx
//4b dec bx
//4c dec sp
//4d dec bp
//4e dec si
//4f dec di
auto V30MZ::opDecReg(uint16& reg) {
reg--;
}
//98 cbw
auto V30MZ::opSignExtendByte() {
setAcc(Word, (int8)getAcc(Byte));
}
//99 cwd
auto V30MZ::opSignExtendWord() {
setAcc(Long, (int16)getAcc(Word));
}

View File

@ -0,0 +1,191 @@
auto V30MZ::opLoop() {
wait(1);
auto offset = (int8)fetch();
if(--r.cx) {
wait(3);
r.ip += offset;
}
}
auto V30MZ::opLoopWhile(bool value) {
wait(2);
auto offset = (int8)fetch();
if(--r.cx && r.f.z == value) {
wait(3);
r.ip += offset;
}
}
auto V30MZ::opJumpShort() {
wait(3);
auto offset = (int8)fetch();
r.ip += offset;
}
auto V30MZ::opJumpIf(bool condition) {
auto offset = (int8)fetch();
if(condition) r.ip += offset;
}
auto V30MZ::opJumpNear() {
wait(3);
r.ip += (int16)fetch(Word);
}
auto V30MZ::opJumpFar() {
wait(6);
auto ip = fetch(Word);
auto cs = fetch(Word);
r.cs = cs;
r.ip = ip;
}
auto V30MZ::opCallNear() {
wait(4);
auto offset = (int16)fetch(Word);
push(r.ip);
r.ip += offset;
}
auto V30MZ::opCallFar() {
wait(9);
auto ip = fetch(Word);
auto cs = fetch(Word);
push(r.cs);
push(r.ip);
r.cs = cs;
r.ip = ip;
}
auto V30MZ::opReturn() {
wait(5);
r.ip = pop();
}
auto V30MZ::opReturnImm() {
wait(5);
auto offset = fetch(Word);
r.ip = pop();
r.sp += offset;
}
auto V30MZ::opReturnFar() {
wait(7);
r.ip = pop();
r.cs = pop();
}
auto V30MZ::opReturnFarImm() {
wait(8);
auto offset = fetch(Word);
r.ip = pop();
r.cs = pop();
r.sp += offset;
}
auto V30MZ::opReturnInt() {
wait(9);
r.ip = pop();
r.cs = pop();
r.f = pop();
}
auto V30MZ::opInt3() {
wait(8);
interrupt(3);
}
auto V30MZ::opIntImm() {
wait(9);
interrupt(fetch());
}
auto V30MZ::opInto() {
wait(5);
interrupt(4);
}
auto V30MZ::opEnter() {
wait(7);
auto offset = fetch(Word);
auto length = fetch(Byte) & 0x1f;
push(r.bp);
r.bp = r.sp;
r.sp -= offset;
if(length) {
wait(length > 1 ? 7 : 6);
for(uint n = 1; n < length; n++) {
wait(4);
auto data = read(Word, segment(r.ss), r.bp - n * 2);
push(data);
}
push(r.bp);
}
}
auto V30MZ::opLeave() {
wait(1);
r.sp = r.bp;
r.bp = pop();
}
auto V30MZ::opPushReg(uint16& reg) {
push(reg);
}
auto V30MZ::opPopReg(uint16& reg) {
reg = pop();
}
//9c pushf
auto V30MZ::opPushFlags() {
wait(1);
push(r.f);
}
//9d popf
auto V30MZ::opPopFlags() {
wait(2);
r.f = pop();
}
//60 pusha
auto V30MZ::opPushAll() {
wait(8);
auto sp = r.sp;
push(r.ax);
push(r.cx);
push(r.dx);
push(r.bx);
push(sp);
push(r.bp);
push(r.si);
push(r.di);
}
//61 popa
auto V30MZ::opPopAll() {
wait(7);
r.di = pop();
r.si = pop();
r.bp = pop();
auto sp = pop();
r.bx = pop();
r.dx = pop();
r.cx = pop();
r.ax = pop();
r.sp = sp;
}
//68 push imm16
//6a push imm8s
auto V30MZ::opPushImm(Size size) {
push(size == Word ? fetch(Word) : (int8)fetch(Byte));
}
auto V30MZ::opPopMem() {
modRM();
setMem(Word, pop());
}

View File

@ -0,0 +1,27 @@
//9e sahf
auto V30MZ::opStoreFlagsAcc() {
wait(3);
r.f = (r.f & 0xff00) | r.ah;
}
//9f lahf
auto V30MZ::opLoadAccFlags() {
wait(1);
r.ah = (r.f & 0x00ff);
}
//f5 cmc
auto V30MZ::opComplementCarry() {
wait(3);
r.f.c = !r.f.c;
}
auto V30MZ::opClearFlag(bool& flag) {
wait(3);
flag = false;
}
auto V30MZ::opSetFlag(bool& flag) {
wait(3);
flag = true;
}

View File

@ -0,0 +1,78 @@
//80 grp1 memb,immb
//81 grp1 memw,immw
//82 grp1 memb,immbs
//83 grp1 memw,immbs
auto V30MZ::opGroup1MemImm(Size size, bool sign) {
modRM();
auto mem = getMem(size);
auto imm = sign ? (int8)fetch() : size == Byte ? fetch() : fetch(Word);
switch(modrm.reg) {
case 0: setMem(size, alAdd(size, mem, imm)); break;
case 1: setMem(size, alOr (size, mem, imm)); break;
case 2: setMem(size, alAdc(size, mem, imm)); break;
case 3: setMem(size, alSbb(size, mem, imm)); break;
case 4: setMem(size, alAnd(size, mem, imm)); break;
case 5: setMem(size, alSub(size, mem, imm)); break;
case 6: setMem(size, alXor(size, mem, imm)); break;
case 7: alSub(size, mem, imm); break;
}
}
//c0 grp2 memb,imm8
//c1 grp2 memw,imm8
//d0 grp2 memb,1
//d1 grp2 memw,1
//d2 grp2 memb,cl
//d3 grp2 memw,cl
auto V30MZ::opGroup2MemImm(Size size, maybe<uint8> imm) {
modRM();
auto mem = getMem(size);
if(!imm) {
wait(2);
imm = fetch();
}
switch(modrm.reg) {
case 0: setMem(size, alRol(size, mem, *imm)); break;
case 1: setMem(size, alRor(size, mem, *imm)); break;
case 2: setMem(size, alRcl(size, mem, *imm)); break;
case 3: setMem(size, alRcr(size, mem, *imm)); break;
case 4: setMem(size, alShl(size, mem, *imm)); break;
case 5: setMem(size, alShr(size, mem, *imm)); break;
case 6: setMem(size, alSal(size, mem, *imm)); break;
case 7: setMem(size, alSar(size, mem, *imm)); break;
}
}
//f6 grp3 memb
//f7 grp3 memw
auto V30MZ::opGroup3MemImm(Size size) {
modRM();
auto mem = getMem(size);
switch(modrm.reg) {
case 0: alAnd(size, mem, fetch(size)); break;
case 1: break;
case 2: wait(2); setMem(size, alNot(size, mem)); break;
case 3: wait(2); setMem(size, alNeg(size, mem)); break;
case 4: wait(2); setAcc(size * 2, alMul(size, getAcc(size), mem)); break;
case 5: wait(2); setAcc(size * 2, alMuli(size, getAcc(size), mem)); break; break;
case 6: wait(size == Byte ? 15 : 23); setAcc(size * 2, alDiv(size, getAcc(size * 2), mem)); break;
case 7: wait(size == Byte ? 17 : 24); setAcc(size * 2, alDivi(size, getAcc(size * 2), mem)); break;
}
}
//fe grp4 memb
//ff grp4 memw
auto V30MZ::opGroup4MemImm(Size size) {
modRM();
auto mem = getMem(size);
switch(modrm.reg) {
case 0: wait(2); setMem(size, alInc(size, mem)); break;
case 1: wait(2); setMem(size, alDec(size, mem)); break;
case 2: break;
case 3: break;
case 4: break;
case 5: break;
case 6: break;
case 7: break;
}
}

View File

@ -0,0 +1,72 @@
//26 es:
//2e cs:
//36 ss:
//3e ds:
auto V30MZ::opSegment(uint16 segment) {
state.prefix = true;
prefix.segment = segment;
}
//f2 repnz
//f3 repz
auto V30MZ::opRepeat(bool flag) {
wait(4);
if(r.cx == 0) return;
state.prefix = true;
prefix.repeat = flag;
}
//f0 lock
auto V30MZ::opLock() {
state.prefix = true;
}
//9b wait
auto V30MZ::opWait() {
}
//f4 hlt
auto V30MZ::opHalt() {
wait(8);
state.halt = true;
}
//90 nop
auto V30MZ::opNop() {
}
auto V30MZ::opIn(Size size) {
wait(5);
setAcc(size, in(size, fetch()));
}
auto V30MZ::opOut(Size size) {
wait(5);
out(size, fetch(), getAcc(size));
}
auto V30MZ::opInDX(Size size) {
wait(5);
setAcc(size, in(size, r.dx));
}
auto V30MZ::opOutDX(Size size) {
wait(5);
out(size, r.dx, getAcc(size));
}
//d7 xlat
auto V30MZ::opTranslate() {
wait(4);
r.al = read(Byte, segment(r.ds), r.bx + r.al);
}
//62 bound reg,mem,mem
auto V30MZ::opBound() {
wait(12);
modRM();
auto lo = getMem(Word, 0);
auto hi = getMem(Word, 2);
auto reg = getReg(Word);
if(reg < lo || reg > hi) interrupt(5);
}

View File

@ -0,0 +1,68 @@
auto V30MZ::opMoveMemReg(Size size) {
modRM();
setMem(size, getReg(size));
}
auto V30MZ::opMoveRegMem(Size size) {
modRM();
setReg(size, getMem(size));
}
auto V30MZ::opMoveMemSeg() {
modRM();
setMem(Word, getSeg());
}
auto V30MZ::opMoveSegMem() {
wait(1);
modRM();
setSeg(getMem(Word));
}
auto V30MZ::opMoveAccMem(Size size) {
setAcc(size, read(size, r.ds, fetch(Word)));
}
auto V30MZ::opMoveMemAcc(Size size) {
write(size, r.ds, fetch(Word), getAcc(size));
}
auto V30MZ::opMoveRegImm(uint8& reg) {
reg = fetch(Byte);
}
auto V30MZ::opMoveRegImm(uint16& reg) {
reg = fetch(Word);
}
auto V30MZ::opMoveMemImm(Size size) {
modRM();
setMem(size, fetch(size));
}
auto V30MZ::opExchange(uint16& x, uint16& y) {
wait(2);
uint16 z = x;
x = y;
y = z;
}
auto V30MZ::opExchangeMemReg(Size size) {
wait(2);
modRM();
auto mem = getMem(size);
auto reg = getReg(size);
setMem(size, reg);
setReg(size, mem);
}
auto V30MZ::opLoadEffectiveAddressRegMem() {
modRM();
setReg(Word, modrm.address);
}
auto V30MZ::opLoadSegmentMem(uint16& reg) {
wait(5);
modRM();
reg = getMem(Word);
}

View File

@ -0,0 +1,87 @@
auto V30MZ::opInString(Size size) {
wait(5);
auto data = in(size, r.dx);
write(size, r.es, r.di, data);
r.di += r.f.d ? -size : size;
if(prefix.repeat && --r.cx) {
state.prefix = true;
r.ip--;
}
}
auto V30MZ::opOutString(Size size) {
wait(6);
auto data = read(size, segment(r.ds), r.si);
out(size, r.dx, data);
r.si += r.f.d ? -size : size;
if(prefix.repeat && --r.cx) {
state.prefix = true;
r.ip--;
}
}
auto V30MZ::opMoveString(Size size) {
wait(4);
auto data = read(size, segment(r.ds), r.si);
write(size, r.es, r.di, data);
r.si += r.f.d ? -size : size;
r.di += r.f.d ? -size : size;
if(prefix.repeat && --r.cx) {
state.prefix = true;
r.ip--;
}
}
auto V30MZ::opCompareString(Size size) {
wait(5);
auto x = read(size, segment(r.ds), r.si);
auto y = read(size, r.es, r.di);
r.si += r.f.d ? -size : size;
r.di += r.f.d ? -size : size;
alSub(size, x, y);
if(prefix.repeat && prefix.repeat() == r.f.z && --r.cx) {
state.prefix = true;
r.ip--;
}
}
auto V30MZ::opStoreString(Size size) {
wait(2);
write(size, r.es, r.di, getAcc(size));
r.di += r.f.d ? -size : size;
if(prefix.repeat && --r.cx) {
state.prefix = true;
r.ip--;
}
}
//ac lodsb
//ad lodsw
auto V30MZ::opLoadString(Size size) {
wait(2);
setAcc(size, read(size, segment(r.ds), r.si));
if(prefix.repeat && --r.cx) {
state.prefix = true;
r.ip--;
}
}
//ae scasb
//af scasw
auto V30MZ::opScanString(Size size) {
wait(3);
auto x = getAcc(size);
auto y = read(size, r.es, r.di);
alSub(size, x, y);
if(prefix.repeat && prefix.repeat() == r.f.z && --r.cx) {
state.prefix = true;
r.ip--;
}
}

View File

@ -1,678 +0,0 @@
//00 addb mem,reg
//01 addw mem,reg
auto V30MZ::opAddMemReg(Size size) {
auto modRM = fetch();
setMem(size, modRM, alAdd(size, getMem(size, modRM), getReg(size, modRM)));
}
//02 addb reg,mem
//03 addw reg,mem
auto V30MZ::opAddRegMem(Size size) {
auto modRM = fetch();
setReg(size, modRM, alAdd(size, getReg(size, modRM), getMem(size, modRM)));
}
//04 add al,#imm
//05 add ax,#imm
auto V30MZ::opAddAccImm(Size size) {
setAcc(size, alAdd(size, getAcc(size), fetch(size)));
}
//08 orb mem,reg
//09 orb mem,reg
auto V30MZ::opOrMemReg(Size size) {
auto modRM = fetch();
setMem(size, modRM, alOr(size, getMem(size, modRM), getReg(size, modRM)));
}
//0a orb reg,mem
//0b orb reg,mem
auto V30MZ::opOrRegMem(Size size) {
auto modRM = fetch();
setReg(size, modRM, alOr(size, getReg(size, modRM), getMem(size, modRM)));
}
//0c or al,#imm
//0d or ax,#imm
auto V30MZ::opOrAccImm(Size size) {
setAcc(size, alOr(size, getAcc(size), fetch(size)));
}
auto V30MZ::opAdcMemReg(Size size) {
auto modRM = fetch();
setMem(size, modRM, alAdc(size, getMem(size, modRM), getReg(size, modRM)));
}
auto V30MZ::opAdcRegMem(Size size) {
auto modRM = fetch();
setReg(size, modRM, alAdc(size, getReg(size, modRM), getMem(size, modRM)));
}
auto V30MZ::opAdcAccImm(Size size) {
setAcc(size, alAdc(size, getAcc(size), fetch(size)));
}
auto V30MZ::opSbbMemReg(Size size) {
auto modRM = fetch();
setMem(size, modRM, alSbb(size, getMem(size, modRM), getReg(size, modRM)));
}
auto V30MZ::opSbbRegMem(Size size) {
auto modRM = fetch();
setReg(size, modRM, alSbb(size, getReg(size, modRM), getMem(size, modRM)));
}
auto V30MZ::opSbbAccImm(Size size) {
setAcc(size, alSbb(size, getAcc(size), fetch(size)));
}
auto V30MZ::opAndMemReg(Size size) {
auto modRM = fetch();
setMem(size, modRM, alAnd(size, getMem(size, modRM), getReg(size, modRM)));
}
auto V30MZ::opAndRegMem(Size size) {
auto modRM = fetch();
setReg(size, modRM, alAnd(size, getReg(size, modRM), getMem(size, modRM)));
}
auto V30MZ::opAndAccImm(Size size) {
setAcc(size, alAnd(size, getAcc(size), fetch(size)));
}
auto V30MZ::opSubMemReg(Size size) {
auto modRM = fetch();
setMem(size, modRM, alSub(size, getMem(size, modRM), getReg(size, modRM)));
}
auto V30MZ::opSubRegMem(Size size) {
auto modRM = fetch();
setReg(size, modRM, alSub(size, getReg(size, modRM), getMem(size, modRM)));
}
auto V30MZ::opSubAccImm(Size size) {
setAcc(size, alSub(size, getAcc(size), fetch(size)));
}
//26 es:
//2e cs:
//36 ss:
//3e ds:
auto V30MZ::opPrefix(uint16& segment) {
prefix.hold = true;
prefix.segment = segment;
}
//27 daa
//2f das
auto V30MZ::opDecimalAdjust(bool negate) {
wait(9);
uint8 al = r.al;
if(r.f.h || ((al & 0x0f) > 0x09)) {
r.al += negate ? -0x06 : 0x06;
r.f.h = 1;
}
if(r.f.c || (al > 0x99)) {
r.al += negate ? -0x06 : 0x60;
r.f.c = 1;
}
r.f.s = r.al & 0x80;
r.f.z = r.al == 0;
r.f.p = parity(r.al);
}
//37 aaa
//3f aas
auto V30MZ::opAsciiAdjust(bool negate) {
wait(8);
if(r.f.h || ((r.al & 0x0f) > 0x09)) {
r.al += negate ? -0x06 : 0x06;
r.ah += negate ? -0x01 : 0x01;
r.f.h = 1;
r.f.c = 1;
} else {
r.f.h = 0;
r.f.c = 0;
}
r.al &= 0x0f;
}
auto V30MZ::opXorMemReg(Size size) {
auto modRM = fetch();
setMem(size, modRM, alXor(size, getMem(size, modRM), getReg(size, modRM)));
}
auto V30MZ::opXorRegMem(Size size) {
auto modRM = fetch();
setReg(size, modRM, alXor(size, getReg(size, modRM), getMem(size, modRM)));
}
auto V30MZ::opXorAccImm(Size size) {
setAcc(size, alXor(size, getAcc(size), fetch(size)));
}
auto V30MZ::opCmpMemReg(Size size) {
auto modRM = fetch();
alSub(size, getMem(size, modRM), getReg(size, modRM));
}
auto V30MZ::opCmpRegMem(Size size) {
auto modRM = fetch();
alSub(size, getReg(size, modRM), getMem(size, modRM));
}
auto V30MZ::opCmpAccImm(Size size) {
alSub(size, getAcc(size), fetch(size));
}
//40 inc ax
//41 inc cx
//42 inc dx
//43 inc bx
//44 inc sp
//45 inc bp
//46 inc si
//47 inc di
auto V30MZ::opIncReg(uint16& reg) {
reg++;
}
//48 dec ax
//49 dec cx
//4a dec dx
//4b dec bx
//4c dec sp
//4d dec bp
//4e dec si
//4f dec di
auto V30MZ::opDecReg(uint16& reg) {
reg--;
}
auto V30MZ::opPushReg(uint16& reg) {
push(reg);
}
auto V30MZ::opPopReg(uint16& reg) {
reg = pop();
}
//60 pusha
auto V30MZ::opPushAll() {
wait(8);
auto sp = r.sp;
push(r.ax);
push(r.cx);
push(r.dx);
push(r.bx);
push(sp);
push(r.bp);
push(r.si);
push(r.di);
}
//61 popa
auto V30MZ::opPopAll() {
wait(7);
r.di = pop();
r.si = pop();
r.bp = pop();
auto sp = pop();
r.bx = pop();
r.dx = pop();
r.cx = pop();
r.ax = pop();
r.sp = sp;
}
//62 bound reg,mem,mem
auto V30MZ::opBound() {
wait(12);
auto modRM = fetch();
auto bound = getMem(Long, modRM);
auto reg = getReg(Word, modRM);
uint16 lo = bound >> 0;
uint16 hi = bound >> 16;
if(reg < lo || reg > hi) {
//todo
}
}
//68 push imm16
//6a push imm8s
auto V30MZ::opPushImm(Size size) {
push(size == Word ? fetch(Word) : (int8)fetch(Byte));
}
auto V30MZ::opMultiplySignedRegMemImm(Size size) {
wait(2);
auto modRM = fetch();
auto mem = getMem(size, modRM);
auto imm = size == Word ? fetch(Word) : (int8)fetch(Byte);
setReg(size, modRM, alMuli(size, mem, imm));
}
//9e sahf
auto V30MZ::opStoreFlagsAcc() {
wait(3);
r.f = (r.f & 0xff00) | r.ah;
}
//9f lahf
auto V30MZ::opLoadAccFlags() {
wait(1);
r.ah = (r.f & 0x00ff);
}
auto V30MZ::opJumpIf(bool condition) {
auto offset = (int8)fetch();
if(condition) r.ip += offset;
}
//80 grp1 memb,imm8
//81 grp1 memw,imm16
//82 grp1 memb,imm8s
//83 grp1 memw,imm8s
auto V30MZ::opGroup1MemImm(Size size, bool sign) {
auto modRM = fetch();
auto imm = sign ? (int8)fetch() : size == Byte ? fetch() : fetch(Word);
auto mem = getMem(size, modRM);
switch((uint3)(modRM >> 3)) {
case 0: setMem(size, modRM, alAdd(size, mem, imm)); break;
case 1: setMem(size, modRM, alOr (size, mem, imm)); break;
case 2: setMem(size, modRM, alAdc(size, mem, imm)); break;
case 3: setMem(size, modRM, alSbb(size, mem, imm)); break;
case 4: setMem(size, modRM, alAnd(size, mem, imm)); break;
case 5: setMem(size, modRM, alSub(size, mem, imm)); break;
case 6: setMem(size, modRM, alXor(size, mem, imm)); break;
case 7: alSub(size, mem, imm); break;
}
}
auto V30MZ::opTestMemReg(Size size) {
auto modRM = fetch();
auto mem = getMem(size, modRM);
auto reg = getReg(size, modRM);
alAnd(size, mem, reg);
}
auto V30MZ::opExchangeMemReg(Size size) {
wait(2);
auto modRM = fetch();
auto mem = getMem(size, modRM);
auto reg = getReg(size, modRM);
setMem(size, modRM, reg);
setReg(size, modRM, mem);
}
auto V30MZ::opMoveMemReg(Size size) {
auto modRM = fetch();
setMem(size, modRM, getReg(size, modRM));
}
auto V30MZ::opMoveRegMem(Size size) {
auto modRM = fetch();
setReg(size, modRM, getMem(size, modRM));
}
auto V30MZ::opLoadEffectiveAddressRegMem() {
auto modRM = fetch();
setReg(Word, modRM, getMemAddress(modRM));
}
auto V30MZ::opMoveMemSeg() {
auto modRM = fetch();
setMem(Word, modRM, getSeg(modRM));
}
auto V30MZ::opMoveSegMem() {
wait(1);
auto modRM = fetch();
setSeg(modRM, getMem(Word, modRM));
}
auto V30MZ::opPopMem() {
auto modRM = fetch();
setMem(Word, modRM, pop());
}
auto V30MZ::opNop() {
}
auto V30MZ::opExchange(uint16& x, uint16& y) {
wait(2);
uint16 z = x;
x = y;
y = z;
}
//98 cbw
auto V30MZ::opSignExtendByte() {
setAcc(Word, (int8)getAcc(Byte));
}
//99 cwd
auto V30MZ::opSignExtendWord() {
setAcc(Long, (int16)getAcc(Word));
}
auto V30MZ::opCallFar() {
wait(9);
auto ip = fetch(Word);
auto cs = fetch(Word);
push(r.cs);
push(r.ip);
r.cs = cs;
r.ip = ip;
}
auto V30MZ::opMoveAccMem(Size size) {
setAcc(size, read(size, r.ds, fetch(Word)));
}
auto V30MZ::opMoveMemAcc(Size size) {
write(size, r.ds, fetch(Word), getAcc(size));
}
auto V30MZ::opInString(Size size) {
wait(5);
auto data = in(size, r.dx);
write(size, r.es, r.di, data);
r.di += r.f.d ? -size : size;
if(prefix.repeat && --r.cx) {
prefix.hold = true;
r.ip--;
}
}
auto V30MZ::opOutString(Size size) {
wait(6);
auto data = read(size, segment(r.ds), r.si);
out(size, r.dx, data);
r.si += r.f.d ? -size : size;
if(prefix.repeat && --r.cx) {
prefix.hold = true;
r.ip--;
}
}
auto V30MZ::opMoveString(Size size) {
wait(4);
auto data = read(size, segment(r.ds), r.si);
write(size, r.es, r.di, data);
r.si += r.f.d ? -size : size;
r.di += r.f.d ? -size : size;
if(prefix.repeat && --r.cx) {
prefix.hold = true;
r.ip--;
}
}
auto V30MZ::opCompareString(Size size) {
wait(5);
auto x = read(size, segment(r.ds), r.si);
auto y = read(size, r.es, r.di);
r.si += r.f.d ? -size : size;
r.di += r.f.d ? -size : size;
alSub(size, x, y);
if(prefix.repeat && prefix.repeat() == r.f.z && --r.cx) {
prefix.hold = true;
r.ip--;
}
}
auto V30MZ::opTestAcc(Size size) {
alAnd(size, getAcc(size), fetch(size));
}
auto V30MZ::opStoreString(Size size) {
wait(2);
write(size, r.es, r.di, getAcc(size));
r.di += r.f.d ? -size : size;
if(prefix.repeat && --r.cx) {
prefix.hold = true;
r.ip--;
}
}
//ac lodsb
//ad lodsw
auto V30MZ::opLoadString(Size size) {
wait(2);
setAcc(size, read(size, segment(r.ds), r.si));
if(prefix.repeat && --r.cx) {
prefix.hold = true;
r.ip--;
}
}
//ae scasb
//af scasw
auto V30MZ::opSubtractCompareString(Size size) {
wait(3);
auto x = getAcc(size);
auto y = read(size, r.es, r.di);
alSub(size, x, y);
if(prefix.repeat && prefix.repeat() == r.f.z && --r.cx) {
prefix.hold = true;
r.ip--;
}
}
auto V30MZ::opMoveRegImm(uint8& reg) {
reg = fetch(Byte);
}
auto V30MZ::opMoveRegImm(uint16& reg) {
reg = fetch(Word);
}
auto V30MZ::opReturnImm() {
wait(5);
auto offset = fetch(Word);
r.ip = pop();
r.sp += offset;
}
auto V30MZ::opReturn() {
wait(5);
r.ip = pop();
}
auto V30MZ::opMoveMemImm(Size size) {
auto modRM = fetch();
setMem(size, modRM, fetch(size));
}
auto V30MZ::opReturnFarImm() {
wait(8);
auto offset = fetch(Word);
r.ip = pop();
r.cs = pop();
r.sp += offset;
}
auto V30MZ::opReturnFar() {
wait(7);
r.ip = pop();
r.cs = pop();
}
auto V30MZ::opReturnInt() {
wait(9);
r.ip = pop();
r.cs = pop();
r.f = pop();
}
auto V30MZ::opInto() {
wait(5);
//todo
}
auto V30MZ::opLeave() {
wait(1);
r.sp = r.bp;
r.bp = pop();
}
auto V30MZ::opGroup2MemImm(Size size, maybe<uint8> imm) {
auto modRM = fetch();
if(!imm) {
wait(2);
imm = fetch();
}
auto mem = getMem(size, modRM);
switch((uint3)(modRM >> 3)) {
case 0: setMem(size, modRM, alRol(size, mem, *imm)); break;
case 1: setMem(size, modRM, alRor(size, mem, *imm)); break;
case 2: setMem(size, modRM, alRcl(size, mem, *imm)); break;
case 3: setMem(size, modRM, alRcr(size, mem, *imm)); break;
case 4: setMem(size, modRM, alShl(size, mem, *imm)); break;
case 5: setMem(size, modRM, alShr(size, mem, *imm)); break;
case 6: setMem(size, modRM, alSal(size, mem, *imm)); break;
case 7: setMem(size, modRM, alSar(size, mem, *imm)); break;
}
}
auto V30MZ::opGroup3MemImm(Size size) {
auto modRM = fetch();
auto mem = getMem(size, modRM);
switch((uint3)(modRM >> 3)) {
case 0: alAnd(size, mem, fetch(size)); break;
case 1: break;
case 2: wait(2); setMem(size, modRM, alNot(size, mem)); break;
case 3: wait(2); setMem(size, modRM, alNeg(size, mem)); break;
case 4: wait(2); setAcc(size * 2, alMul(size, getAcc(size), mem)); break;
case 5: wait(2); setAcc(size * 2, alMuli(size, getAcc(size), mem)); break; break;
case 6: wait(size == Byte ? 15 : 23); setAcc(size * 2, alDiv(size, getAcc(size * 2), mem)); break;
case 7: wait(size == Byte ? 17 : 24); setAcc(size * 2, alDivi(size, getAcc(size * 2), mem)); break;
}
}
auto V30MZ::opGroup4MemImm(Size size) {
auto modRM = fetch();
auto mem = getMem(size, modRM);
switch((uint3)(modRM >> 3)) {
case 0: wait(2); setMem(size, modRM, alInc(size, mem)); break;
case 1: wait(2); setMem(size, modRM, alDec(size, mem)); break;
case 2: break;
case 3: break;
case 4: break;
case 5: break;
case 6: break;
case 7: break;
}
}
auto V30MZ::opLoopWhile(bool value) {
wait(2);
auto offset = (int8)fetch();
if(--r.cx && r.f.z == value) {
wait(3);
r.ip += offset;
}
}
auto V30MZ::opLoop() {
wait(1);
auto offset = (int8)fetch();
if(--r.cx) {
wait(3);
r.ip += offset;
}
}
auto V30MZ::opIn(Size size) {
wait(5);
auto port = fetch();
r.al = in(port++);
if(size != Word) return;
r.ah = in(port++);
}
auto V30MZ::opOut(Size size) {
wait(5);
auto port = fetch();
out(port++, r.al);
if(size != Word) return;
out(port++, r.ah);
}
auto V30MZ::opCallNear() {
wait(4);
auto offset = (int16)fetch(Word);
push(r.ip);
r.ip += offset;
}
auto V30MZ::opJumpFar() {
wait(6);
auto ip = fetch(Word);
auto cs = fetch(Word);
r.cs = cs;
r.ip = ip;
}
auto V30MZ::opJumpShort() {
wait(3);
auto offset = (int8)fetch();
r.ip += offset;
}
auto V30MZ::opInDX(Size size) {
wait(5);
r.al = in(r.dx + 0);
if(size != Word) return;
r.ah = in(r.dx + 1);
}
auto V30MZ::opOutDX(Size size) {
wait(5);
out(r.dx + 0, r.al);
if(size != Word) return;
out(r.dx + 1, r.ah);
}
//f0 lock
auto V30MZ::opLock() {
prefix.hold = true;
}
//f2 repnz
//f3 repz
auto V30MZ::opRepeat(bool flag) {
wait(4);
if(r.cx == 0) return;
prefix.hold = true;
prefix.repeat = flag;
}
//f4 halt
auto V30MZ::opHalt() {
wait(8);
//todo
}
//f5 cmc
auto V30MZ::opComplementCarry() {
wait(3);
r.f.c = !r.f.c;
}
auto V30MZ::opClearFlag(bool& flag) {
wait(3);
flag = false;
}
auto V30MZ::opSetFlag(bool& flag) {
wait(3);
flag = true;
}

View File

@ -3,56 +3,65 @@
//d5-d3 => reg
//d2-d0 => mem
auto V30MZ::getReg(Size size, uint8 modRM) -> uint16 {
return size == Byte ? r.byte(modRM >> 3) : r.word(modRM >> 3);
}
auto V30MZ::modRM() -> void {
auto byte = fetch();
modrm.mod = byte >> 6;
modrm.reg = byte >> 3;
modrm.mem = byte >> 0;
auto V30MZ::setReg(Size size, uint8 modRM, uint16 data) -> void {
if(size == Byte) r.byte(modRM >> 3) = data;
if(size == Word) r.word(modRM >> 3) = data;
}
//
auto V30MZ::getSeg(uint8 modRM) -> uint16 {
return r.segment(modRM >> 3);
}
auto V30MZ::setSeg(uint8 modRM, uint16 data) -> void {
r.segment(modRM >> 3) = data;
}
//
auto V30MZ::getMemAddress(uint8 modRM) -> uint32 {
if((modRM & 0xc7) == 0x06) return r.ds << 16 | fetch(Word);
uint16 s = 0, a = 0;
if((modRM & 0xc0) == 0x40) a = (int8)fetch(Byte);
if((modRM & 0xc0) == 0x80) a = (int16)fetch(Word);
switch(modRM & 7) {
case 0: s = r.ds; a += r.bx + r.si; break;
case 1: s = r.ds; a += r.bx + r.di; break;
case 2: s = r.ss; a += r.bp + r.si; break;
case 3: s = r.ss; a += r.bp + r.di; break;
case 4: s = r.ds; a += r.si; break;
case 5: s = r.ds; a += r.di; break;
case 6: s = r.ss; a += r.bp; break;
case 7: s = r.ds; a += r.bx; break;
if(modrm.mod == 0 && modrm.mem == 6) {
modrm.segment = segment(r.ds);
modrm.address = fetch(Word);
} else {
switch(modrm.reg) {
case 0: modrm.segment = segment(r.ds); modrm.address = r.bx + r.si; break;
case 1: modrm.segment = segment(r.ds); modrm.address = r.bx + r.di; break;
case 2: modrm.segment = segment(r.ss); modrm.address = r.bp + r.si; break;
case 3: modrm.segment = segment(r.ss); modrm.address = r.bp + r.di; break;
case 4: modrm.segment = segment(r.ds); modrm.address = r.si; break;
case 5: modrm.segment = segment(r.ds); modrm.address = r.di; break;
case 6: modrm.segment = segment(r.ds); modrm.address = r.bp; break;
case 7: modrm.segment = segment(r.ds); modrm.address = r.bx; break;
}
if(modrm.mod == 1) modrm.address += (int8)fetch(Byte);
if(modrm.mod == 2) modrm.address += (int16)fetch(Word);
}
return segment(s) << 16 | a;
}
auto V30MZ::getMem(Size size, uint8 modRM) -> uint32 {
if(modRM >= 0xc0) return getReg(size, modRM << 3);
auto addr = getMemAddress(modRM);
return read(size, addr >> 16, addr);
//
auto V30MZ::getMem(Size size, uint offset) -> uint16 {
if(modrm.mod != 3) return read(size, modrm.segment, modrm.address + offset);
if(size == Byte) return *r.b[modrm.mem];
if(size == Word) return *r.w[modrm.mem];
unreachable;
}
auto V30MZ::setMem(Size size, uint8 modRM, uint16 data) -> void {
if(modRM >= 0xc0) return setReg(size, modRM << 3, data);
auto addr = getMemAddress(modRM);
return write(size, addr >> 16, addr, data);
auto V30MZ::setMem(Size size, uint16 data) -> void {
if(modrm.mod != 3) return write(size, modrm.segment, modrm.address, data);
if(size == Byte) *r.b[modrm.mem] = data;
if(size == Word) *r.w[modrm.mem] = data;
}
//
auto V30MZ::getReg(Size size) -> uint16 {
if(size == Byte) return *r.b[modrm.reg];
if(size == Word) return *r.w[modrm.reg];
unreachable;
}
auto V30MZ::setReg(Size size, uint16 data) -> void {
if(size == Byte) *r.b[modrm.reg] = data;
if(size == Word) *r.w[modrm.reg] = data;
}
//
auto V30MZ::getSeg() -> uint16 {
return *r.s[modrm.reg];
}
auto V30MZ::setSeg(uint16 data) -> void {
*r.s[modrm.reg] = data;
}

View File

@ -16,41 +16,6 @@ auto V30MZ::setAcc(Size size, uint32 data) -> void {
if(size == Long) r.ax = data, r.dx = data >> 16;
}
auto V30MZ::Registers::byte(uint3 r) -> uint8& {
switch(r) {
case 0: return al;
case 1: return cl;
case 2: return dl;
case 3: return bl;
case 4: return ah;
case 5: return ch;
case 6: return dh;
case 7: return bh;
} unreachable;
}
auto V30MZ::Registers::word(uint3 r) -> uint16& {
switch(r) {
case 0: return ax;
case 1: return cx;
case 2: return dx;
case 3: return bx;
case 4: return sp;
case 5: return bp;
case 6: return si;
case 7: return di;
} unreachable;
}
auto V30MZ::Registers::segment(uint2 r) -> uint16& {
switch(r) {
case 0: return es;
case 1: return cs;
case 2: return ss;
case 3: return ds;
} unreachable;
}
//
V30MZ::Registers::Flags::operator uint16() const {

View File

@ -7,30 +7,35 @@ namespace Processor {
#include "modrm.cpp"
#include "memory.cpp"
#include "algorithms.cpp"
#include "instructions.cpp"
#include "instructions-adjust.cpp"
#include "instructions-alu.cpp"
#include "instructions-exec.cpp"
#include "instructions-flag.cpp"
#include "instructions-group.cpp"
#include "instructions-misc.cpp"
#include "instructions-move.cpp"
#include "instructions-string.cpp"
#include "disassembler.cpp"
auto V30MZ::exec() -> void {
if(halt) return wait(1);
if(state.halt) return wait(1);
#if 1
#if 0
static uint16 cs = 0, ip = 0;
if(cs != r.cs || ip != r.ip) print(disassemble(cs = r.cs, ip = r.ip), "\n");
#endif
execOpcode();
instruction();
if(prefix.hold) {
prefix.hold = false;
if(state.prefix) {
state.prefix = false;
} else {
prefix.segment = nothing;
prefix.repeat = nothing;
}
}
auto V30MZ::execOpcode() -> void {
executed++;
auto V30MZ::instruction() -> void {
auto opcode = fetch();
wait(1);
@ -66,14 +71,14 @@ auto V30MZ::execOpcode() -> void {
case 0x1c: return opSbbAccImm(Byte);
case 0x1d: return opSbbAccImm(Word);
case 0x1e: return opPushReg(r.ds);
case 0x1f: return opPopReg(r.cs);
case 0x1f: return opPopReg(r.ds);
case 0x20: return opAndMemReg(Byte);
case 0x21: return opAndMemReg(Word);
case 0x22: return opAndRegMem(Byte);
case 0x23: return opAndRegMem(Word);
case 0x24: return opAndAccImm(Byte);
case 0x25: return opAndAccImm(Word);
case 0x26: return opPrefix(r.es);
case 0x26: return opSegment(r.es);
case 0x27: return opDecimalAdjust(0); //daa
case 0x28: return opSubMemReg(Byte);
case 0x29: return opSubMemReg(Word);
@ -81,7 +86,7 @@ auto V30MZ::execOpcode() -> void {
case 0x2b: return opSubRegMem(Word);
case 0x2c: return opSubAccImm(Byte);
case 0x2d: return opSubAccImm(Word);
case 0x2e: return opPrefix(r.cs);
case 0x2e: return opSegment(r.cs);
case 0x2f: return opDecimalAdjust(1); //das
case 0x30: return opXorMemReg(Byte);
case 0x31: return opXorMemReg(Word);
@ -89,7 +94,7 @@ auto V30MZ::execOpcode() -> void {
case 0x33: return opXorRegMem(Word);
case 0x34: return opXorAccImm(Byte);
case 0x35: return opXorAccImm(Word);
case 0x36: return opPrefix(r.ss);
case 0x36: return opSegment(r.ss);
case 0x37: return opAsciiAdjust(0); //aaa
case 0x38: return opCmpMemReg(Byte);
case 0x39: return opCmpMemReg(Word);
@ -97,7 +102,7 @@ auto V30MZ::execOpcode() -> void {
case 0x3b: return opCmpRegMem(Word);
case 0x3c: return opCmpAccImm(Byte);
case 0x3d: return opCmpAccImm(Word);
case 0x3e: return opPrefix(r.ds);
case 0x3e: return opSegment(r.ds);
case 0x3f: return opAsciiAdjust(1); //aas
case 0x40: return opIncReg(r.ax);
case 0x41: return opIncReg(r.cx);
@ -190,9 +195,9 @@ auto V30MZ::execOpcode() -> void {
case 0x98: return opSignExtendByte();
case 0x99: return opSignExtendWord();
case 0x9a: return opCallFar();
//9b
//9c
//9d
case 0x9b: return opWait();
case 0x9c: return opPushFlags();
case 0x9d: return opPopFlags();
case 0x9e: return opStoreFlagsAcc();
case 0x9f: return opLoadAccFlags();
case 0xa0: return opMoveAccMem(Byte);
@ -209,8 +214,8 @@ auto V30MZ::execOpcode() -> void {
case 0xab: return opStoreString(Word);
case 0xac: return opLoadString(Byte);
case 0xad: return opLoadString(Word);
case 0xae: return opSubtractCompareString(Byte);
case 0xaf: return opSubtractCompareString(Word);
case 0xae: return opScanString(Byte);
case 0xaf: return opScanString(Word);
case 0xb0: return opMoveRegImm(r.al);
case 0xb1: return opMoveRegImm(r.cl);
case 0xb2: return opMoveRegImm(r.dl);
@ -231,26 +236,26 @@ auto V30MZ::execOpcode() -> void {
case 0xc1: return opGroup2MemImm(Word);
case 0xc2: return opReturnImm();
case 0xc3: return opReturn();
//c4
//c5
case 0xc4: return opLoadSegmentMem(r.es);
case 0xc5: return opLoadSegmentMem(r.ds);
case 0xc6: return opMoveMemImm(Byte);
case 0xc7: return opMoveMemImm(Word);
//c8
case 0xc8: return opEnter();
case 0xc9: return opLeave();
case 0xca: return opReturnFarImm();
case 0xcb: return opReturnFar();
//cc
//cd
case 0xcc: return opInt3();
case 0xcd: return opIntImm();
case 0xce: return opInto();
case 0xcf: return opReturnInt();
case 0xd0: return opGroup2MemImm(Byte, 1);
case 0xd1: return opGroup2MemImm(Word, 1);
case 0xd2: return opGroup2MemImm(Byte, r.cl);
case 0xd3: return opGroup2MemImm(Word, r.cl);
//d4
//d5
case 0xd4: return opAdjustAfterMultiply();
case 0xd5: return opAdjustAfterDivide();
case 0xd6: return;
//d7
case 0xd7: return opTranslate();
case 0xd8: return; //fpo1
case 0xd9: return; //fpo1
case 0xda: return; //fpo1
@ -268,7 +273,7 @@ auto V30MZ::execOpcode() -> void {
case 0xe6: return opOut(Byte);
case 0xe7: return opOut(Word);
case 0xe8: return opCallNear();
//e9
case 0xe9: return opJumpNear();
case 0xea: return opJumpFar();
case 0xeb: return opJumpShort();
case 0xec: return opInDX(Byte);
@ -292,17 +297,30 @@ auto V30MZ::execOpcode() -> void {
case 0xfe: return opGroup4MemImm(Byte);
case 0xff: return opGroup4MemImm(Word);
}
}
print("error: unknown opcode: ", hex(opcode, 2L), "\n");
print("executed: ", --executed, "\n");
halt = true;
auto V30MZ::interrupt(uint8 vector) -> void {
state.halt = false;
auto ip = read(Word, 0x0000, vector * 2 + 0);
auto cs = read(Word, 0x0000, vector * 2 + 2);
push(r.f);
push(r.cs);
push(r.ip);
r.f.m = true;
r.f.i = false;
r.f.b = false;
r.ip = ip;
r.cs = cs;
}
auto V30MZ::power() -> void {
halt = false;
executed = 0;
state.halt = false;
state.prefix = false;
prefix.hold = false;
prefix.segment = nothing;
prefix.repeat = nothing;

View File

@ -5,8 +5,9 @@
namespace Processor {
struct V30MZ {
using Size = const uint&;
using Size = uint;
enum : uint { Byte = 1, Word = 2, Long = 4 };
struct ModRM;
virtual auto wait(uint clocks = 1) -> void = 0;
virtual auto read(uint20 addr) -> uint8 = 0;
@ -15,7 +16,8 @@ struct V30MZ {
virtual auto out(uint16 port, uint8 data) -> void = 0;
auto exec() -> void;
auto execOpcode() -> void;
auto instruction() -> void;
auto interrupt(uint8 vector) -> void;
auto power() -> void;
//registers.cpp
@ -25,15 +27,16 @@ struct V30MZ {
auto setAcc(Size, uint32) -> void;
//modrm.cpp
auto getReg(Size, uint8) -> uint16;
auto setReg(Size, uint8, uint16) -> void;
auto modRM() -> void;
auto getSeg(uint8) -> uint16;
auto setSeg(uint8, uint16) -> void;
auto getMem(Size, uint offset = 0) -> uint16;
auto setMem(Size, uint16) -> void;
auto getMemAddress(uint8) -> uint32;
auto getMem(Size, uint8) -> uint32;
auto setMem(Size, uint8, uint16) -> void;
auto getReg(Size) -> uint16;
auto setReg(Size, uint16) -> void;
auto getSeg() -> uint16;
auto setSeg(uint16) -> void;
//memory.cpp
auto read(Size, uint16, uint16) -> uint32;
@ -47,7 +50,7 @@ struct V30MZ {
auto push(uint16) -> void;
//algorithms.cpp
auto parity(uint16) const -> bool;
auto parity(uint8) const -> bool;
auto alAdc(Size, uint16, uint16) -> uint16;
auto alAdd(Size, uint16, uint16) -> uint16;
auto alAnd(Size, uint16, uint16) -> uint16;
@ -72,7 +75,13 @@ struct V30MZ {
auto alShr(Size, uint16, uint5 ) -> uint16;
auto alXor(Size, uint16, uint16) -> uint16;
//instructions.cpp
//instructions-adjust.cpp
auto opDecimalAdjust(bool);
auto opAsciiAdjust(bool);
auto opAdjustAfterMultiply();
auto opAdjustAfterDivide();
//instructions-alu.cpp
auto opAddMemReg(Size);
auto opAddRegMem(Size);
auto opAddAccImm(Size);
@ -88,9 +97,6 @@ struct V30MZ {
auto opAndMemReg(Size);
auto opAndRegMem(Size);
auto opAndAccImm(Size);
auto opPrefix(uint16&);
auto opDecimalAdjust(bool);
auto opAsciiAdjust(bool);
auto opSubMemReg(Size);
auto opSubRegMem(Size);
auto opSubAccImm(Size);
@ -100,90 +106,116 @@ struct V30MZ {
auto opCmpMemReg(Size);
auto opCmpRegMem(Size);
auto opCmpAccImm(Size);
auto opTestMemReg(Size);
auto opTestAcc(Size);
auto opMultiplySignedRegMemImm(Size);
auto opIncReg(uint16&);
auto opDecReg(uint16&);
auto opPushReg(uint16&);
auto opPopReg(uint16&);
auto opPushAll();
auto opPopAll();
auto opBound();
auto opPushImm(Size);
auto opMultiplySignedRegMemImm(Size);
auto opStoreFlagsAcc();
auto opLoadAccFlags();
auto opJumpIf(bool);
auto opGroup1MemImm(Size, bool);
auto opTestMemReg(Size);
auto opExchangeMemReg(Size);
auto opMoveMemReg(Size);
auto opMoveRegMem(Size);
auto opMoveMemSeg();
auto opLoadEffectiveAddressRegMem();
auto opMoveSegMem();
auto opPopMem();
auto opNop();
auto opExchange(uint16&, uint16&);
auto opSignExtendByte();
auto opSignExtendWord();
auto opCallFar();
auto opMoveAccMem(Size);
auto opMoveMemAcc(Size);
auto opInString(Size);
auto opOutString(Size);
auto opMoveString(Size);
auto opCompareString(Size);
auto opTestAcc(Size);
auto opStoreString(Size);
auto opLoadString(Size);
auto opSubtractCompareString(Size);
auto opMoveRegImm(uint8&);
auto opMoveRegImm(uint16&);
auto opReturnImm();
auto opReturn();
auto opMoveMemImm(Size);
auto opReturnFarImm();
auto opReturnFar();
auto opReturnInt();
auto opInto();
auto opLeave();
auto opGroup2MemImm(Size, maybe<uint8> = {});
auto opGroup3MemImm(Size);
auto opGroup4MemImm(Size);
auto opLoopWhile(bool);
//instructions-exec.cpp
auto opLoop();
auto opIn(Size);
auto opOut(Size);
auto opCallNear();
auto opJumpFar();
auto opLoopWhile(bool);
auto opJumpShort();
auto opInDX(Size);
auto opOutDX(Size);
auto opLock();
auto opRepeat(bool);
auto opHalt();
auto opJumpIf(bool);
auto opJumpNear();
auto opJumpFar();
auto opCallNear();
auto opCallFar();
auto opReturn();
auto opReturnImm();
auto opReturnFar();
auto opReturnFarImm();
auto opReturnInt();
auto opInt3();
auto opIntImm();
auto opInto();
auto opEnter();
auto opLeave();
auto opPushReg(uint16&);
auto opPopReg(uint16&);
auto opPushFlags();
auto opPopFlags();
auto opPushAll();
auto opPopAll();
auto opPushImm(Size);
auto opPopMem();
//instructions-flag.cpp
auto opStoreFlagsAcc();
auto opLoadAccFlags();
auto opComplementCarry();
auto opClearFlag(bool&);
auto opSetFlag(bool&);
//instructions-group.cpp
auto opGroup1MemImm(Size, bool);
auto opGroup2MemImm(Size, maybe<uint8> = {});
auto opGroup3MemImm(Size);
auto opGroup4MemImm(Size);
//instructions-misc.cpp
auto opSegment(uint16);
auto opRepeat(bool);
auto opLock();
auto opWait();
auto opHalt();
auto opNop();
auto opIn(Size);
auto opOut(Size);
auto opInDX(Size);
auto opOutDX(Size);
auto opTranslate();
auto opBound();
//instructions-move.cpp
auto opMoveMemReg(Size);
auto opMoveRegMem(Size);
auto opMoveMemSeg();
auto opMoveSegMem();
auto opMoveAccMem(Size);
auto opMoveMemAcc(Size);
auto opMoveRegImm(uint8&);
auto opMoveRegImm(uint16&);
auto opMoveMemImm(Size);
auto opExchange(uint16&, uint16&);
auto opExchangeMemReg(Size);
auto opLoadEffectiveAddressRegMem();
auto opLoadSegmentMem(uint16&);
//instructions-string.cpp
auto opInString(Size);
auto opOutString(Size);
auto opMoveString(Size);
auto opCompareString(Size);
auto opStoreString(Size);
auto opLoadString(Size);
auto opScanString(Size);
//disassembler.cpp
auto disassemble(uint16 cs, uint16 ip, bool registers = true, bool bytes = true) -> string;
//state
bool halt = false;
uint executed = 0;
struct State {
bool halt;
bool prefix;
} state;
struct Prefix {
bool hold;
maybe<uint16> segment;
maybe<bool> repeat;
} prefix;
struct Registers {
//registers.cpp
auto byte(uint3) -> uint8&;
auto word(uint3) -> uint16&;
auto segment(uint2) -> uint16&;
struct ModRM {
uint2 mod;
uint3 reg;
uint3 mem;
uint16 address;
uint16 segment;
} modrm;
struct Registers {
uint16 ip;
union { uint16 ax; struct { uint8 order_lsb2(al, ah); }; };
union { uint16 bx; struct { uint8 order_lsb2(bl, bh); }; };
@ -198,6 +230,10 @@ struct V30MZ {
uint16 es;
uint16 ss;
uint8* b[8]{&al, &cl, &dl, &bl, &ah, &ch, &dh, &bh};
uint16* w[8]{&ax, &cx, &dx, &bx, &sp, &bp, &si, &di};
uint16* s[8]{&es, &cs, &ss, &ds, &es, &cs, &ss, &ds};
struct Flags {
//registers.cpp
operator uint16() const;

View File

@ -4,6 +4,8 @@ namespace WonderSwan {
CPU cpu;
#include "memory.cpp"
#include "io.cpp"
#include "dma.cpp"
auto CPU::Enter() -> void {
cpu.main();
@ -53,6 +55,17 @@ auto CPU::power() -> void {
create(CPU::Enter, 3072000);
iomap[0x00a0] = this;
if(WSC() || SC()) {
for(uint p = 0x0040; p <= 0x0049; p++) iomap[p] = this;
iomap[0x0062] = this;
}
s.dmaSource = 0x00000;
s.dmaTarget = 0x0000;
s.dmaLength = 0x0000;
s.dmaEnable = false;
s.dmaMode = 0;
}
}

View File

@ -16,8 +16,27 @@ struct CPU : Processor::V30MZ, Thread, IO {
auto ramRead(uint16 addr) -> uint8;
auto ramWrite(uint16 addr, uint8 data) -> void;
//io.cpp
auto portRead(uint16 addr) -> uint8 override;
auto portWrite(uint16 addr, uint8 data) -> void override;
//dma.cpp
auto dmaTransfer() -> void;
struct State {
//$0040-0042 DMA_SRC
uint20 dmaSource;
//$0044-0045 DMA_DST
uint16_ dmaTarget;
//$0046-0047 DMA_LEN
uint16_ dmaLength;
//$0048 DMA_CTRL
bool dmaEnable;
bool dmaMode; //0 = increment; 1 = decrement
} s;
};
extern CPU cpu;

29
higan/ws/cpu/dma.cpp Normal file
View File

@ -0,0 +1,29 @@
auto CPU::dmaTransfer() -> void {
//length of 0 or SRAM source address cause immediate termination
if(s.dmaLength == 0 || s.dmaSource.b2 == 1) {
s.dmaEnable = false;
return;
}
wait(5);
while(s.dmaLength) {
wait(2);
uint16 data = 0;
//once DMA is started; SRAM reads still incur time penalty, but do not transfer
if(s.dmaSource.b2 != 1) {
data |= read(s.dmaSource + 0) << 0;
data |= read(s.dmaSource + 1) << 8;
write(s.dmaTarget + 0, data >> 0);
write(s.dmaTarget + 1, data >> 8);
}
if(s.dmaMode == 0) {
s.dmaSource += 2;
s.dmaTarget += 2;
} else {
s.dmaSource -= 2;
s.dmaTarget -= 2;
}
s.dmaLength -= 2;
};
s.dmaEnable = false;
}

65
higan/ws/cpu/io.cpp Normal file
View File

@ -0,0 +1,65 @@
auto CPU::portRead(uint16 addr) -> uint8 {
//DMA_SRC
if(addr == 0x0040) return s.dmaSource.b0;
if(addr == 0x0041) return s.dmaSource.b1;
if(addr == 0x0042) return s.dmaSource.b2;
//DMA_DST
if(addr == 0x0044) return s.dmaTarget.b0;
if(addr == 0x0045) return s.dmaTarget.b1;
//DMA_LEN
if(addr == 0x0046) return s.dmaLength.b0;
if(addr == 0x0047) return s.dmaLength.b1;
//DMA_CTRL
if(addr == 0x0048) return s.dmaEnable << 7 | s.dmaMode << 0;
//WSC_SYSTEM
if(addr == 0x0062) {
return SC() << 7;
}
//HW_FLAGS
if(addr == 0x00a0) {
return 1 << 7 //1 = built-in self-test passed
| 1 << 2 //0 = 8-bit bus width; 1 = 16-bit bus width
| !WS() << 1 //0 = WonderSwan; 1 = WonderSwan Color or SwanCrystal
| 1 << 0; //0 = BIOS mapped; 1 = cartridge mapped
}
return 0x00;
}
auto CPU::portWrite(uint16 addr, uint8 data) -> void {
//DMA_SRC
if(addr == 0x0040) { s.dmaSource.b0 = data & ~1; return; }
if(addr == 0x0041) { s.dmaSource.b1 = data; return; }
if(addr == 0x0042) { s.dmaSource.b2 = data; return; }
//DMA_DST
if(addr == 0x0044) { s.dmaTarget.b0 = data & ~1; return; }
if(addr == 0x0045) { s.dmaTarget.b1 = data; return; }
//DMA_LEN
if(addr == 0x0046) { s.dmaLength.b0 = data & ~1; return; }
if(addr == 0x0047) { s.dmaLength.b1 = data; return; }
//DMA_CTRL
if(addr == 0x0048) {
s.dmaEnable = (uint1)(data >> 7);
s.dmaMode = (uint1)(data >> 0);
if(s.dmaEnable) dmaTransfer();
return;
}
//WSC_SYSTEM
if(addr == 0x0062) {
//todo: d0 = 1 powers off system
}
//HW_FLAGS
if(addr == 0x00a0) {
//todo: d2 (bus width) bit is writable; but ... it will do very bad things
}
}

View File

@ -7,22 +7,3 @@ auto CPU::ramWrite(uint16 addr, uint8 data) -> void {
if(WS() && addr >= 0x4000) return;
iram[addr] = data;
}
auto CPU::portRead(uint16 addr) -> uint8 {
//HW_FLAGS
if(addr == 0x00a0) {
return 1 << 7 //1 = built-in self-test passed
| 1 << 2 //0 = 8-bit bus width; 1 = 16-bit bus width
| !WS() << 1 //0 = WonderSwan; 1 = WonderSwan Color or SwanCrystal
| 1 << 0; //0 = BIOS mapped; 1 = cartridge mapped
}
return 0x00; //should never occur
}
auto CPU::portWrite(uint16 addr, uint8 data) -> void {
//HW_FLAGS
if(addr == 0x00a0) {
//todo: d2 (bus width) bit is writable; but ... it will do very bad things
}
}

View File

@ -12,12 +12,12 @@ auto IO::power() -> void {
}
auto IO::portRead(uint16 addr) -> uint8 {
//print("[", hex(addr, 4L), "]: port unmapped\n");
print("[", hex(addr, 4L), "]: port unmapped\n");
return 0x00;
}
auto IO::portWrite(uint16 addr, uint8 data) -> void {
//print("[", hex(addr, 4L), "] = ", hex(data, 2L), ": port unmapped\n");
print("[", hex(addr, 4L), "] = ", hex(data, 2L), ": port unmapped\n");
}
auto Bus::read(uint20 addr) -> uint8 {

216
higan/ws/ppu/io.cpp Normal file
View File

@ -0,0 +1,216 @@
auto PPU::portRead(uint16 addr) -> uint8 {
//DISP_CTRL
if(addr == 0x0000) {
return (
r.screenTwoWindowEnable << 5
| r.screenTwoWindowMode << 4
| r.spriteWindowEnable << 3
| r.spriteEnable << 2
| r.screenTwoEnable << 1
| r.screenOneEnable << 0
);
}
//BACK_COLOR
if(addr == 0x0001) return r.backColorPalette << 4 | r.backColorIndex << 0;
//SPR_BASE
if(addr == 0x0004) return r.spriteBase;
//SPR_FIRST
if(addr == 0x0005) return r.spriteFirst;
//SPR_COUNT
if(addr == 0x0006) return r.spriteCount;
//MAP_BASE
if(addr == 0x0007) return r.screenTwoMapBase << 4 | r.screenOneMapBase << 0;
//SCR1_X
if(addr == 0x0010) return r.scrollOneX;
//SCR1_Y
if(addr == 0x0011) return r.scrollOneY;
//SCR2_X
if(addr == 0x0012) return r.scrollTwoX;
//SCR2_Y
if(addr == 0x0013) return r.scrollTwoY;
//LCD_CTRL
if(addr == 0x0014) return r.control;
//LCD_ICON
if(addr == 0x0015) {
return (
r.iconAux3 << 5
| r.iconAux2 << 4
| r.iconAux1 << 3
| r.iconHorizontal << 2
| r.iconVertical << 1
| r.iconSleep << 0
);
}
//PALMONO_POOL_0
if(addr == 0x001c) return r.monoPool[0] << 0 | r.monoPool[1] << 4;
//PALMONO_POOL_1
if(addr == 0x001d) return r.monoPool[2] << 0 | r.monoPool[3] << 4;
//PALMONO_POOL_2
if(addr == 0x001e) return r.monoPool[4] << 0 | r.monoPool[5] << 4;
//PALMONO_POOL_3
if(addr == 0x001f) return r.monoPool[6] << 0 | r.monoPool[7] << 4;
//DISP_MODE
if(addr == 0x0060) {
return (
r.bpp << 7
| r.color << 6
| r.format << 5
| r.u0060 << 0
);
}
return 0x00;
}
auto PPU::portWrite(uint16 addr, uint8 data) -> void {
//DISP_CTRL
if(addr == 0x0000) {
r.screenTwoWindowEnable = data & 0x20;
r.screenTwoWindowMode = data & 0x10;
r.spriteWindowEnable = data & 0x08;
r.spriteEnable = data & 0x04;
r.screenTwoEnable = data & 0x02;
r.screenOneEnable = data & 0x01;
return;
}
//BACK_COLOR
if(addr == 0x0001) {
if(WS()) {
r.backColorPalette = 0;
r.backColorIndex = (uint3)(data >> 0);
} else {
r.backColorPalette = (uint4)(data >> 4);
r.backColorIndex = (uint4)(data >> 0);
}
return;
}
//SPR_BASE
if(addr == 0x0004) {
if(WS()) {
r.spriteBase = (uint5)data;
} else {
r.spriteBase = (uint6)data;
}
return;
}
//SPR_FIRST
if(addr == 0x0005) {
r.spriteFirst = data;
return;
}
//SPR_COUNT
if(addr == 0x0006) {
r.spriteCount = data;
return;
}
//MAP_BASE
if(addr == 0x0007) {
if(WS()) {
r.screenTwoMapBase = (uint3)(data >> 4);
r.screenOneMapBase = (uint3)(data >> 0);
} else {
r.screenTwoMapBase = (uint4)(data >> 4);
r.screenOneMapBase = (uint4)(data >> 0);
}
return;
}
//SCR1_X
if(addr == 0x0010) {
r.scrollOneX = data;
return;
}
//SCR1_Y
if(addr == 0x0011) {
r.scrollOneY = data;
return;
}
//SCR2_X
if(addr == 0x0012) {
r.scrollTwoX = data;
return;
}
//SCR2_Y
if(addr == 0x0013) {
r.scrollTwoY = data;
return;
}
//LCD_CTRL
if(addr == 0x0014) {
r.control = data;
return;
}
//LCD_ICON
if(addr == 0x0015) {
r.iconAux3 = data & 0x20;
r.iconAux2 = data & 0x10;
r.iconAux1 = data & 0x08;
r.iconHorizontal = data & 0x04;
r.iconVertical = data & 0x02;
r.iconSleep = data & 0x01;
return;
}
//PALMONO_POOL_0
if(addr == 0x001c) {
r.monoPool[0] = data >> 0;
r.monoPool[1] = data >> 4;
return;
}
//PALMONO_POOL_1
if(addr == 0x001d) {
r.monoPool[2] = data >> 0;
r.monoPool[3] = data >> 4;
return;
}
//PALMONO_POOL_2
if(addr == 0x001e) {
r.monoPool[4] = data >> 0;
r.monoPool[5] = data >> 4;
return;
}
//PALMONO_POOL_3
if(addr == 0x001f) {
r.monoPool[6] = data >> 0;
r.monoPool[7] = data >> 4;
return;
}
//DISP_MODE
if(addr == 0x0060) {
r.bpp = data & 0x80;
r.color = data & 0x40;
r.format = data & 0x20;
r.u0060 = data & 0b1011;
return;
}
}

View File

@ -3,6 +3,7 @@
namespace WonderSwan {
PPU ppu;
#include "io.cpp"
#include "video.cpp"
auto PPU::Enter() -> void {
@ -35,6 +36,12 @@ auto PPU::step(uint clocks) -> void {
auto PPU::power() -> void {
create(PPU::Enter, 3072000);
for(uint n = 0x0000; n <= 0x0001; n++) iomap[n] = this;
for(uint n = 0x0004; n <= 0x0007; n++) iomap[n] = this;
for(uint n = 0x0010; n <= 0x0015; n++) iomap[n] = this;
for(uint n = 0x001c; n <= 0x001f; n++) iomap[n] = this;
iomap[0x0060] = this;
for(auto& n : output) n = 0;
status.vclk = 0;

View File

@ -1,18 +1,80 @@
#include "video.hpp"
struct PPU : Thread {
struct PPU : Thread, IO {
static auto Enter() -> void;
auto main() -> void;
auto step(uint clocks) -> void;
auto power() -> void;
auto portRead(uint16 addr) -> uint8 override;
auto portWrite(uint16 addr, uint8 data) -> void override;
uint16 output[224 * 144] = {0};
struct Status {
uint vclk;
uint hclk;
} status;
struct Registers {
//$0000 DISP_CTRL
bool screenTwoWindowEnable;
bool screenTwoWindowMode;
bool spriteWindowEnable;
bool spriteEnable;
bool screenTwoEnable;
bool screenOneEnable;
//$0001 BACK_COLOR
uint4 backColorIndex;
uint4 backColorPalette;
//$0004 SPR_BASE
uint6 spriteBase;
//$0005 SPR_FIRST
uint7 spriteFirst;
//$0006 SPR_COUNT
uint8 spriteCount; //0 - 128
//$0007 MAP_BASE
uint4 screenTwoMapBase;
uint4 screenOneMapBase;
//$0010 SCR1_X
uint8 scrollOneX;
//$0011 SCR1_Y
uint8 scrollOneY;
//$0012 SCR2_X
uint8 scrollTwoX;
//$0013 SCR2_Y
uint8 scrollTwoY;
//$0014 LCD_CTRL
uint8 control;
//$0015 LCD_ICON
bool iconAux3;
bool iconAux2;
bool iconAux1;
bool iconHorizontal;
bool iconVertical;
bool iconSleep;
//$001c-001f PALMONO_POOL
uint4 monoPool[8];
//$0060 DISP_MODE
bool bpp;
bool color;
bool format;
uint5 u0060; //unknown purpose
} r;
};
extern PPU ppu;

View File

@ -86,7 +86,7 @@ using int4 = nall::Integer< 4>;
using int5 = nall::Integer< 5>;
using int6 = nall::Integer< 6>;
using int7 = nall::Integer< 7>;
//using int8 = nall::Integer< 8>;
using int8_= nall::Integer< 8>;
using int9 = nall::Integer< 9>;
using int10 = nall::Integer<10>;
using int11 = nall::Integer<11>;
@ -94,7 +94,7 @@ using int12 = nall::Integer<12>;
using int13 = nall::Integer<13>;
using int14 = nall::Integer<14>;
using int15 = nall::Integer<15>;
//using int16 = nall::Integer<16>;
using int16_= nall::Integer<16>;
using int17 = nall::Integer<17>;
using int18 = nall::Integer<18>;
using int19 = nall::Integer<19>;
@ -110,7 +110,7 @@ using int28 = nall::Integer<28>;
using int29 = nall::Integer<29>;
using int30 = nall::Integer<30>;
using int31 = nall::Integer<31>;
//using int32 = nall::Integer<32>;
using int32_= nall::Integer<32>;
using int33 = nall::Integer<33>;
using int34 = nall::Integer<34>;
using int35 = nall::Integer<35>;
@ -142,7 +142,7 @@ using int60 = nall::Integer<60>;
using int61 = nall::Integer<61>;
using int62 = nall::Integer<62>;
using int63 = nall::Integer<63>;
//using int64 = nall::Integer<64>;
using int64_= nall::Integer<64>;
using uint1 = nall::Natural< 1>;
using uint2 = nall::Natural< 2>;
@ -151,7 +151,7 @@ using uint4 = nall::Natural< 4>;
using uint5 = nall::Natural< 5>;
using uint6 = nall::Natural< 6>;
using uint7 = nall::Natural< 7>;
//using uint8 = nall::Natural< 8>;
using uint8_= nall::Natural< 8>;
using uint9 = nall::Natural< 9>;
using uint10 = nall::Natural<10>;
using uint11 = nall::Natural<11>;
@ -159,7 +159,7 @@ using uint12 = nall::Natural<12>;
using uint13 = nall::Natural<13>;
using uint14 = nall::Natural<14>;
using uint15 = nall::Natural<15>;
//using uint16 = nall::Natural<16>;
using uint16_= nall::Natural<16>;
using uint17 = nall::Natural<17>;
using uint18 = nall::Natural<18>;
using uint19 = nall::Natural<19>;
@ -175,7 +175,7 @@ using uint28 = nall::Natural<28>;
using uint29 = nall::Natural<29>;
using uint30 = nall::Natural<30>;
using uint31 = nall::Natural<31>;
//using uint32 = nall::Natural<32>;
using uint32_= nall::Natural<32>;
using uint33 = nall::Natural<33>;
using uint34 = nall::Natural<34>;
using uint35 = nall::Natural<35>;
@ -207,4 +207,4 @@ using uint60 = nall::Natural<60>;
using uint61 = nall::Natural<61>;
using uint62 = nall::Natural<62>;
using uint63 = nall::Natural<63>;
//using uint64 = nall::Natural<64>;
using uint64_= nall::Natural<64>;