Fixed MOVSX,MOVZX, and passed initial paging test
This commit is contained in:
parent
df838b8f86
commit
f3646d206f
10 changed files with 403 additions and 128 deletions
|
|
@ -78,6 +78,7 @@
|
||||||
"debugger": {
|
"debugger": {
|
||||||
"id": "pc386.debugger",
|
"id": "pc386.debugger",
|
||||||
"name": "",
|
"name": "",
|
||||||
|
"commands": "",
|
||||||
"messages": ""
|
"messages": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -744,9 +744,9 @@ if (DEBUGGER) {
|
||||||
/* 0x89 */ [Debugger.INS.MOV, Debugger.TYPE_MODRM | Debugger.TYPE_WORDV | Debugger.TYPE_OUT, Debugger.TYPE_REG | Debugger.TYPE_WORDV | Debugger.TYPE_IN],
|
/* 0x89 */ [Debugger.INS.MOV, Debugger.TYPE_MODRM | Debugger.TYPE_WORDV | Debugger.TYPE_OUT, Debugger.TYPE_REG | Debugger.TYPE_WORDV | Debugger.TYPE_IN],
|
||||||
/* 0x8A */ [Debugger.INS.MOV, Debugger.TYPE_REG | Debugger.TYPE_BYTE | Debugger.TYPE_OUT, Debugger.TYPE_MODRM | Debugger.TYPE_BYTE | Debugger.TYPE_IN],
|
/* 0x8A */ [Debugger.INS.MOV, Debugger.TYPE_REG | Debugger.TYPE_BYTE | Debugger.TYPE_OUT, Debugger.TYPE_MODRM | Debugger.TYPE_BYTE | Debugger.TYPE_IN],
|
||||||
/* 0x8B */ [Debugger.INS.MOV, Debugger.TYPE_REG | Debugger.TYPE_WORDV | Debugger.TYPE_OUT, Debugger.TYPE_MODRM | Debugger.TYPE_WORDV | Debugger.TYPE_IN],
|
/* 0x8B */ [Debugger.INS.MOV, Debugger.TYPE_REG | Debugger.TYPE_WORDV | Debugger.TYPE_OUT, Debugger.TYPE_MODRM | Debugger.TYPE_WORDV | Debugger.TYPE_IN],
|
||||||
/* 0x8C */ [Debugger.INS.MOV, Debugger.TYPE_MODRM | Debugger.TYPE_WORD | Debugger.TYPE_OUT, Debugger.TYPE_SEGREG | Debugger.TYPE_WORD | Debugger.TYPE_IN],
|
/* 0x8C */ [Debugger.INS.MOV, Debugger.TYPE_MODRM | Debugger.TYPE_WORDV | Debugger.TYPE_OUT, Debugger.TYPE_SEGREG | Debugger.TYPE_WORD | Debugger.TYPE_IN],
|
||||||
/* 0x8D */ [Debugger.INS.LEA, Debugger.TYPE_REG | Debugger.TYPE_WORDV | Debugger.TYPE_OUT, Debugger.TYPE_MEM | Debugger.TYPE_WORDV],
|
/* 0x8D */ [Debugger.INS.LEA, Debugger.TYPE_REG | Debugger.TYPE_WORDV | Debugger.TYPE_OUT, Debugger.TYPE_MEM | Debugger.TYPE_WORDV],
|
||||||
/* 0x8E */ [Debugger.INS.MOV, Debugger.TYPE_SEGREG | Debugger.TYPE_WORD | Debugger.TYPE_OUT, Debugger.TYPE_MODRM | Debugger.TYPE_WORD | Debugger.TYPE_IN],
|
/* 0x8E */ [Debugger.INS.MOV, Debugger.TYPE_SEGREG | Debugger.TYPE_WORD | Debugger.TYPE_OUT, Debugger.TYPE_MODRM | Debugger.TYPE_WORDV | Debugger.TYPE_IN],
|
||||||
/* 0x8F */ [Debugger.INS.POP, Debugger.TYPE_MODRM | Debugger.TYPE_WORDV | Debugger.TYPE_OUT],
|
/* 0x8F */ [Debugger.INS.POP, Debugger.TYPE_MODRM | Debugger.TYPE_WORDV | Debugger.TYPE_OUT],
|
||||||
|
|
||||||
/* 0x90 */ [Debugger.INS.NOP],
|
/* 0x90 */ [Debugger.INS.NOP],
|
||||||
|
|
@ -883,8 +883,8 @@ if (DEBUGGER) {
|
||||||
0x03: [Debugger.INS.LSL, Debugger.TYPE_REG | Debugger.TYPE_WORD | Debugger.TYPE_OUT | Debugger.TYPE_80286, Debugger.TYPE_MEM | Debugger.TYPE_WORD | Debugger.TYPE_IN],
|
0x03: [Debugger.INS.LSL, Debugger.TYPE_REG | Debugger.TYPE_WORD | Debugger.TYPE_OUT | Debugger.TYPE_80286, Debugger.TYPE_MEM | Debugger.TYPE_WORD | Debugger.TYPE_IN],
|
||||||
0x05: [Debugger.INS.LOADALL,Debugger.TYPE_80286],
|
0x05: [Debugger.INS.LOADALL,Debugger.TYPE_80286],
|
||||||
0x06: [Debugger.INS.CLTS, Debugger.TYPE_80286],
|
0x06: [Debugger.INS.CLTS, Debugger.TYPE_80286],
|
||||||
0x20: [Debugger.INS.MOV, Debugger.TYPE_REG | Debugger.TYPE_DWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_CTLREG | Debugger.TYPE_DWORD | Debugger.TYPE_IN],
|
0x20: [Debugger.INS.MOV, Debugger.TYPE_MODRM | Debugger.TYPE_DWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_CTLREG | Debugger.TYPE_DWORD | Debugger.TYPE_IN],
|
||||||
0x22: [Debugger.INS.MOV, Debugger.TYPE_CTLREG | Debugger.TYPE_DWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_REG | Debugger.TYPE_DWORD | Debugger.TYPE_IN],
|
0x22: [Debugger.INS.MOV, Debugger.TYPE_CTLREG | Debugger.TYPE_DWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_MODRM | Debugger.TYPE_DWORD | Debugger.TYPE_IN],
|
||||||
0x80: [Debugger.INS.JO, Debugger.TYPE_IMMREL | Debugger.TYPE_WORDV | Debugger.TYPE_IN | Debugger.TYPE_80386],
|
0x80: [Debugger.INS.JO, Debugger.TYPE_IMMREL | Debugger.TYPE_WORDV | Debugger.TYPE_IN | Debugger.TYPE_80386],
|
||||||
0x81: [Debugger.INS.JNO, Debugger.TYPE_IMMREL | Debugger.TYPE_WORDV | Debugger.TYPE_IN | Debugger.TYPE_80386],
|
0x81: [Debugger.INS.JNO, Debugger.TYPE_IMMREL | Debugger.TYPE_WORDV | Debugger.TYPE_IN | Debugger.TYPE_80386],
|
||||||
0x82: [Debugger.INS.JC, Debugger.TYPE_IMMREL | Debugger.TYPE_WORDV | Debugger.TYPE_IN | Debugger.TYPE_80386],
|
0x82: [Debugger.INS.JC, Debugger.TYPE_IMMREL | Debugger.TYPE_WORDV | Debugger.TYPE_IN | Debugger.TYPE_80386],
|
||||||
|
|
@ -910,7 +910,9 @@ if (DEBUGGER) {
|
||||||
0xAC: [Debugger.INS.SHRD, Debugger.TYPE_MODRM | Debugger.TYPE_WORDV | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_REG | Debugger.TYPE_WORDV | Debugger.TYPE_IN, Debugger.TYPE_IMM | Debugger.TYPE_BYTE | Debugger.TYPE_IN],
|
0xAC: [Debugger.INS.SHRD, Debugger.TYPE_MODRM | Debugger.TYPE_WORDV | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_REG | Debugger.TYPE_WORDV | Debugger.TYPE_IN, Debugger.TYPE_IMM | Debugger.TYPE_BYTE | Debugger.TYPE_IN],
|
||||||
0xAD: [Debugger.INS.SHRD, Debugger.TYPE_MODRM | Debugger.TYPE_WORDV | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_REG | Debugger.TYPE_WORDV | Debugger.TYPE_IN, Debugger.TYPE_IMPREG | Debugger.TYPE_CL | Debugger.TYPE_IN],
|
0xAD: [Debugger.INS.SHRD, Debugger.TYPE_MODRM | Debugger.TYPE_WORDV | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_REG | Debugger.TYPE_WORDV | Debugger.TYPE_IN, Debugger.TYPE_IMPREG | Debugger.TYPE_CL | Debugger.TYPE_IN],
|
||||||
0xB6: [Debugger.INS.MOVZX, Debugger.TYPE_REG | Debugger.TYPE_WORDV | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_MODRM | Debugger.TYPE_BYTE | Debugger.TYPE_IN],
|
0xB6: [Debugger.INS.MOVZX, Debugger.TYPE_REG | Debugger.TYPE_WORDV | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_MODRM | Debugger.TYPE_BYTE | Debugger.TYPE_IN],
|
||||||
0xB7: [Debugger.INS.MOVZX, Debugger.TYPE_REG | Debugger.TYPE_DWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_MODRM | Debugger.TYPE_WORD | Debugger.TYPE_IN]
|
0xB7: [Debugger.INS.MOVZX, Debugger.TYPE_REG | Debugger.TYPE_DWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_MODRM | Debugger.TYPE_WORD | Debugger.TYPE_IN],
|
||||||
|
0xBE: [Debugger.INS.MOVSX, Debugger.TYPE_REG | Debugger.TYPE_WORDV | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_MODRM | Debugger.TYPE_BYTE | Debugger.TYPE_IN],
|
||||||
|
0xBF: [Debugger.INS.MOVSX, Debugger.TYPE_REG | Debugger.TYPE_DWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_MODRM | Debugger.TYPE_WORD | Debugger.TYPE_IN]
|
||||||
};
|
};
|
||||||
|
|
||||||
Debugger.aaGrpDescs = [
|
Debugger.aaGrpDescs = [
|
||||||
|
|
@ -1243,12 +1245,6 @@ if (DEBUGGER) {
|
||||||
this.messageDump(Messages.DOS, function onDumpDOS(s) { dbg.dumpDOS(s); });
|
this.messageDump(Messages.DOS, function onDumpDOS(s) { dbg.dumpDOS(s); });
|
||||||
|
|
||||||
this.setReady();
|
this.setReady();
|
||||||
|
|
||||||
if (this.sInitCommands) {
|
|
||||||
var a = this.parseCommand(this.sInitCommands);
|
|
||||||
delete this.sInitCommands;
|
|
||||||
for (var s in a) this.doCommand(a[s]);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1514,7 +1510,7 @@ if (DEBUGGER) {
|
||||||
this.println("id physaddr blkaddr used size type");
|
this.println("id physaddr blkaddr used size type");
|
||||||
this.println("-------- --------- -------- ------ ------ ----");
|
this.println("-------- --------- -------- ------ ------ ----");
|
||||||
for (var i = 0; i < this.cpu.aMemBlocks.length; i++) {
|
for (var i = 0; i < this.cpu.aMemBlocks.length; i++) {
|
||||||
var block = this.cpu.aMemBlocks[i];
|
var block = this.cpu.aBusBlocks[i];
|
||||||
if (block.type === Memory.TYPE.NONE) continue;
|
if (block.type === Memory.TYPE.NONE) continue;
|
||||||
this.println(str.toHex(block.id) + " %" + str.toHex(i << this.cpu.blockShift) + ": " + str.toHex(block.addr) + " " + str.toHexWord(block.used) + " " + str.toHexWord(block.size) + " " + Memory.TYPE.NAMES[block.type]);
|
this.println(str.toHex(block.id) + " %" + str.toHex(i << this.cpu.blockShift) + ": " + str.toHex(block.addr) + " " + str.toHexWord(block.used) + " " + str.toHexWord(block.size) + " " + Memory.TYPE.NAMES[block.type]);
|
||||||
}
|
}
|
||||||
|
|
@ -2046,6 +2042,11 @@ if (DEBUGGER) {
|
||||||
{
|
{
|
||||||
this.println("Type ? for list of debugger commands");
|
this.println("Type ? for list of debugger commands");
|
||||||
this.updateStatus();
|
this.updateStatus();
|
||||||
|
if (this.sInitCommands) {
|
||||||
|
var a = this.parseCommand(this.sInitCommands);
|
||||||
|
delete this.sInitCommands;
|
||||||
|
for (var s in a) this.doCommand(a[s]);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -2225,7 +2226,9 @@ if (DEBUGGER) {
|
||||||
* we always reset and then perform a (potentially limited) restore.
|
* we always reset and then perform a (potentially limited) restore.
|
||||||
*/
|
*/
|
||||||
this.reset(true);
|
this.reset(true);
|
||||||
this.println(data? "resuming" : "powering up");
|
|
||||||
|
// this.println(data? "resuming" : "powering up");
|
||||||
|
|
||||||
if (data && this.restore) {
|
if (data && this.restore) {
|
||||||
if (!this.restore(data)) return false;
|
if (!this.restore(data)) return false;
|
||||||
}
|
}
|
||||||
|
|
@ -5358,7 +5361,7 @@ if (DEBUGGER) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
this.println("debugger sad: " + e.message);
|
this.println("debugger error: " + (e.stack || e.message));
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
|
||||||
|
|
@ -793,7 +793,7 @@ X86CPU.prototype.mapPageBlock = function(addr, fWrite)
|
||||||
* Now we can create a new PAGED Memory block and record the physical block info using setPhysBlock().
|
* Now we can create a new PAGED Memory block and record the physical block info using setPhysBlock().
|
||||||
*/
|
*/
|
||||||
var addrPage = addr & ~X86.LADDR.OFFSET;
|
var addrPage = addr & ~X86.LADDR.OFFSET;
|
||||||
var blockPage = new Memory(addrPage, 0, this.blockSize, Memory.TYPE.PAGED);
|
var blockPage = new Memory(addrPage, 0, 0, Memory.TYPE.PAGED);
|
||||||
blockPage.setPhysBlock(blockPhys, blockPDE, offPDE, blockPTE, offPTE);
|
blockPage.setPhysBlock(blockPhys, blockPDE, offPDE, blockPTE, offPTE);
|
||||||
|
|
||||||
var iBlock = addr >>> this.blockShift;
|
var iBlock = addr >>> this.blockShift;
|
||||||
|
|
|
||||||
|
|
@ -313,11 +313,9 @@ X86.opMOVcr = function MOVcr()
|
||||||
break;
|
break;
|
||||||
case 0x2:
|
case 0x2:
|
||||||
temp = this.regEDX;
|
temp = this.regEDX;
|
||||||
if (DEBUG) this.stopCPU();
|
|
||||||
break;
|
break;
|
||||||
case 0x3:
|
case 0x3:
|
||||||
temp = this.regEBX;
|
temp = this.regEBX;
|
||||||
if (DEBUG) this.stopCPU();
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
X86.opInvalid.call(this);
|
X86.opInvalid.call(this);
|
||||||
|
|
@ -1128,6 +1126,7 @@ X86.opMOVZXb = function MOVZXb()
|
||||||
X86.opMOVZXw = function MOVZXw()
|
X86.opMOVZXw = function MOVZXw()
|
||||||
{
|
{
|
||||||
var bModRM = this.getIPByte();
|
var bModRM = this.getIPByte();
|
||||||
|
this.setDataSize(2);
|
||||||
this.aOpModRegWord[bModRM].call(this, X86.fnMOVX);
|
this.aOpModRegWord[bModRM].call(this, X86.fnMOVX);
|
||||||
switch((bModRM & 0x38) >> 3) {
|
switch((bModRM & 0x38) >> 3) {
|
||||||
case 0x0:
|
case 0x0:
|
||||||
|
|
@ -1287,6 +1286,7 @@ X86.opMOVSXb = function MOVSXb()
|
||||||
X86.opMOVSXw = function MOVSXw()
|
X86.opMOVSXw = function MOVSXw()
|
||||||
{
|
{
|
||||||
var bModRM = this.getIPByte();
|
var bModRM = this.getIPByte();
|
||||||
|
this.setDataSize(2);
|
||||||
this.aOpModRegWord[bModRM].call(this, X86.fnMOVX);
|
this.aOpModRegWord[bModRM].call(this, X86.fnMOVX);
|
||||||
switch((bModRM & 0x38) >> 3) {
|
switch((bModRM & 0x38) >> 3) {
|
||||||
case 0x0:
|
case 0x0:
|
||||||
|
|
|
||||||
|
|
@ -887,22 +887,15 @@ X86Seg.prototype.updateMode = function(fLoad, fProt)
|
||||||
if (fProt === undefined) {
|
if (fProt === undefined) {
|
||||||
fProt = !!(this.cpu.regCR0 & X86.CR0.MSW.PE);
|
fProt = !!(this.cpu.regCR0 & X86.CR0.MSW.PE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following properties are used for STACK segments only (ie, segSS); we want to make it easier
|
* The following properties are used for STACK segments only (ie, segSS); we want to make it easier
|
||||||
* for setSS() to set stack lower and upper limits, which requires knowing whether or not the segment is
|
* for setSS() to set stack lower and upper limits, which requires knowing whether or not the segment is
|
||||||
* marked as EXPDOWN.
|
* marked as EXPDOWN.
|
||||||
*/
|
*/
|
||||||
this.fExpDown = false;
|
this.fExpDown = false;
|
||||||
|
|
||||||
if (fProt) {
|
if (fProt) {
|
||||||
/*
|
|
||||||
* If we've just transitioned from real-mode, then CPL (which is meaningful for segCS only)
|
|
||||||
* should be left alone (ie, should remain at zero). On the first protected-mode CS selector
|
|
||||||
* load (normally an intersegment JMP immediately following the protected-mode switch), CPL
|
|
||||||
* (along with the rest of the segment settings) will be properly set.
|
|
||||||
*/
|
|
||||||
if (this.load !== this.loadReal) {
|
|
||||||
this.cpl = this.sel & X86.SEL.RPL;
|
|
||||||
}
|
|
||||||
this.load = this.loadProt;
|
this.load = this.loadProt;
|
||||||
this.loadIDT = this.loadIDTProt;
|
this.loadIDT = this.loadIDTProt;
|
||||||
this.checkRead = this.checkReadProt;
|
this.checkRead = this.checkReadProt;
|
||||||
|
|
@ -929,13 +922,13 @@ X86Seg.prototype.updateMode = function(fLoad, fProt)
|
||||||
this.fExpDown = true;
|
this.fExpDown = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.dpl = (this.acc & X86.DESC.ACC.DPL.MASK) >> X86.DESC.ACC.DPL.SHIFT;
|
|
||||||
if (fLoad) {
|
if (fLoad) {
|
||||||
/*
|
/*
|
||||||
* Any update to the OPERAND and ADDRESS sizes should happen only on segment loads, not simply when
|
* Any update to the following properties must occur only on segment loads, not simply when
|
||||||
* we're updating the segment register as part of a mode change. Note that there is no counterpart to
|
* we're updating segment registers as part of a mode change.
|
||||||
* this for real-mode, because real-mode segment loads never change these attributes.
|
|
||||||
*/
|
*/
|
||||||
|
this.cpl = this.sel & X86.SEL.RPL;
|
||||||
|
this.dpl = (this.acc & X86.DESC.ACC.DPL.MASK) >> X86.DESC.ACC.DPL.SHIFT;
|
||||||
if (this.cpu.model < X86.MODEL_80386 || !(this.ext & X86.DESC.EXT.BIG)) {
|
if (this.cpu.model < X86.MODEL_80386 || !(this.ext & X86.DESC.EXT.BIG)) {
|
||||||
this.dataSize = 2;
|
this.dataSize = 2;
|
||||||
this.dataMask = 0xffff;
|
this.dataMask = 0xffff;
|
||||||
|
|
@ -957,19 +950,15 @@ X86Seg.prototype.updateMode = function(fLoad, fProt)
|
||||||
*
|
*
|
||||||
* See http://www.os2museum.com/wp/himem-sys-unreal-mode-and-loadall/ for more details.
|
* See http://www.os2museum.com/wp/himem-sys-unreal-mode-and-loadall/ for more details.
|
||||||
*
|
*
|
||||||
* Ditto for other attributes such as acc, type, ext, and the OPERAND and ADDRESS sizes, which are derived
|
* Ditto for other attributes such as acc, type, and ext (and the OPERAND and ADDRESS sizes, which
|
||||||
* from the ext property. Even an explicit segment load in real-mode does not alter these properties.
|
* are derived from the ext property). Even an explicit segment load in real-mode does not alter those
|
||||||
*
|
* properties.
|
||||||
* this.limit = 0xffff;
|
|
||||||
* this.acc = this.type = this.ext = 0;
|
|
||||||
* this.dataSize = this.addrSize = 2;
|
|
||||||
* this.dataMask = this.addrMask = 0xffff;
|
|
||||||
*
|
*
|
||||||
* TODO: The checkReadReal() and checkWriteReal() functions need to generate GP faults for offsets
|
* TODO: The checkReadReal() and checkWriteReal() functions need to generate GP faults for offsets
|
||||||
* beyond the current real-mode limit.
|
* beyond the current real-mode limit.
|
||||||
*/
|
*/
|
||||||
this.addrDesc = X86.ADDR_INVALID;
|
|
||||||
this.cpl = this.dpl = 0;
|
this.cpl = this.dpl = 0;
|
||||||
|
this.addrDesc = X86.ADDR_INVALID;
|
||||||
}
|
}
|
||||||
return fProt;
|
return fProt;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
all: tests.json
|
all: tests.json
|
||||||
|
|
||||||
tests.com: tests.nasm
|
tests.com: tests.nasm ../inc/dos.inc ../inc/misc.inc ../inc/x86.inc
|
||||||
nasm -f bin tests.nasm -l tests.lst -o tests.com
|
nasm -i../inc/ -f bin tests.nasm -l tests.lst -o tests.com
|
||||||
|
|
||||||
tests.json: tests.com
|
tests.json: tests.com
|
||||||
node ../../../modules/filedump/bin/filedump --file=tests.com --output=tests.json --overwrite
|
node ../../../modules/filedump/bin/filedump --file=tests.com --output=tests.json --overwrite
|
||||||
|
|
|
||||||
|
|
@ -4,48 +4,41 @@
|
||||||
;
|
;
|
||||||
; When used as a ROM, it should be installed at physical address 983296 (0xf0100) and aliased at
|
; When used as a ROM, it should be installed at physical address 983296 (0xf0100) and aliased at
|
||||||
; physical address 4294902016 (0xffff0100). The jump at jmpStart should align with the CPU reset
|
; physical address 4294902016 (0xffff0100). The jump at jmpStart should align with the CPU reset
|
||||||
; address (%0xfffffff0), which will transfer control to 0xf000:0x0100.
|
; address (%0xfffffff0), which will transfer control to 0xf000:0x0100. From that point on,
|
||||||
|
; all memory accesses should remain within the first 1Mb.
|
||||||
;
|
;
|
||||||
; The code which attempts to update myGDT and addrGDT will have no effect when installed as a ROM,
|
; The code which attempts to update myGDT and addrGDT will have no effect when installed as a ROM,
|
||||||
; which is fine, because those data structures are predefined with appropriate ROM-based addresses.
|
; which is fine, because those data structures are predefined with appropriate ROM-based addresses.
|
||||||
;
|
;
|
||||||
; See the machine definition file in /modules/pcjs/bin/romtests.json for a sample ROM configuration.
|
; See the machine definition file in /modules/pcjs/bin/romtests.json for a configuration that can
|
||||||
|
; load this file as a ROM image.
|
||||||
;
|
;
|
||||||
; PMODE_32BIT Notes
|
; PROT32 Notes
|
||||||
; -----------------
|
; -----------------
|
||||||
; PMODE_32BIT is NOT enabled by default, because based on what I've seen in VirtualBox (and notes
|
; PROT32 is NOT enabled by default, because based on what I've seen in VirtualBox (and notes
|
||||||
; at http://geezer.osdevbrasil.net/johnfine/segments.htm), if CS is loaded with a 32-bit code segment
|
; at http://geezer.osdevbrasil.net/johnfine/segments.htm), if CS is loaded with a 32-bit code segment
|
||||||
; while in protected-mode and we then return to real-mode, even if we immediately perform a FAR JMP
|
; while in protected-mode and we then return to real-mode, even if we immediately perform a FAR jump
|
||||||
; with a real-mode CS, the base and limit of CS will be updated, but other CS attributes, like EXT_BIG,
|
; with a real-mode CS, the base of CS will be updated, but all the other segment attributes, like
|
||||||
; will NOT be updated. As a result, the processor will crash as soon as it starts executing 16-bit
|
; EXT_BIG, remain unchanged. As a result, the processor will crash as soon as it starts executing
|
||||||
; real-mode code, because it's being misinterpreted as 32-bit code, and there doesn't appear to be
|
; 16-bit real-mode code, because it's being misinterpreted as 32-bit code, and there doesn't appear
|
||||||
; anything you can do about it from real-mode.
|
; to be anything you can do about it from real-mode.
|
||||||
;
|
;
|
||||||
; The work-around: switch to a 16-bit code segment BEFORE returning to real-mode.
|
; The work-around: load CS with a 16-bit code segment BEFORE returning to real-mode.
|
||||||
;
|
;
|
||||||
; "Unreal mode" works by setting other segment registers (eg, DS, ES) to 32-bit segments, not CS.
|
; "Unreal mode" works by setting other segment registers (eg, DS, ES) to 32-bit segments, not CS.
|
||||||
; SS should not be set to a 32-bit segment either, because that causes implicit pushes to use ESP
|
; SS should not be set to a 32-bit segment either, because that causes implicit pushes to use ESP
|
||||||
; instead of SP, even in real-mode.
|
; instead of SP, even in real-mode.
|
||||||
;
|
|
||||||
; TODO: Verify that a 80386 cannot successfully return to real-mode when CS contains a 32-bit code segment.
|
|
||||||
;
|
;
|
||||||
cpu 386
|
cpu 386
|
||||||
org 0x100
|
org 0x100
|
||||||
section .text
|
section .text
|
||||||
|
|
||||||
|
%include "dos.inc"
|
||||||
|
%include "misc.inc"
|
||||||
|
%include "x86.inc"
|
||||||
|
|
||||||
bits 16
|
bits 16
|
||||||
|
|
||||||
ACC_TYPE_SEG equ 0x1000
|
|
||||||
ACC_PRESENT equ 0x8000
|
|
||||||
ACC_TYPE_CODE equ 0x0800
|
|
||||||
ACC_TYPE_READABLE equ 0x0200
|
|
||||||
ACC_TYPE_WRITABLE equ 0x0200
|
|
||||||
ACC_TYPE_CODE_READABLE equ 0x1a00
|
|
||||||
ACC_TYPE_DATA_WRITABLE equ 0x1200
|
|
||||||
|
|
||||||
EXT_NONE equ 0x0000
|
|
||||||
EXT_BIG equ 0x0040
|
|
||||||
|
|
||||||
;
|
;
|
||||||
; If we built our data structures in RAM, we might use the first page of RAM (0x0000-0x0fff) like so:
|
; If we built our data structures in RAM, we might use the first page of RAM (0x0000-0x0fff) like so:
|
||||||
;
|
;
|
||||||
|
|
@ -66,25 +59,9 @@ EXT_BIG equ 0x0040
|
||||||
;RAM_RETF equ 0x0d10
|
;RAM_RETF equ 0x0d10
|
||||||
|
|
||||||
CSEG_REAL equ 0xf000
|
CSEG_REAL equ 0xf000
|
||||||
CSEG_PROT equ 0x0008
|
CSEG_PROT16 equ 0x0008
|
||||||
DSEG_PROT equ 0x0010
|
CSEG_PROT32 equ 0x0010
|
||||||
|
DSEG_PROT16 equ 0x0018
|
||||||
CR0_MSW_PE equ 0x0001
|
|
||||||
|
|
||||||
;
|
|
||||||
; The "set" macro initializes a register to the specified value (eg, "set eax,0")
|
|
||||||
;
|
|
||||||
%macro set 2
|
|
||||||
%ifnum %2
|
|
||||||
%if %2 = 0
|
|
||||||
xor %1,%1
|
|
||||||
%else
|
|
||||||
mov %1,%2
|
|
||||||
%endif
|
|
||||||
%else
|
|
||||||
mov %1,%2
|
|
||||||
%endif
|
|
||||||
%endmacro
|
|
||||||
|
|
||||||
;
|
;
|
||||||
; The "defDesc" macro defines a descriptor, given a name (%1), base (%2), limit (%3), type (%4), and ext (%5)
|
; The "defDesc" macro defines a descriptor, given a name (%1), base (%2), limit (%3), type (%4), and ext (%5)
|
||||||
|
|
@ -118,14 +95,29 @@ CR0_MSW_PE equ 0x0001
|
||||||
%endmacro
|
%endmacro
|
||||||
|
|
||||||
start: cli
|
start: cli
|
||||||
|
;
|
||||||
|
; Test unsigned 32-bit multiplication and division
|
||||||
|
;
|
||||||
mov eax,0x44332211
|
mov eax,0x44332211
|
||||||
mov ebx,eax
|
mov ebx,eax
|
||||||
mov ecx,0x88776655
|
mov ecx,0x88776655
|
||||||
mul ecx
|
mul ecx
|
||||||
div ecx
|
div ecx
|
||||||
cmp eax,ebx
|
cmp eax,ebx
|
||||||
je near initGDT ; apparently we have to tell NASM "near" because this is a forward reference
|
jne near exitErr ; apparently we have to tell NASM "near" because this is a forward reference
|
||||||
|
|
||||||
|
xor dx,dx
|
||||||
|
mov ds,dx ; DS -> 0x0000
|
||||||
|
;
|
||||||
|
; Test moving a segment register to a 32-bit register
|
||||||
|
;
|
||||||
|
mov eax,ds
|
||||||
|
test eax,eax
|
||||||
|
jnz near exitErr
|
||||||
|
|
||||||
|
jmp initGDT
|
||||||
times 32768 nop ; lots of NOPs to force a 16-bit conditional jump
|
times 32768 nop ; lots of NOPs to force a 16-bit conditional jump
|
||||||
|
|
||||||
;
|
;
|
||||||
; storeDesc(EBX=base, ECX=limit, DX=type, AX=ext, DI=address of descriptor)
|
; storeDesc(EBX=base, ECX=limit, DX=type, AX=ext, DI=address of descriptor)
|
||||||
;
|
;
|
||||||
|
|
@ -150,19 +142,15 @@ storeDesc:
|
||||||
ret
|
ret
|
||||||
|
|
||||||
addrGDT:dw myGDTEnd - myGDT - 1 ; 16-bit limit of myGDT
|
addrGDT:dw myGDTEnd - myGDT - 1 ; 16-bit limit of myGDT
|
||||||
dw myGDT, 0xffff ; 32-bit base address of myGDT (works as long as we're aliased at 0xffff0000)
|
dw myGDT, 0x000f ; 32-bit base address of myGDT
|
||||||
|
|
||||||
;
|
;
|
||||||
; TODO: Why do I need to provide a 2nd parameter for "defDesc NULL"? Is this a NASM 0.98.x bug?
|
; TODO: Why do I need to provide a 2nd parameter for "defDesc NULL"? Is this a NASM 0.98.x bug?
|
||||||
;
|
;
|
||||||
myGDT: defDesc NULL,0 ; the first descriptor in any descriptor table is always a dud (it corresponds to the null selector)
|
myGDT: defDesc NULL,0 ; the first descriptor in any descriptor table is always a dud (it corresponds to the null selector)
|
||||||
%ifdef PMODE_32BIT
|
defDesc CSEG_PROT16,0x000f0000,0x0000ffff,ACC_TYPE_CODE_READABLE,EXT_NONE
|
||||||
defDesc CSEG_PROT,0x000f0000,0x0000ffff,ACC_TYPE_CODE_READABLE,EXT_BIG
|
defDesc CSEG_PROT32,0x000f0000,0x0000ffff,ACC_TYPE_CODE_READABLE,EXT_BIG
|
||||||
defDesc DSEG_PROT,0x00000000,0x000fffff,ACC_TYPE_DATA_WRITABLE,EXT_BIG
|
defDesc DSEG_PROT16,0x00000000,0x000fffff,ACC_TYPE_DATA_WRITABLE,EXT_NONE
|
||||||
%else
|
|
||||||
defDesc CSEG_PROT,0x000f0000,0x0000ffff,ACC_TYPE_CODE_READABLE,EXT_NONE
|
|
||||||
defDesc DSEG_PROT,0x00000000,0x000fffff,ACC_TYPE_DATA_WRITABLE,EXT_NONE
|
|
||||||
%endif
|
|
||||||
myGDTEnd:
|
myGDTEnd:
|
||||||
|
|
||||||
initGDT:
|
initGDT:
|
||||||
|
|
@ -173,8 +161,9 @@ initGDT:
|
||||||
xor eax,eax
|
xor eax,eax
|
||||||
mov ax,cs
|
mov ax,cs
|
||||||
shl eax,4
|
shl eax,4
|
||||||
setDesc CSEG_PROT,eax,0x0000ffff,ACC_TYPE_CODE_READABLE,EXT_NONE
|
setDesc CSEG_PROT16,eax,0x0000ffff,ACC_TYPE_CODE_READABLE,EXT_NONE
|
||||||
setDesc DSEG_PROT,0x0,0x000fffff,ACC_TYPE_DATA_WRITABLE,EXT_NONE
|
setDesc CSEG_PROT32,eax,0x0000ffff,ACC_TYPE_CODE_READABLE,EXT_BIG
|
||||||
|
setDesc DSEG_PROT16,0x0,0x000fffff,ACC_TYPE_DATA_WRITABLE,EXT_NONE
|
||||||
sub edi,RAM_GDT
|
sub edi,RAM_GDT
|
||||||
dec edi
|
dec edi
|
||||||
mov [RAM_GDTR],di
|
mov [RAM_GDTR],di
|
||||||
|
|
@ -182,65 +171,177 @@ initGDT:
|
||||||
mov word [RAM_RETF+2],cs
|
mov word [RAM_RETF+2],cs
|
||||||
%else
|
%else
|
||||||
;
|
;
|
||||||
; This code will have no effect if we're in ROM (but in that case, everything should already be initialized correctly)
|
; This code fixes the GDT and all our FAR jumps if we're running in RAM
|
||||||
;
|
;
|
||||||
xor eax,eax
|
xor eax,eax
|
||||||
mov ax,cs
|
mov ax,cs
|
||||||
shl eax,4 ; EAX = base address of the current CS
|
shl eax,4 ; EAX == base address of the current CS
|
||||||
mov edx,eax ; save it in EDX
|
mov edx,eax ; save it in EDX
|
||||||
mov [cs:myGDT+CSEG_PROT+2],ax ; update the base portions of the descriptor for CSEG_PROT
|
mov [cs:myGDT+CSEG_PROT16+2],ax ; update the base portions of the descriptor for CSEG_PROT16 and CSEG_PROT32
|
||||||
|
mov [cs:myGDT+CSEG_PROT32+2],ax
|
||||||
shr eax,16
|
shr eax,16
|
||||||
mov [cs:myGDT+CSEG_PROT+4],al
|
mov [cs:myGDT+CSEG_PROT16+4],al
|
||||||
mov [cs:myGDT+CSEG_PROT+7],ah
|
mov [cs:myGDT+CSEG_PROT32+4],al
|
||||||
|
mov [cs:myGDT+CSEG_PROT16+7],ah
|
||||||
|
mov [cs:myGDT+CSEG_PROT32+7],ah
|
||||||
mov eax,edx ; recover the base address of the current CS
|
mov eax,edx ; recover the base address of the current CS
|
||||||
add eax,myGDT ; EAX = physical address of myGDT
|
add eax,myGDT ; EAX == physical address of myGDT
|
||||||
mov [cs:addrGDT+2],eax ; update the 32-bit base address of myGDT in addrGDT
|
mov [cs:addrGDT+2],eax ; update the 32-bit base address of myGDT in addrGDT
|
||||||
%ifdef PMODE_32BIT
|
mov ax,cs
|
||||||
mov [cs:jmpReal+5],cs ; update the segment of the far jmp that returns us to real-mode
|
%ifdef PROT32
|
||||||
%else
|
mov [cs:jmpReal+5],ax ; update the segment of the FAR jump that returns us to real-mode
|
||||||
mov [cs:jmpReal+3],cs
|
%else
|
||||||
%endif
|
mov [cs:jmpReal+3],ax
|
||||||
mov [cs:jmpStart+3],cs ; ditto for the far jmp that returns us to the start of the image
|
%endif
|
||||||
|
mov [cs:jmpStart+3],ax ; ditto for the FAR jump that returns us to the start of the image
|
||||||
%endif
|
%endif
|
||||||
|
;
|
||||||
|
; Now we want to build a page directory and a page table, but we need two pages of
|
||||||
|
; 4K-aligned physical memory. We can use hard-coded addresses in we're running in ROM,
|
||||||
|
; otherwise we ask DOS for some memory.
|
||||||
|
;
|
||||||
|
cmp ax,CSEG_REAL
|
||||||
|
mov edi,0x1000 ; default to the 2nd physical page in low memory
|
||||||
|
je initPages
|
||||||
|
mov bx,0x1000 ; 4K paragraphs == 64K bytes
|
||||||
|
mov ah,DOS_SETBLOCK ; resize the current block so we can allocate a new block
|
||||||
|
int INT_DOS
|
||||||
|
jnc allocPages
|
||||||
|
exitErrDOSMem:
|
||||||
|
mov dx,errDOSMem
|
||||||
|
exitErrDOS:
|
||||||
|
mov ah,DOS_STD_CON_STRING_OUTPUT
|
||||||
|
int INT_DOS
|
||||||
|
int INT_DOSEXIT
|
||||||
|
|
||||||
|
errDOSMem:
|
||||||
|
db "Insufficient memory",CR,LF,'$'
|
||||||
|
|
||||||
|
exitErr:nop
|
||||||
|
int3
|
||||||
|
jmp exitErr
|
||||||
|
|
||||||
|
allocPages:
|
||||||
|
mov bx,0x1000 ; 4K paragraphs == 64K bytes
|
||||||
|
mov ah,DOS_ALLOC
|
||||||
|
int INT_DOS
|
||||||
|
jc errDOSMem
|
||||||
|
;
|
||||||
|
; AX == segment of 64K memory block
|
||||||
|
;
|
||||||
|
movzx eax,ax
|
||||||
|
shl eax,4
|
||||||
|
add eax,0xfff
|
||||||
|
and eax,~0xfff
|
||||||
|
mov edi,eax ; EDI == first physical 4K-aligned page within the 64K
|
||||||
|
|
||||||
|
initPages:
|
||||||
|
mov esi,edi ; ESI == saved copy of EDI
|
||||||
|
;
|
||||||
|
; Build a page directory at EDI with only 1 valid PDE (the first one)
|
||||||
|
;
|
||||||
|
cld
|
||||||
|
mov eax,edi
|
||||||
|
add eax,0x1000 ; EAX == page frame address (of the next page)
|
||||||
|
or eax,PTE_USER | PTE_READWRITE | PTE_PRESENT
|
||||||
|
stosd
|
||||||
|
mov ecx,1024-1 ; ECX == number of (remaining) PDEs to write
|
||||||
|
sub eax,eax
|
||||||
|
rep stosd
|
||||||
|
;
|
||||||
|
; Build a page table at EDI with only 256 (out of 1024) valid PTEs, which will map the first 1Mb of the
|
||||||
|
; first 4Mb as linear == physical.
|
||||||
|
;
|
||||||
|
mov eax,PTE_USER | PTE_READWRITE | PTE_PRESENT
|
||||||
|
mov ecx,256 ; ECX == number of PTEs to write
|
||||||
|
initPT: stosd
|
||||||
|
add eax,0x1000
|
||||||
|
loop initPT
|
||||||
|
mov ecx,1024-256 ; ECX == number of (remaining) PTEs to write
|
||||||
|
sub eax,eax
|
||||||
|
rep stosd
|
||||||
|
|
||||||
goProt: o32 lgdt [cs:addrGDT]
|
goProt: o32 lgdt [cs:addrGDT]
|
||||||
|
mov cr3,esi
|
||||||
mov eax,cr0
|
mov eax,cr0
|
||||||
|
%ifdef PAGING
|
||||||
|
or eax,CR0_MSW_PE | CR0_PG
|
||||||
|
%else
|
||||||
or eax,CR0_MSW_PE
|
or eax,CR0_MSW_PE
|
||||||
mov cr0,eax
|
|
||||||
nop
|
|
||||||
jmpProt:
|
|
||||||
jmp CSEG_PROT:toProt
|
|
||||||
|
|
||||||
toProt:
|
|
||||||
%ifdef PMODE_32BIT
|
|
||||||
bits 32 ; only if we define the CSEG_PROT descriptor with EXT_BIG
|
|
||||||
%endif
|
%endif
|
||||||
mov ax,DSEG_PROT
|
mov cr0,eax
|
||||||
|
jmpProt:
|
||||||
|
jmp CSEG_PROT32:toProt32
|
||||||
|
|
||||||
|
toProt32:
|
||||||
|
bits 32
|
||||||
|
|
||||||
|
mov ax,DSEG_PROT16
|
||||||
mov ds,ax
|
mov ds,ax
|
||||||
mov es,ax
|
mov es,ax
|
||||||
;
|
;
|
||||||
; Do some protected-mode tests now...
|
; Test moving a segment register to a 32-bit memory location
|
||||||
;
|
;
|
||||||
|
mov edx,[0x0000] ; save the DWORD at 0x0000:0x0000 in EDX
|
||||||
|
or eax,-1
|
||||||
|
mov [0x0000],eax
|
||||||
|
mov [0x0000],ds
|
||||||
|
mov eax,ds
|
||||||
|
cmp eax,[0x0000]
|
||||||
|
err1: jne err1
|
||||||
|
mov [0x0000],edx ; restore the DWORD at 0x0000:0x0000 from EDX
|
||||||
|
|
||||||
|
;
|
||||||
|
; Test moving a byte to a 32-bit register with sign-extension
|
||||||
|
;
|
||||||
|
movsx eax,byte [0xfffff]
|
||||||
|
cmp eax,0xffffff80
|
||||||
|
err2: jne err2
|
||||||
|
|
||||||
|
;
|
||||||
|
; Test moving a word to a 32-bit register with sign-extension
|
||||||
|
;
|
||||||
|
movsx eax,word [0xffffe]
|
||||||
|
cmp eax,0xffff80fc
|
||||||
|
err3: jne err3
|
||||||
|
|
||||||
|
;
|
||||||
|
; Test moving a byte to a 32-bit register with zero-extension
|
||||||
|
;
|
||||||
|
movzx eax,byte [0xfffff]
|
||||||
|
cmp eax,0x00000080
|
||||||
|
err4: jne err4
|
||||||
|
|
||||||
|
;
|
||||||
|
; Test moving a word to a 32-bit register with zero-extension
|
||||||
|
;
|
||||||
|
movzx eax,word [0xffffe]
|
||||||
|
cmp eax,0x000080fc
|
||||||
|
err5: jne err5
|
||||||
|
|
||||||
|
;
|
||||||
|
; Return to real-mode now, after first loading CS with a 16-bit code segment
|
||||||
|
;
|
||||||
|
jmp CSEG_PROT16:toProt16
|
||||||
|
|
||||||
|
toProt16:
|
||||||
|
bits 16
|
||||||
|
|
||||||
goReal: mov eax,cr0
|
goReal: mov eax,cr0
|
||||||
and eax,~CR0_MSW_PE
|
and eax,~(CR0_MSW_PE | CR0_PG)
|
||||||
mov cr0,eax
|
mov cr0,eax
|
||||||
nop
|
|
||||||
jmpReal:
|
jmpReal:
|
||||||
jmp CSEG_REAL:toReal
|
jmp CSEG_REAL:toReal
|
||||||
|
|
||||||
toReal:
|
toReal:
|
||||||
%ifdef PMODE_32BIT
|
|
||||||
bits 16 ; only if we define the CSEG_PROT descriptor with EXT_BIG
|
|
||||||
%endif
|
|
||||||
mov ax,cs
|
mov ax,cs
|
||||||
cmp ax,CSEG_REAL ; is CS equal to 0xf000?
|
cmp ax,CSEG_REAL ; is CS equal to 0xf000?
|
||||||
je near jmpStart ; yes
|
je near jmpStart ; yes, so loop around, only because we have nowhere else to go
|
||||||
int 0x20 ; no, so assume we're running under DOS and exit
|
int INT_DOSEXIT ; no, so assume we're running under DOS and exit
|
||||||
|
;
|
||||||
;
|
; Fill the remaining space with NOPs until we get to target offset 0xFFF0.
|
||||||
; Fill the remaining space with NOPs until we get to target offset 0xFFF0.
|
; Note that we subtract 0x100 from the target offset because we're ORG'ed at 0x100.
|
||||||
; Note that we subtract 0x100 from the target offset because we're ORG'ed at 0x100.
|
;
|
||||||
;
|
|
||||||
times 0xfff0-0x100-($-$$) nop
|
times 0xfff0-0x100-($-$$) nop
|
||||||
|
|
||||||
jmpStart:
|
jmpStart:
|
||||||
|
|
@ -249,4 +350,4 @@ jmpStart:
|
||||||
db 0x20
|
db 0x20
|
||||||
db '04/04/15'
|
db '04/04/15'
|
||||||
db 0xFC ; 0000FFFE FC (Model ID byte)
|
db 0xFC ; 0000FFFE FC (Model ID byte)
|
||||||
db 0x00 ; 0000FFFF 00 (location of checksum byte)
|
db 0x80 ; 0000FFFF 80 (normally, location of a checksum byte)
|
||||||
|
|
|
||||||
141
tests/pc/inc/dos.inc
Normal file
141
tests/pc/inc/dos.inc
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
INT_DOSEXIT EQU 20H
|
||||||
|
INT_DOS EQU 21H
|
||||||
|
DOS_ABORT EQU 00H
|
||||||
|
DOS_STD_CON_INPUT EQU 01H
|
||||||
|
DOS_STD_CON_OUTPUT EQU 02H
|
||||||
|
DOS_STD_AUX_INPUT EQU 03H
|
||||||
|
DOS_STD_AUX_OUTPUT EQU 04H
|
||||||
|
DOS_STD_PRINTER_OUTPUT EQU 05H
|
||||||
|
DOS_RAW_CON_IO EQU 06H
|
||||||
|
DOS_RAW_CON_INPUT EQU 07H
|
||||||
|
DOS_STD_CON_INPUT_NO_ECHO EQU 08H
|
||||||
|
DOS_STD_CON_STRING_OUTPUT EQU 09H
|
||||||
|
DOS_STD_CON_STRING_INPUT EQU 0AH
|
||||||
|
DOS_STD_CON_INPUT_STATUS EQU 0BH
|
||||||
|
DOS_STD_CON_INPUT_FLUSH EQU 0CH
|
||||||
|
DOS_DISK_RESET EQU 0DH
|
||||||
|
DOS_SET_DEFAULT_DRIVE EQU 0EH
|
||||||
|
DOS_FCB_OPEN EQU 0FH
|
||||||
|
DOS_FCB_CLOSE EQU 10H
|
||||||
|
DOS_DIR_SEARCH_FIRST EQU 11H
|
||||||
|
DOS_DIR_SEARCH_NEXT EQU 12H
|
||||||
|
DOS_FCB_DELETE EQU 13H
|
||||||
|
DOS_FCB_SEQ_READ EQU 14H
|
||||||
|
DOS_FCB_SEQ_WRITE EQU 15H
|
||||||
|
DOS_FCB_CREATE EQU 16H
|
||||||
|
DOS_FCB_RENAME EQU 17H
|
||||||
|
DOS_RESERVED18 EQU 18H
|
||||||
|
DOS_GET_DEFAULT_DRIVE EQU 19H
|
||||||
|
DOS_SET_DMA EQU 1AH
|
||||||
|
DOS_RESERVED1B EQU 1BH
|
||||||
|
DOS_RESERVED1C EQU 1CH
|
||||||
|
DOS_RESERVED1D EQU 1DH
|
||||||
|
DOS_RESERVED1E EQU 1EH
|
||||||
|
DOS_GET_DEFAULT_DPB EQU 1FH
|
||||||
|
DOS_RESERVED20 EQU 20H
|
||||||
|
DOS_FCB_RANDOM_READ EQU 21H
|
||||||
|
DOS_FCB_RANDOM_WRITE EQU 22H
|
||||||
|
DOS_GET_FCB_FILE_LENGTH EQU 23H
|
||||||
|
DOS_GET_FCB_POSITION EQU 24H
|
||||||
|
DOS_SET_INTERRUPT_VECTOR EQU 25H
|
||||||
|
DOS_CREATE_PDB EQU 26H
|
||||||
|
DOS_FCB_RANDOM_READ_BLOCK EQU 27H
|
||||||
|
DOS_FCB_RANDOM_WRITE_BLOCK EQU 28H
|
||||||
|
DOS_PARSE_FILE_DESCRIPTOR EQU 29H
|
||||||
|
DOS_GET_DATE EQU 2AH
|
||||||
|
DOS_SET_DATE EQU 2BH
|
||||||
|
DOS_GET_TIME EQU 2CH
|
||||||
|
DOS_SET_TIME EQU 2DH
|
||||||
|
DOS_SET_VERIFY_ON_WRITE EQU 2EH
|
||||||
|
DOS_GET_DMA EQU 2FH
|
||||||
|
DOS_GET_VERSION EQU 30H
|
||||||
|
DOS_KEEP_PROCESS EQU 31H
|
||||||
|
DOS_GET_DPB EQU 32H
|
||||||
|
DOS_SET_CTRL_C_TRAPPING EQU 33H
|
||||||
|
DOS_GET_INDOS_FLAG EQU 34H
|
||||||
|
DOS_GET_INTERRUPT_VECTOR EQU 35H
|
||||||
|
DOS_GET_DRIVE_FREESPACE EQU 36H
|
||||||
|
DOS_CHAR_OPER EQU 37H
|
||||||
|
DOS_INTERNATIONAL_SUPPORT EQU 38H
|
||||||
|
DOS_MKDIR EQU 39H
|
||||||
|
DOS_RMDIR EQU 3AH
|
||||||
|
DOS_CHDIR EQU 3BH
|
||||||
|
DOS_CREAT EQU 3CH
|
||||||
|
DOS_OPEN EQU 3DH
|
||||||
|
DOS_CLOSE EQU 3EH
|
||||||
|
DOS_READ EQU 3FH
|
||||||
|
DOS_WRITE EQU 40H
|
||||||
|
DOS_UNLINK EQU 41H
|
||||||
|
DOS_LSEEK EQU 42H
|
||||||
|
DOS_CHMOD EQU 43H
|
||||||
|
DOS_IOCTL EQU 44H
|
||||||
|
DOS_XDUP EQU 45H
|
||||||
|
DOS_XDUP2 EQU 46H
|
||||||
|
DOS_GETDIR EQU 47H
|
||||||
|
DOS_ALLOC EQU 48H
|
||||||
|
DOS_DEALLOC EQU 49H
|
||||||
|
DOS_SETBLOCK EQU 4AH
|
||||||
|
DOS_EXEC EQU 4BH
|
||||||
|
DOS_EXIT EQU 4CH
|
||||||
|
DOS_WAIT EQU 4DH
|
||||||
|
DOS_FIND_FIRST EQU 4EH
|
||||||
|
DOS_FIND_NEXT EQU 4FH
|
||||||
|
DOS_SET_CURRENT_PDB EQU 50H
|
||||||
|
DOS_GET_CURRENT_PDB EQU 51H
|
||||||
|
DOS_GET_SYSINIT_VARS EQU 52H
|
||||||
|
DOS_SET_DPB EQU 53H
|
||||||
|
DOS_GET_VERIFY_ON_WRITE EQU 54H
|
||||||
|
DOS_DUP_PDB EQU 55H
|
||||||
|
DOS_RENAME EQU 56H
|
||||||
|
DOS_FILE_TIMES EQU 57H
|
||||||
|
DOS_RESERVED58 EQU 58H
|
||||||
|
DOS_GET_EXTENDED_ERROR EQU 59H
|
||||||
|
DOS_CREATE_TEMP_FILE EQU 5AH
|
||||||
|
DOS_CREATE_NEW_FILE EQU 5BH
|
||||||
|
DOS_LOCK_OPER EQU 5CH
|
||||||
|
DOS_SERVER_CALL EQU 5DH
|
||||||
|
DOS_USER_OPER EQU 5EH
|
||||||
|
DOS_ASSIGN_OPER EQU 5FH
|
||||||
|
DOS_XNAMETRANS EQU 60H
|
||||||
|
DOS_JSA EQU 61H
|
||||||
|
DOS_GET_CURRENT_PSP EQU 62H
|
||||||
|
DOS_HONGEUL EQU 63H
|
||||||
|
DOS_SYSINITSLEAZE EQU 64H
|
||||||
|
DOSERR_NONE EQU 00H
|
||||||
|
DOSERR_BADFUNCTION EQU 01H
|
||||||
|
DOSERR_NOFILE EQU 02H
|
||||||
|
DOSERR_NOPATH EQU 03H
|
||||||
|
DOSERR_NOHANDLES EQU 04H
|
||||||
|
DOSERR_NOACCESS EQU 05H
|
||||||
|
DOSERR_BADHANDLE EQU 06H
|
||||||
|
DOSERR_BADARENA EQU 07H
|
||||||
|
DOSERR_NOMEMORY EQU 08H
|
||||||
|
DOSERR_BADADDRESS EQU 09H
|
||||||
|
DOSERR_BADENVIRONMENT EQU 0AH
|
||||||
|
DOSERR_BADFORMAT EQU 0BH
|
||||||
|
DOSERR_BADACCESS EQU 0CH
|
||||||
|
DOSERR_BADDATA EQU 0DH
|
||||||
|
DOSERR_BADUNIT EQU 0EH
|
||||||
|
DOSERR_BADDISK EQU 0FH
|
||||||
|
DOSERR_DELETECURDIR EQU 10H
|
||||||
|
DOSERR_NOTSAMEDEVICE EQU 11H
|
||||||
|
DOSERR_NOMOREFILES EQU 12H
|
||||||
|
DOSERR_WRITEPROTECT EQU 13H
|
||||||
|
DOSERR_UNKNOWNUNIT EQU 14H
|
||||||
|
DOSERR_DRIVENOTREADY EQU 15H
|
||||||
|
DOSERR_BADCOMMAND EQU 16H
|
||||||
|
DOSERR_DATA EQU 17H
|
||||||
|
DOSERR_BADREQUEST EQU 18H
|
||||||
|
DOSERR_SEEK EQU 19H
|
||||||
|
DOSERR_UNKNOWNMEDIA EQU 1AH
|
||||||
|
DOSERR_BADSECTOR EQU 1BH
|
||||||
|
DOSERR_NOPAPER EQU 1CH
|
||||||
|
DOSERR_WRITEFAULT EQU 1DH
|
||||||
|
DOSERR_READFAULT EQU 1EH
|
||||||
|
DOSERR_GENERALFAILURE EQU 1FH
|
||||||
|
DOSERR_NOTSHARED EQU 20H
|
||||||
|
DOSERR_LOCKED EQU 21H
|
||||||
|
DOSERR_DISKCHANGE EQU 22H
|
||||||
|
SEEK_SET EQU 00H
|
||||||
|
SEEK_CUR EQU 01H
|
||||||
|
SEEK_END EQU 02H
|
||||||
17
tests/pc/inc/misc.inc
Normal file
17
tests/pc/inc/misc.inc
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
CR equ 0x0d
|
||||||
|
LF equ 0x0a
|
||||||
|
|
||||||
|
;
|
||||||
|
; The "set" macro initializes a register to the specified value (eg, "set eax,0")
|
||||||
|
;
|
||||||
|
%macro set 2
|
||||||
|
%ifnum %2
|
||||||
|
%if %2 = 0
|
||||||
|
xor %1,%1
|
||||||
|
%else
|
||||||
|
mov %1,%2
|
||||||
|
%endif
|
||||||
|
%else
|
||||||
|
mov %1,%2
|
||||||
|
%endif
|
||||||
|
%endmacro
|
||||||
23
tests/pc/inc/x86.inc
Normal file
23
tests/pc/inc/x86.inc
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
;
|
||||||
|
; X86.DESC defines (see x86.js)
|
||||||
|
;
|
||||||
|
ACC_TYPE_SEG equ 0x1000
|
||||||
|
ACC_PRESENT equ 0x8000
|
||||||
|
ACC_TYPE_CODE equ 0x0800
|
||||||
|
ACC_TYPE_READABLE equ 0x0200
|
||||||
|
ACC_TYPE_WRITABLE equ 0x0200
|
||||||
|
ACC_TYPE_CODE_READABLE equ 0x1a00
|
||||||
|
ACC_TYPE_DATA_WRITABLE equ 0x1200
|
||||||
|
|
||||||
|
EXT_NONE equ 0x0000
|
||||||
|
EXT_BIG equ 0x0040
|
||||||
|
|
||||||
|
CR0_MSW_PE equ 0x0001
|
||||||
|
CR0_PG equ 0x80000000 ; set if paging enabled
|
||||||
|
|
||||||
|
PTE_FRAME equ 0xfffff000
|
||||||
|
PTE_DIRTY equ 0x00000040 ; page has been modified
|
||||||
|
PTE_ACCESSED equ 0x00000020 ; page has been accessed
|
||||||
|
PTE_USER equ 0x00000004 ; set for user level (CPL 3), clear for supervisor level (CPL 0-2)
|
||||||
|
PTE_READWRITE equ 0x00000002 ; set for read/write, clear for read-only (affects CPL 3 only)
|
||||||
|
PTE_PRESENT equ 0x00000001 ; set for present page, clear for not-present page
|
||||||
Loading…
Reference in a new issue