mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
d158c8f293
commit
7a748e093e
|
@ -6,7 +6,7 @@ using namespace nall;
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
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 Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "http://byuu.org/";
|
static const string Website = "http://byuu.org/";
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
//(0 = odd, 1 = even) number of bits set in value
|
//(0 = odd, 1 = even) number of bits set in value
|
||||||
auto V30MZ::parity(uint16 value) const -> bool {
|
auto V30MZ::parity(uint8 value) const -> bool {
|
||||||
value ^= value >> 8;
|
|
||||||
value ^= value >> 4;
|
value ^= value >> 4;
|
||||||
value ^= value >> 2;
|
value ^= value >> 2;
|
||||||
value ^= value >> 1;
|
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 {
|
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 quotient = x / y;
|
||||||
uint32 remainder = x % y;
|
uint32 remainder = x % y;
|
||||||
return (remainder & mask) << bits | (quotient & mask);
|
return (remainder & mask) << bits | (quotient & mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::alDivi(Size size, int32 x, int32 y) -> uint32 {
|
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;
|
x = size == Byte ? (int8)x : (int16)x;
|
||||||
y = size == Byte ? (int8)y : (int16)y;
|
y = size == Byte ? (int8)y : (int16)y;
|
||||||
uint32 quotient = x / y;
|
uint32 quotient = x / y;
|
||||||
|
|
|
@ -237,6 +237,9 @@ auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers, bool bytes) -> str
|
||||||
case 0x98: s = {"cbw "}; break;
|
case 0x98: s = {"cbw "}; break;
|
||||||
case 0x99: s = {"cwd "}; break;
|
case 0x99: s = {"cwd "}; break;
|
||||||
case 0x9a: s = {"call {1}:{0}", format{readWord(), readWord()}}; 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 0x9e: s = {"sahf "}; break;
|
||||||
case 0x9f: s = {"lahf "}; break;
|
case 0x9f: s = {"lahf "}; break;
|
||||||
case 0xa0: s = {"mov al,{0}", format{readIndirectByte()}}; 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 0xc1: s = {"{0} {1},{2}", format{readGroup(2), readMemWord(), readByte()}}; break;
|
||||||
case 0xc2: s = {"ret {0}", format{readWord()}}; break;
|
case 0xc2: s = {"ret {0}", format{readWord()}}; break;
|
||||||
case 0xc3: s = {"ret "}; 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 0xc6: s = {"mov {0},{1}", format{readMemByte(), readByte()}}; break;
|
||||||
case 0xc7: s = {"mov {0},{1}", format{readMemWord(), readWord()}}; 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 0xc9: s = {"leave "}; break;
|
||||||
case 0xca: s = {"retf {0}", format{readWord()}}; break;
|
case 0xca: s = {"retf {0}", format{readWord()}}; break;
|
||||||
case 0xcb: s = {"retf "}; break;
|
case 0xcb: s = {"retf "}; break;
|
||||||
|
case 0xcc: s = {"int3 "}; break;
|
||||||
|
case 0xcd: s = {"int ", format{readByte()}}; break;
|
||||||
case 0xce: s = {"into "}; break;
|
case 0xce: s = {"into "}; break;
|
||||||
case 0xcf: s = {"iret "}; break;
|
case 0xcf: s = {"iret "}; break;
|
||||||
case 0xd0: s = {"{0} {1},1", format{readGroup(2), readMemByte()}}; break;
|
case 0xd0: s = {"{0} {1},1", format{readGroup(2), readMemByte()}}; break;
|
||||||
case 0xd1: s = {"{0} {1},1", format{readGroup(2), readMemWord()}}; break;
|
case 0xd1: s = {"{0} {1},1", format{readGroup(2), readMemWord()}}; break;
|
||||||
case 0xd2: s = {"{0} {1},cl", format{readGroup(2), readMemByte()}}; break;
|
case 0xd2: s = {"{0} {1},cl", format{readGroup(2), readMemByte()}}; break;
|
||||||
case 0xd3: s = {"{0} {1},cl", format{readGroup(2), readMemWord()}}; 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 0xd8:
|
||||||
//case 0xd9:
|
//case 0xd9:
|
||||||
//case 0xda:
|
//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 0xe6: s = {"out {0},al", format{readByte()}}; break;
|
||||||
case 0xe7: s = {"out {0},ax", format{readByte()}}; break;
|
case 0xe7: s = {"out {0},ax", format{readByte()}}; break;
|
||||||
case 0xe8: s = {"call {0}", format{readRelativeWord()}}; 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 0xea: s = {"jmp {1}:{0}", format{readWord(), readWord()}}; break;
|
||||||
case 0xeb: s = {"jmp {0}", format{readRelativeByte()}}; break;
|
case 0xeb: s = {"jmp {0}", format{readRelativeByte()}}; break;
|
||||||
case 0xec: s = {"in al,dx"}; 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 0xfd: s = {"std "}; break;
|
||||||
case 0xfe: s = {"{0} {1},{2}", format{readGroup(4), readMemByte(), readByte()}}; 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;
|
case 0xff: s = {"{0} {1},{2}", format{readGroup(4), readMemWord(), readWord()}}; break;
|
||||||
|
default: s = {"??? {0}", format{hex(opcode, 2L)}}; break;
|
||||||
default:
|
|
||||||
s = {"??? [", hex(opcode, 2L), "]"};
|
|
||||||
}
|
}
|
||||||
while(s.size() < 24) s.append(" ");
|
while(s.size() < 24) s.append(" ");
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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));
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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--;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -3,56 +3,65 @@
|
||||||
//d5-d3 => reg
|
//d5-d3 => reg
|
||||||
//d2-d0 => mem
|
//d2-d0 => mem
|
||||||
|
|
||||||
auto V30MZ::getReg(Size size, uint8 modRM) -> uint16 {
|
auto V30MZ::modRM() -> void {
|
||||||
return size == Byte ? r.byte(modRM >> 3) : r.word(modRM >> 3);
|
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(modrm.mod == 0 && modrm.mem == 6) {
|
||||||
if(size == Byte) r.byte(modRM >> 3) = data;
|
modrm.segment = segment(r.ds);
|
||||||
if(size == Word) r.word(modRM >> 3) = data;
|
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;
|
||||||
auto V30MZ::getSeg(uint8 modRM) -> uint16 {
|
case 2: modrm.segment = segment(r.ss); modrm.address = r.bp + r.si; break;
|
||||||
return r.segment(modRM >> 3);
|
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;
|
||||||
auto V30MZ::setSeg(uint8 modRM, uint16 data) -> void {
|
case 6: modrm.segment = segment(r.ds); modrm.address = r.bp; break;
|
||||||
r.segment(modRM >> 3) = data;
|
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);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
auto V30MZ::getMem(Size size, uint offset) -> uint16 {
|
||||||
return read(size, addr >> 16, addr);
|
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 {
|
auto V30MZ::setMem(Size size, uint16 data) -> void {
|
||||||
if(modRM >= 0xc0) return setReg(size, modRM << 3, data);
|
if(modrm.mod != 3) return write(size, modrm.segment, modrm.address, data);
|
||||||
auto addr = getMemAddress(modRM);
|
if(size == Byte) *r.b[modrm.mem] = data;
|
||||||
return write(size, addr >> 16, addr, 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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,41 +16,6 @@ auto V30MZ::setAcc(Size size, uint32 data) -> void {
|
||||||
if(size == Long) r.ax = data, r.dx = data >> 16;
|
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 {
|
V30MZ::Registers::Flags::operator uint16() const {
|
||||||
|
|
|
@ -7,30 +7,35 @@ namespace Processor {
|
||||||
#include "modrm.cpp"
|
#include "modrm.cpp"
|
||||||
#include "memory.cpp"
|
#include "memory.cpp"
|
||||||
#include "algorithms.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"
|
#include "disassembler.cpp"
|
||||||
|
|
||||||
auto V30MZ::exec() -> void {
|
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;
|
static uint16 cs = 0, ip = 0;
|
||||||
if(cs != r.cs || ip != r.ip) print(disassemble(cs = r.cs, ip = r.ip), "\n");
|
if(cs != r.cs || ip != r.ip) print(disassemble(cs = r.cs, ip = r.ip), "\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
execOpcode();
|
instruction();
|
||||||
|
|
||||||
if(prefix.hold) {
|
if(state.prefix) {
|
||||||
prefix.hold = false;
|
state.prefix = false;
|
||||||
} else {
|
} else {
|
||||||
prefix.segment = nothing;
|
prefix.segment = nothing;
|
||||||
prefix.repeat = nothing;
|
prefix.repeat = nothing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::execOpcode() -> void {
|
auto V30MZ::instruction() -> void {
|
||||||
executed++;
|
|
||||||
|
|
||||||
auto opcode = fetch();
|
auto opcode = fetch();
|
||||||
wait(1);
|
wait(1);
|
||||||
|
|
||||||
|
@ -66,14 +71,14 @@ auto V30MZ::execOpcode() -> void {
|
||||||
case 0x1c: return opSbbAccImm(Byte);
|
case 0x1c: return opSbbAccImm(Byte);
|
||||||
case 0x1d: return opSbbAccImm(Word);
|
case 0x1d: return opSbbAccImm(Word);
|
||||||
case 0x1e: return opPushReg(r.ds);
|
case 0x1e: return opPushReg(r.ds);
|
||||||
case 0x1f: return opPopReg(r.cs);
|
case 0x1f: return opPopReg(r.ds);
|
||||||
case 0x20: return opAndMemReg(Byte);
|
case 0x20: return opAndMemReg(Byte);
|
||||||
case 0x21: return opAndMemReg(Word);
|
case 0x21: return opAndMemReg(Word);
|
||||||
case 0x22: return opAndRegMem(Byte);
|
case 0x22: return opAndRegMem(Byte);
|
||||||
case 0x23: return opAndRegMem(Word);
|
case 0x23: return opAndRegMem(Word);
|
||||||
case 0x24: return opAndAccImm(Byte);
|
case 0x24: return opAndAccImm(Byte);
|
||||||
case 0x25: return opAndAccImm(Word);
|
case 0x25: return opAndAccImm(Word);
|
||||||
case 0x26: return opPrefix(r.es);
|
case 0x26: return opSegment(r.es);
|
||||||
case 0x27: return opDecimalAdjust(0); //daa
|
case 0x27: return opDecimalAdjust(0); //daa
|
||||||
case 0x28: return opSubMemReg(Byte);
|
case 0x28: return opSubMemReg(Byte);
|
||||||
case 0x29: return opSubMemReg(Word);
|
case 0x29: return opSubMemReg(Word);
|
||||||
|
@ -81,7 +86,7 @@ auto V30MZ::execOpcode() -> void {
|
||||||
case 0x2b: return opSubRegMem(Word);
|
case 0x2b: return opSubRegMem(Word);
|
||||||
case 0x2c: return opSubAccImm(Byte);
|
case 0x2c: return opSubAccImm(Byte);
|
||||||
case 0x2d: return opSubAccImm(Word);
|
case 0x2d: return opSubAccImm(Word);
|
||||||
case 0x2e: return opPrefix(r.cs);
|
case 0x2e: return opSegment(r.cs);
|
||||||
case 0x2f: return opDecimalAdjust(1); //das
|
case 0x2f: return opDecimalAdjust(1); //das
|
||||||
case 0x30: return opXorMemReg(Byte);
|
case 0x30: return opXorMemReg(Byte);
|
||||||
case 0x31: return opXorMemReg(Word);
|
case 0x31: return opXorMemReg(Word);
|
||||||
|
@ -89,7 +94,7 @@ auto V30MZ::execOpcode() -> void {
|
||||||
case 0x33: return opXorRegMem(Word);
|
case 0x33: return opXorRegMem(Word);
|
||||||
case 0x34: return opXorAccImm(Byte);
|
case 0x34: return opXorAccImm(Byte);
|
||||||
case 0x35: return opXorAccImm(Word);
|
case 0x35: return opXorAccImm(Word);
|
||||||
case 0x36: return opPrefix(r.ss);
|
case 0x36: return opSegment(r.ss);
|
||||||
case 0x37: return opAsciiAdjust(0); //aaa
|
case 0x37: return opAsciiAdjust(0); //aaa
|
||||||
case 0x38: return opCmpMemReg(Byte);
|
case 0x38: return opCmpMemReg(Byte);
|
||||||
case 0x39: return opCmpMemReg(Word);
|
case 0x39: return opCmpMemReg(Word);
|
||||||
|
@ -97,7 +102,7 @@ auto V30MZ::execOpcode() -> void {
|
||||||
case 0x3b: return opCmpRegMem(Word);
|
case 0x3b: return opCmpRegMem(Word);
|
||||||
case 0x3c: return opCmpAccImm(Byte);
|
case 0x3c: return opCmpAccImm(Byte);
|
||||||
case 0x3d: return opCmpAccImm(Word);
|
case 0x3d: return opCmpAccImm(Word);
|
||||||
case 0x3e: return opPrefix(r.ds);
|
case 0x3e: return opSegment(r.ds);
|
||||||
case 0x3f: return opAsciiAdjust(1); //aas
|
case 0x3f: return opAsciiAdjust(1); //aas
|
||||||
case 0x40: return opIncReg(r.ax);
|
case 0x40: return opIncReg(r.ax);
|
||||||
case 0x41: return opIncReg(r.cx);
|
case 0x41: return opIncReg(r.cx);
|
||||||
|
@ -190,9 +195,9 @@ auto V30MZ::execOpcode() -> void {
|
||||||
case 0x98: return opSignExtendByte();
|
case 0x98: return opSignExtendByte();
|
||||||
case 0x99: return opSignExtendWord();
|
case 0x99: return opSignExtendWord();
|
||||||
case 0x9a: return opCallFar();
|
case 0x9a: return opCallFar();
|
||||||
//9b
|
case 0x9b: return opWait();
|
||||||
//9c
|
case 0x9c: return opPushFlags();
|
||||||
//9d
|
case 0x9d: return opPopFlags();
|
||||||
case 0x9e: return opStoreFlagsAcc();
|
case 0x9e: return opStoreFlagsAcc();
|
||||||
case 0x9f: return opLoadAccFlags();
|
case 0x9f: return opLoadAccFlags();
|
||||||
case 0xa0: return opMoveAccMem(Byte);
|
case 0xa0: return opMoveAccMem(Byte);
|
||||||
|
@ -209,8 +214,8 @@ auto V30MZ::execOpcode() -> void {
|
||||||
case 0xab: return opStoreString(Word);
|
case 0xab: return opStoreString(Word);
|
||||||
case 0xac: return opLoadString(Byte);
|
case 0xac: return opLoadString(Byte);
|
||||||
case 0xad: return opLoadString(Word);
|
case 0xad: return opLoadString(Word);
|
||||||
case 0xae: return opSubtractCompareString(Byte);
|
case 0xae: return opScanString(Byte);
|
||||||
case 0xaf: return opSubtractCompareString(Word);
|
case 0xaf: return opScanString(Word);
|
||||||
case 0xb0: return opMoveRegImm(r.al);
|
case 0xb0: return opMoveRegImm(r.al);
|
||||||
case 0xb1: return opMoveRegImm(r.cl);
|
case 0xb1: return opMoveRegImm(r.cl);
|
||||||
case 0xb2: return opMoveRegImm(r.dl);
|
case 0xb2: return opMoveRegImm(r.dl);
|
||||||
|
@ -231,26 +236,26 @@ auto V30MZ::execOpcode() -> void {
|
||||||
case 0xc1: return opGroup2MemImm(Word);
|
case 0xc1: return opGroup2MemImm(Word);
|
||||||
case 0xc2: return opReturnImm();
|
case 0xc2: return opReturnImm();
|
||||||
case 0xc3: return opReturn();
|
case 0xc3: return opReturn();
|
||||||
//c4
|
case 0xc4: return opLoadSegmentMem(r.es);
|
||||||
//c5
|
case 0xc5: return opLoadSegmentMem(r.ds);
|
||||||
case 0xc6: return opMoveMemImm(Byte);
|
case 0xc6: return opMoveMemImm(Byte);
|
||||||
case 0xc7: return opMoveMemImm(Word);
|
case 0xc7: return opMoveMemImm(Word);
|
||||||
//c8
|
case 0xc8: return opEnter();
|
||||||
case 0xc9: return opLeave();
|
case 0xc9: return opLeave();
|
||||||
case 0xca: return opReturnFarImm();
|
case 0xca: return opReturnFarImm();
|
||||||
case 0xcb: return opReturnFar();
|
case 0xcb: return opReturnFar();
|
||||||
//cc
|
case 0xcc: return opInt3();
|
||||||
//cd
|
case 0xcd: return opIntImm();
|
||||||
case 0xce: return opInto();
|
case 0xce: return opInto();
|
||||||
case 0xcf: return opReturnInt();
|
case 0xcf: return opReturnInt();
|
||||||
case 0xd0: return opGroup2MemImm(Byte, 1);
|
case 0xd0: return opGroup2MemImm(Byte, 1);
|
||||||
case 0xd1: return opGroup2MemImm(Word, 1);
|
case 0xd1: return opGroup2MemImm(Word, 1);
|
||||||
case 0xd2: return opGroup2MemImm(Byte, r.cl);
|
case 0xd2: return opGroup2MemImm(Byte, r.cl);
|
||||||
case 0xd3: return opGroup2MemImm(Word, r.cl);
|
case 0xd3: return opGroup2MemImm(Word, r.cl);
|
||||||
//d4
|
case 0xd4: return opAdjustAfterMultiply();
|
||||||
//d5
|
case 0xd5: return opAdjustAfterDivide();
|
||||||
case 0xd6: return;
|
case 0xd6: return;
|
||||||
//d7
|
case 0xd7: return opTranslate();
|
||||||
case 0xd8: return; //fpo1
|
case 0xd8: return; //fpo1
|
||||||
case 0xd9: return; //fpo1
|
case 0xd9: return; //fpo1
|
||||||
case 0xda: return; //fpo1
|
case 0xda: return; //fpo1
|
||||||
|
@ -268,7 +273,7 @@ auto V30MZ::execOpcode() -> void {
|
||||||
case 0xe6: return opOut(Byte);
|
case 0xe6: return opOut(Byte);
|
||||||
case 0xe7: return opOut(Word);
|
case 0xe7: return opOut(Word);
|
||||||
case 0xe8: return opCallNear();
|
case 0xe8: return opCallNear();
|
||||||
//e9
|
case 0xe9: return opJumpNear();
|
||||||
case 0xea: return opJumpFar();
|
case 0xea: return opJumpFar();
|
||||||
case 0xeb: return opJumpShort();
|
case 0xeb: return opJumpShort();
|
||||||
case 0xec: return opInDX(Byte);
|
case 0xec: return opInDX(Byte);
|
||||||
|
@ -292,17 +297,30 @@ auto V30MZ::execOpcode() -> void {
|
||||||
case 0xfe: return opGroup4MemImm(Byte);
|
case 0xfe: return opGroup4MemImm(Byte);
|
||||||
case 0xff: return opGroup4MemImm(Word);
|
case 0xff: return opGroup4MemImm(Word);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
print("error: unknown opcode: ", hex(opcode, 2L), "\n");
|
auto V30MZ::interrupt(uint8 vector) -> void {
|
||||||
print("executed: ", --executed, "\n");
|
state.halt = false;
|
||||||
halt = true;
|
|
||||||
|
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 {
|
auto V30MZ::power() -> void {
|
||||||
halt = false;
|
state.halt = false;
|
||||||
executed = 0;
|
state.prefix = false;
|
||||||
|
|
||||||
prefix.hold = false;
|
|
||||||
prefix.segment = nothing;
|
prefix.segment = nothing;
|
||||||
prefix.repeat = nothing;
|
prefix.repeat = nothing;
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
namespace Processor {
|
namespace Processor {
|
||||||
|
|
||||||
struct V30MZ {
|
struct V30MZ {
|
||||||
using Size = const uint&;
|
using Size = uint;
|
||||||
enum : uint { Byte = 1, Word = 2, Long = 4 };
|
enum : uint { Byte = 1, Word = 2, Long = 4 };
|
||||||
|
struct ModRM;
|
||||||
|
|
||||||
virtual auto wait(uint clocks = 1) -> void = 0;
|
virtual auto wait(uint clocks = 1) -> void = 0;
|
||||||
virtual auto read(uint20 addr) -> uint8 = 0;
|
virtual auto read(uint20 addr) -> uint8 = 0;
|
||||||
|
@ -15,7 +16,8 @@ struct V30MZ {
|
||||||
virtual auto out(uint16 port, uint8 data) -> void = 0;
|
virtual auto out(uint16 port, uint8 data) -> void = 0;
|
||||||
|
|
||||||
auto exec() -> void;
|
auto exec() -> void;
|
||||||
auto execOpcode() -> void;
|
auto instruction() -> void;
|
||||||
|
auto interrupt(uint8 vector) -> void;
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
|
||||||
//registers.cpp
|
//registers.cpp
|
||||||
|
@ -25,15 +27,16 @@ struct V30MZ {
|
||||||
auto setAcc(Size, uint32) -> void;
|
auto setAcc(Size, uint32) -> void;
|
||||||
|
|
||||||
//modrm.cpp
|
//modrm.cpp
|
||||||
auto getReg(Size, uint8) -> uint16;
|
auto modRM() -> void;
|
||||||
auto setReg(Size, uint8, uint16) -> void;
|
|
||||||
|
|
||||||
auto getSeg(uint8) -> uint16;
|
auto getMem(Size, uint offset = 0) -> uint16;
|
||||||
auto setSeg(uint8, uint16) -> void;
|
auto setMem(Size, uint16) -> void;
|
||||||
|
|
||||||
auto getMemAddress(uint8) -> uint32;
|
auto getReg(Size) -> uint16;
|
||||||
auto getMem(Size, uint8) -> uint32;
|
auto setReg(Size, uint16) -> void;
|
||||||
auto setMem(Size, uint8, uint16) -> void;
|
|
||||||
|
auto getSeg() -> uint16;
|
||||||
|
auto setSeg(uint16) -> void;
|
||||||
|
|
||||||
//memory.cpp
|
//memory.cpp
|
||||||
auto read(Size, uint16, uint16) -> uint32;
|
auto read(Size, uint16, uint16) -> uint32;
|
||||||
|
@ -47,7 +50,7 @@ struct V30MZ {
|
||||||
auto push(uint16) -> void;
|
auto push(uint16) -> void;
|
||||||
|
|
||||||
//algorithms.cpp
|
//algorithms.cpp
|
||||||
auto parity(uint16) const -> bool;
|
auto parity(uint8) const -> bool;
|
||||||
auto alAdc(Size, uint16, uint16) -> uint16;
|
auto alAdc(Size, uint16, uint16) -> uint16;
|
||||||
auto alAdd(Size, uint16, uint16) -> uint16;
|
auto alAdd(Size, uint16, uint16) -> uint16;
|
||||||
auto alAnd(Size, uint16, uint16) -> uint16;
|
auto alAnd(Size, uint16, uint16) -> uint16;
|
||||||
|
@ -72,7 +75,13 @@ struct V30MZ {
|
||||||
auto alShr(Size, uint16, uint5 ) -> uint16;
|
auto alShr(Size, uint16, uint5 ) -> uint16;
|
||||||
auto alXor(Size, uint16, uint16) -> 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 opAddMemReg(Size);
|
||||||
auto opAddRegMem(Size);
|
auto opAddRegMem(Size);
|
||||||
auto opAddAccImm(Size);
|
auto opAddAccImm(Size);
|
||||||
|
@ -88,9 +97,6 @@ struct V30MZ {
|
||||||
auto opAndMemReg(Size);
|
auto opAndMemReg(Size);
|
||||||
auto opAndRegMem(Size);
|
auto opAndRegMem(Size);
|
||||||
auto opAndAccImm(Size);
|
auto opAndAccImm(Size);
|
||||||
auto opPrefix(uint16&);
|
|
||||||
auto opDecimalAdjust(bool);
|
|
||||||
auto opAsciiAdjust(bool);
|
|
||||||
auto opSubMemReg(Size);
|
auto opSubMemReg(Size);
|
||||||
auto opSubRegMem(Size);
|
auto opSubRegMem(Size);
|
||||||
auto opSubAccImm(Size);
|
auto opSubAccImm(Size);
|
||||||
|
@ -100,90 +106,116 @@ struct V30MZ {
|
||||||
auto opCmpMemReg(Size);
|
auto opCmpMemReg(Size);
|
||||||
auto opCmpRegMem(Size);
|
auto opCmpRegMem(Size);
|
||||||
auto opCmpAccImm(Size);
|
auto opCmpAccImm(Size);
|
||||||
|
auto opTestMemReg(Size);
|
||||||
|
auto opTestAcc(Size);
|
||||||
|
auto opMultiplySignedRegMemImm(Size);
|
||||||
auto opIncReg(uint16&);
|
auto opIncReg(uint16&);
|
||||||
auto opDecReg(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 opSignExtendByte();
|
||||||
auto opSignExtendWord();
|
auto opSignExtendWord();
|
||||||
auto opCallFar();
|
|
||||||
auto opMoveAccMem(Size);
|
//instructions-exec.cpp
|
||||||
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);
|
|
||||||
auto opLoop();
|
auto opLoop();
|
||||||
auto opIn(Size);
|
auto opLoopWhile(bool);
|
||||||
auto opOut(Size);
|
|
||||||
auto opCallNear();
|
|
||||||
auto opJumpFar();
|
|
||||||
auto opJumpShort();
|
auto opJumpShort();
|
||||||
auto opInDX(Size);
|
auto opJumpIf(bool);
|
||||||
auto opOutDX(Size);
|
auto opJumpNear();
|
||||||
auto opLock();
|
auto opJumpFar();
|
||||||
auto opRepeat(bool);
|
auto opCallNear();
|
||||||
auto opHalt();
|
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 opComplementCarry();
|
||||||
auto opClearFlag(bool&);
|
auto opClearFlag(bool&);
|
||||||
auto opSetFlag(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
|
//disassembler.cpp
|
||||||
auto disassemble(uint16 cs, uint16 ip, bool registers = true, bool bytes = true) -> string;
|
auto disassemble(uint16 cs, uint16 ip, bool registers = true, bool bytes = true) -> string;
|
||||||
|
|
||||||
//state
|
struct State {
|
||||||
bool halt = false;
|
bool halt;
|
||||||
uint executed = 0;
|
bool prefix;
|
||||||
|
} state;
|
||||||
|
|
||||||
struct Prefix {
|
struct Prefix {
|
||||||
bool hold;
|
|
||||||
maybe<uint16> segment;
|
maybe<uint16> segment;
|
||||||
maybe<bool> repeat;
|
maybe<bool> repeat;
|
||||||
} prefix;
|
} prefix;
|
||||||
|
|
||||||
struct Registers {
|
struct ModRM {
|
||||||
//registers.cpp
|
uint2 mod;
|
||||||
auto byte(uint3) -> uint8&;
|
uint3 reg;
|
||||||
auto word(uint3) -> uint16&;
|
uint3 mem;
|
||||||
auto segment(uint2) -> uint16&;
|
|
||||||
|
|
||||||
|
uint16 address;
|
||||||
|
uint16 segment;
|
||||||
|
} modrm;
|
||||||
|
|
||||||
|
struct Registers {
|
||||||
uint16 ip;
|
uint16 ip;
|
||||||
union { uint16 ax; struct { uint8 order_lsb2(al, ah); }; };
|
union { uint16 ax; struct { uint8 order_lsb2(al, ah); }; };
|
||||||
union { uint16 bx; struct { uint8 order_lsb2(bl, bh); }; };
|
union { uint16 bx; struct { uint8 order_lsb2(bl, bh); }; };
|
||||||
|
@ -198,6 +230,10 @@ struct V30MZ {
|
||||||
uint16 es;
|
uint16 es;
|
||||||
uint16 ss;
|
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 {
|
struct Flags {
|
||||||
//registers.cpp
|
//registers.cpp
|
||||||
operator uint16() const;
|
operator uint16() const;
|
||||||
|
|
|
@ -4,6 +4,8 @@ namespace WonderSwan {
|
||||||
|
|
||||||
CPU cpu;
|
CPU cpu;
|
||||||
#include "memory.cpp"
|
#include "memory.cpp"
|
||||||
|
#include "io.cpp"
|
||||||
|
#include "dma.cpp"
|
||||||
|
|
||||||
auto CPU::Enter() -> void {
|
auto CPU::Enter() -> void {
|
||||||
cpu.main();
|
cpu.main();
|
||||||
|
@ -53,6 +55,17 @@ auto CPU::power() -> void {
|
||||||
create(CPU::Enter, 3072000);
|
create(CPU::Enter, 3072000);
|
||||||
|
|
||||||
iomap[0x00a0] = this;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,27 @@ struct CPU : Processor::V30MZ, Thread, IO {
|
||||||
auto ramRead(uint16 addr) -> uint8;
|
auto ramRead(uint16 addr) -> uint8;
|
||||||
auto ramWrite(uint16 addr, uint8 data) -> void;
|
auto ramWrite(uint16 addr, uint8 data) -> void;
|
||||||
|
|
||||||
|
//io.cpp
|
||||||
auto portRead(uint16 addr) -> uint8 override;
|
auto portRead(uint16 addr) -> uint8 override;
|
||||||
auto portWrite(uint16 addr, uint8 data) -> void 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;
|
extern CPU cpu;
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,22 +7,3 @@ auto CPU::ramWrite(uint16 addr, uint8 data) -> void {
|
||||||
if(WS() && addr >= 0x4000) return;
|
if(WS() && addr >= 0x4000) return;
|
||||||
iram[addr] = data;
|
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -12,12 +12,12 @@ auto IO::power() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto IO::portRead(uint16 addr) -> uint8 {
|
auto IO::portRead(uint16 addr) -> uint8 {
|
||||||
//print("[", hex(addr, 4L), "]: port unmapped\n");
|
print("[", hex(addr, 4L), "]: port unmapped\n");
|
||||||
return 0x00;
|
return 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto IO::portWrite(uint16 addr, uint8 data) -> void {
|
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 {
|
auto Bus::read(uint20 addr) -> uint8 {
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
namespace WonderSwan {
|
namespace WonderSwan {
|
||||||
|
|
||||||
PPU ppu;
|
PPU ppu;
|
||||||
|
#include "io.cpp"
|
||||||
#include "video.cpp"
|
#include "video.cpp"
|
||||||
|
|
||||||
auto PPU::Enter() -> void {
|
auto PPU::Enter() -> void {
|
||||||
|
@ -35,6 +36,12 @@ auto PPU::step(uint clocks) -> void {
|
||||||
auto PPU::power() -> void {
|
auto PPU::power() -> void {
|
||||||
create(PPU::Enter, 3072000);
|
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;
|
for(auto& n : output) n = 0;
|
||||||
|
|
||||||
status.vclk = 0;
|
status.vclk = 0;
|
||||||
|
|
|
@ -1,18 +1,80 @@
|
||||||
#include "video.hpp"
|
#include "video.hpp"
|
||||||
|
|
||||||
struct PPU : Thread {
|
struct PPU : Thread, IO {
|
||||||
static auto Enter() -> void;
|
static auto Enter() -> void;
|
||||||
|
|
||||||
auto main() -> void;
|
auto main() -> void;
|
||||||
auto step(uint clocks) -> void;
|
auto step(uint clocks) -> void;
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
|
||||||
|
auto portRead(uint16 addr) -> uint8 override;
|
||||||
|
auto portWrite(uint16 addr, uint8 data) -> void override;
|
||||||
|
|
||||||
uint16 output[224 * 144] = {0};
|
uint16 output[224 * 144] = {0};
|
||||||
|
|
||||||
struct Status {
|
struct Status {
|
||||||
uint vclk;
|
uint vclk;
|
||||||
uint hclk;
|
uint hclk;
|
||||||
} status;
|
} 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;
|
extern PPU ppu;
|
||||||
|
|
|
@ -86,7 +86,7 @@ using int4 = nall::Integer< 4>;
|
||||||
using int5 = nall::Integer< 5>;
|
using int5 = nall::Integer< 5>;
|
||||||
using int6 = nall::Integer< 6>;
|
using int6 = nall::Integer< 6>;
|
||||||
using int7 = nall::Integer< 7>;
|
using int7 = nall::Integer< 7>;
|
||||||
//using int8 = nall::Integer< 8>;
|
using int8_= nall::Integer< 8>;
|
||||||
using int9 = nall::Integer< 9>;
|
using int9 = nall::Integer< 9>;
|
||||||
using int10 = nall::Integer<10>;
|
using int10 = nall::Integer<10>;
|
||||||
using int11 = nall::Integer<11>;
|
using int11 = nall::Integer<11>;
|
||||||
|
@ -94,7 +94,7 @@ using int12 = nall::Integer<12>;
|
||||||
using int13 = nall::Integer<13>;
|
using int13 = nall::Integer<13>;
|
||||||
using int14 = nall::Integer<14>;
|
using int14 = nall::Integer<14>;
|
||||||
using int15 = nall::Integer<15>;
|
using int15 = nall::Integer<15>;
|
||||||
//using int16 = nall::Integer<16>;
|
using int16_= nall::Integer<16>;
|
||||||
using int17 = nall::Integer<17>;
|
using int17 = nall::Integer<17>;
|
||||||
using int18 = nall::Integer<18>;
|
using int18 = nall::Integer<18>;
|
||||||
using int19 = nall::Integer<19>;
|
using int19 = nall::Integer<19>;
|
||||||
|
@ -110,7 +110,7 @@ using int28 = nall::Integer<28>;
|
||||||
using int29 = nall::Integer<29>;
|
using int29 = nall::Integer<29>;
|
||||||
using int30 = nall::Integer<30>;
|
using int30 = nall::Integer<30>;
|
||||||
using int31 = nall::Integer<31>;
|
using int31 = nall::Integer<31>;
|
||||||
//using int32 = nall::Integer<32>;
|
using int32_= nall::Integer<32>;
|
||||||
using int33 = nall::Integer<33>;
|
using int33 = nall::Integer<33>;
|
||||||
using int34 = nall::Integer<34>;
|
using int34 = nall::Integer<34>;
|
||||||
using int35 = nall::Integer<35>;
|
using int35 = nall::Integer<35>;
|
||||||
|
@ -142,7 +142,7 @@ using int60 = nall::Integer<60>;
|
||||||
using int61 = nall::Integer<61>;
|
using int61 = nall::Integer<61>;
|
||||||
using int62 = nall::Integer<62>;
|
using int62 = nall::Integer<62>;
|
||||||
using int63 = nall::Integer<63>;
|
using int63 = nall::Integer<63>;
|
||||||
//using int64 = nall::Integer<64>;
|
using int64_= nall::Integer<64>;
|
||||||
|
|
||||||
using uint1 = nall::Natural< 1>;
|
using uint1 = nall::Natural< 1>;
|
||||||
using uint2 = nall::Natural< 2>;
|
using uint2 = nall::Natural< 2>;
|
||||||
|
@ -151,7 +151,7 @@ using uint4 = nall::Natural< 4>;
|
||||||
using uint5 = nall::Natural< 5>;
|
using uint5 = nall::Natural< 5>;
|
||||||
using uint6 = nall::Natural< 6>;
|
using uint6 = nall::Natural< 6>;
|
||||||
using uint7 = nall::Natural< 7>;
|
using uint7 = nall::Natural< 7>;
|
||||||
//using uint8 = nall::Natural< 8>;
|
using uint8_= nall::Natural< 8>;
|
||||||
using uint9 = nall::Natural< 9>;
|
using uint9 = nall::Natural< 9>;
|
||||||
using uint10 = nall::Natural<10>;
|
using uint10 = nall::Natural<10>;
|
||||||
using uint11 = nall::Natural<11>;
|
using uint11 = nall::Natural<11>;
|
||||||
|
@ -159,7 +159,7 @@ using uint12 = nall::Natural<12>;
|
||||||
using uint13 = nall::Natural<13>;
|
using uint13 = nall::Natural<13>;
|
||||||
using uint14 = nall::Natural<14>;
|
using uint14 = nall::Natural<14>;
|
||||||
using uint15 = nall::Natural<15>;
|
using uint15 = nall::Natural<15>;
|
||||||
//using uint16 = nall::Natural<16>;
|
using uint16_= nall::Natural<16>;
|
||||||
using uint17 = nall::Natural<17>;
|
using uint17 = nall::Natural<17>;
|
||||||
using uint18 = nall::Natural<18>;
|
using uint18 = nall::Natural<18>;
|
||||||
using uint19 = nall::Natural<19>;
|
using uint19 = nall::Natural<19>;
|
||||||
|
@ -175,7 +175,7 @@ using uint28 = nall::Natural<28>;
|
||||||
using uint29 = nall::Natural<29>;
|
using uint29 = nall::Natural<29>;
|
||||||
using uint30 = nall::Natural<30>;
|
using uint30 = nall::Natural<30>;
|
||||||
using uint31 = nall::Natural<31>;
|
using uint31 = nall::Natural<31>;
|
||||||
//using uint32 = nall::Natural<32>;
|
using uint32_= nall::Natural<32>;
|
||||||
using uint33 = nall::Natural<33>;
|
using uint33 = nall::Natural<33>;
|
||||||
using uint34 = nall::Natural<34>;
|
using uint34 = nall::Natural<34>;
|
||||||
using uint35 = nall::Natural<35>;
|
using uint35 = nall::Natural<35>;
|
||||||
|
@ -207,4 +207,4 @@ using uint60 = nall::Natural<60>;
|
||||||
using uint61 = nall::Natural<61>;
|
using uint61 = nall::Natural<61>;
|
||||||
using uint62 = nall::Natural<62>;
|
using uint62 = nall::Natural<62>;
|
||||||
using uint63 = nall::Natural<63>;
|
using uint63 = nall::Natural<63>;
|
||||||
//using uint64 = nall::Natural<64>;
|
using uint64_= nall::Natural<64>;
|
||||||
|
|
Loading…
Reference in New Issue