Cleaned up conditional jump handling
This commit is contained in:
parent
e057bd7a05
commit
2784934491
10 changed files with 135 additions and 50 deletions
|
|
@ -8,16 +8,16 @@
|
|||
"ram": [
|
||||
{ "id": "pc386.ramLow",
|
||||
"name": "",
|
||||
"addr": 0x00000,
|
||||
"size": 0xa0000,
|
||||
"addr": 0,
|
||||
"size": 655360,
|
||||
"test": false
|
||||
}
|
||||
],
|
||||
"rom": [
|
||||
{ "id": "pc386.romTests",
|
||||
"name": "",
|
||||
"addr": 0xf0000,
|
||||
"size": 0x10000,
|
||||
"addr": 983296,
|
||||
"size": 65280,
|
||||
"file": "/tests/pc/80386/tests.json",
|
||||
"notify": ""
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,8 +100,8 @@ A BackTrack index is encoded as a 32-bit value with three parts:
|
|||
|
||||
This represents a total of 31 bits, with bit 31 reserved.
|
||||
|
||||
For example, look at one of the last things a ROM does during boot: load a disk sector into RAM. It will be up to the
|
||||
disk controller (or DMA controller if one is used) to create a BackTrack object representing the sector that was read,
|
||||
For example, look at one of the last things a ROM does during boot: loading a disk sector into RAM. It will be up to the
|
||||
disk controller (or DMA controller, if used) to create a BackTrack object representing the sector that was read,
|
||||
adding that object to the global BackTrack object array, and then associating the corresponding BackTrack index with
|
||||
the first byte of RAM where the sector was loaded. Subsequent bytes of RAM containing the rest of the sector will refer
|
||||
to the same BackTrack object, using BackTrack indexes containing offsets 1-511.
|
||||
|
|
|
|||
|
|
@ -1603,7 +1603,7 @@ if (DEBUGGER) {
|
|||
/*
|
||||
* When we dump the EXT word, we mask off the LIMIT1619 and BASE2431 bits, because those have already
|
||||
* been incorporated into the limit and base properties of the segment register; all we care about here
|
||||
* are whether EXT contains any of the AVAIL (0x10), BIG (0x40) or GRANULARITY (0x80) bits.
|
||||
* are whether EXT contains any of the AVAIL (0x10), BIG (0x40) or LIMITPAGES (0x80) bits.
|
||||
*/
|
||||
this.println(sDump + " dpl=" + str.toHexByte(seg.dpl) + " type=" + str.toHexByte(seg.type >> 8) + " (" + sType + ")" + " ext=" + str.toHexWord(seg.ext & ~(X86.DESC.EXT.LIMIT1619 | X86.DESC.EXT.BASE2431)));
|
||||
};
|
||||
|
|
|
|||
|
|
@ -103,10 +103,10 @@ var X86 = {
|
|||
MASK: 0xfff8 // table index
|
||||
},
|
||||
DESC: { // Descriptor Table Entry
|
||||
LIMIT: {
|
||||
LIMIT: { // LIMIT bits 0-15
|
||||
OFFSET: 0x0
|
||||
},
|
||||
BASE: {
|
||||
BASE: { // BASE bits 0-15
|
||||
OFFSET: 0x2
|
||||
},
|
||||
ACC: { // bit definitions for the access word (offset 0x4)
|
||||
|
|
@ -166,7 +166,7 @@ var X86 = {
|
|||
* is 0xffffffff instead of 0xffff.
|
||||
*/
|
||||
BIG: 0x0040, // clear if default operand/address size is 16-bit, set if 32-bit
|
||||
GRANULARITY: 0x0080, // clear if limit is bytes, set if limit is 4Kb pages
|
||||
LIMITPAGES: 0x0080, // clear if limit granularity is bytes, set if limit granularity is 4Kb pages
|
||||
BASE2431: 0xff00
|
||||
},
|
||||
INVALID: 0 // use X86.DESC.INVALID for invalid DESC values
|
||||
|
|
|
|||
|
|
@ -3197,18 +3197,6 @@ X86CPU.prototype.getIPDisp = function()
|
|||
return w;
|
||||
};
|
||||
|
||||
/**
|
||||
* getIPDispWord()
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @return {number} sign-extended value from the word at the current IP; IP advanced by 2 or 4
|
||||
*/
|
||||
X86CPU.prototype.getIPDispWord = function()
|
||||
{
|
||||
var w = this.getIPWord();
|
||||
return (this.dataSize == 2? ((w << 16) >> 16) : w);
|
||||
};
|
||||
|
||||
/**
|
||||
* getSIBAddr(mod)
|
||||
*
|
||||
|
|
|
|||
|
|
@ -342,6 +342,23 @@ X86.opMOVcr = function MOVcr()
|
|||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* NOTE: The following 16 new conditional jumps actually rely on the OPERAND override setting
|
||||
* for determining whether a signed 16-bit or 32-bit displacement will be fetched, even though
|
||||
* the ADDRESS override might seem more intuitive. Think of them as instructions that are loading
|
||||
* a new operand into IP/EIP.
|
||||
*
|
||||
* Also, in 16-bit code, even though a signed rel16 value would seem to imply a range of -32768
|
||||
* to +32767, any location within a 64Kb code segment outside that range can be reached by choosing
|
||||
* a displacement in the opposite direction, causing the 16-bit value in EIP to underflow or overflow;
|
||||
* any underflow or overflow doesn't matter, because only the low 16 bits of EIP are used when a
|
||||
* 16-bit OPERAND size is in effect.
|
||||
*
|
||||
* In fact, for 16-bit jumps, it's simpler to always think of rel16 as an UNSIGNED value added to
|
||||
* the current EIP, where the result is then truncated to a 16-bit value. This is why we don't have
|
||||
* to sign-extend rel16 before adding it to the current EIP.
|
||||
*/
|
||||
|
||||
/**
|
||||
* opJOw()
|
||||
*
|
||||
|
|
@ -351,7 +368,7 @@ X86.opMOVcr = function MOVcr()
|
|||
*/
|
||||
X86.opJOw = function JOw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
var disp = this.getIPWord();
|
||||
if (this.getOF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesJmpC;
|
||||
|
|
@ -369,7 +386,7 @@ X86.opJOw = function JOw()
|
|||
*/
|
||||
X86.opJNOw = function JNOw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
var disp = this.getIPWord();
|
||||
if (!this.getOF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesJmpC;
|
||||
|
|
@ -387,7 +404,7 @@ X86.opJNOw = function JNOw()
|
|||
*/
|
||||
X86.opJCw = function JCw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
var disp = this.getIPWord();
|
||||
if (this.getCF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesJmpC;
|
||||
|
|
@ -405,7 +422,7 @@ X86.opJCw = function JCw()
|
|||
*/
|
||||
X86.opJNCw = function JNCw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
var disp = this.getIPWord();
|
||||
if (!this.getCF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesJmpC;
|
||||
|
|
@ -423,7 +440,7 @@ X86.opJNCw = function JNCw()
|
|||
*/
|
||||
X86.opJZw = function JZw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
var disp = this.getIPWord();
|
||||
if (this.getZF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesJmpC;
|
||||
|
|
@ -441,7 +458,7 @@ X86.opJZw = function JZw()
|
|||
*/
|
||||
X86.opJNZw = function JNZw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
var disp = this.getIPWord();
|
||||
if (!this.getZF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesJmpC;
|
||||
|
|
@ -459,7 +476,7 @@ X86.opJNZw = function JNZw()
|
|||
*/
|
||||
X86.opJBEw = function JBEw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
var disp = this.getIPWord();
|
||||
if (this.getCF() || this.getZF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesJmpC;
|
||||
|
|
@ -477,7 +494,7 @@ X86.opJBEw = function JBEw()
|
|||
*/
|
||||
X86.opJNBEw = function JNBEw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
var disp = this.getIPWord();
|
||||
if (!this.getCF() && !this.getZF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesJmpC;
|
||||
|
|
@ -495,7 +512,7 @@ X86.opJNBEw = function JNBEw()
|
|||
*/
|
||||
X86.opJSw = function JSw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
var disp = this.getIPWord();
|
||||
if (this.getSF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesJmpC;
|
||||
|
|
@ -513,7 +530,7 @@ X86.opJSw = function JSw()
|
|||
*/
|
||||
X86.opJNSw = function JNSw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
var disp = this.getIPWord();
|
||||
if (!this.getSF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesJmpC;
|
||||
|
|
@ -531,7 +548,7 @@ X86.opJNSw = function JNSw()
|
|||
*/
|
||||
X86.opJPw = function JPw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
var disp = this.getIPWord();
|
||||
if (this.getPF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesJmpC;
|
||||
|
|
@ -549,7 +566,7 @@ X86.opJPw = function JPw()
|
|||
*/
|
||||
X86.opJNPw = function JNPw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
var disp = this.getIPWord();
|
||||
if (!this.getPF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesJmpC;
|
||||
|
|
@ -567,7 +584,7 @@ X86.opJNPw = function JNPw()
|
|||
*/
|
||||
X86.opJLw = function JLw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
var disp = this.getIPWord();
|
||||
if (!this.getSF() != !this.getOF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesJmpC;
|
||||
|
|
@ -585,7 +602,7 @@ X86.opJLw = function JLw()
|
|||
*/
|
||||
X86.opJNLw = function JNLw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
var disp = this.getIPWord();
|
||||
if (!this.getSF() == !this.getOF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesJmpC;
|
||||
|
|
@ -603,7 +620,7 @@ X86.opJNLw = function JNLw()
|
|||
*/
|
||||
X86.opJLEw = function JLEw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
var disp = this.getIPWord();
|
||||
if (this.getZF() || !this.getSF() != !this.getOF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesJmpC;
|
||||
|
|
@ -621,7 +638,7 @@ X86.opJLEw = function JLEw()
|
|||
*/
|
||||
X86.opJNLEw = function JNLEw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
var disp = this.getIPWord();
|
||||
if (!this.getZF() && !this.getSF() == !this.getOF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesJmpC;
|
||||
|
|
@ -1301,7 +1318,7 @@ X86.aOps0F[0x06] = X86.opCLTS;
|
|||
|
||||
/*
|
||||
* On all processors (except the 8086/8088, of course), X86.OPCODE.UD2 (0x0F,0x0B), aka "UD2", is an
|
||||
* instruction guaranteed to raise a #UD (Invalid Opcode) exception (INT 0x06) on all future x86 processors.
|
||||
* instruction guaranteed to raise a #UD (Invalid Opcode) exception (INT 0x06) on all post-8086 processors.
|
||||
*/
|
||||
X86.aOps0F[0x0B] = X86.opInvalid;
|
||||
|
||||
|
|
|
|||
|
|
@ -3497,6 +3497,10 @@ X86.opESC = function ESC()
|
|||
/**
|
||||
* op=0xE0 (LOOPNZ disp)
|
||||
*
|
||||
* NOTE: All the instructions in this group (LOOPNZ, LOOPZ, LOOP, and JCXZ) actually
|
||||
* rely on the ADDRESS override setting for determining whether CX or ECX will be used,
|
||||
* even though it seems counter-intuitive; ditto for the REP prefix.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opLOOPNZ = function LOOPNZ()
|
||||
|
|
@ -3513,6 +3517,10 @@ X86.opLOOPNZ = function LOOPNZ()
|
|||
/**
|
||||
* op=0xE1 (LOOPZ disp)
|
||||
*
|
||||
* NOTE: All the instructions in this group (LOOPNZ, LOOPZ, LOOP, and JCXZ) actually
|
||||
* rely on the ADDRESS override setting for determining whether CX or ECX will be used,
|
||||
* even though it seems counter-intuitive; ditto for the REP prefix.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opLOOPZ = function LOOPZ()
|
||||
|
|
@ -3529,6 +3537,10 @@ X86.opLOOPZ = function LOOPZ()
|
|||
/**
|
||||
* op=0xE2 (LOOP disp)
|
||||
*
|
||||
* NOTE: All the instructions in this group (LOOPNZ, LOOPZ, LOOP, and JCXZ) actually
|
||||
* rely on the ADDRESS override setting for determining whether CX or ECX will be used,
|
||||
* even though it seems counter-intuitive; ditto for the REP prefix.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opLOOP = function LOOP()
|
||||
|
|
@ -3543,7 +3555,11 @@ X86.opLOOP = function LOOP()
|
|||
};
|
||||
|
||||
/**
|
||||
* op=0xE3 (JCXZ disp)
|
||||
* op=0xE3 (JCXZ/JECXZ disp)
|
||||
*
|
||||
* NOTE: All the instructions in this group (LOOPNZ, LOOPZ, LOOP, and JCXZ) actually
|
||||
* rely on the ADDRESS override setting for determining whether CX or ECX will be used,
|
||||
* even though it seems counter-intuitive; ditto for the REP prefix.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -588,7 +588,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress)
|
|||
if (I386 && cpu.model >= X86.MODEL_80386) {
|
||||
base |= (ext & X86.DESC.EXT.BASE2431) << 16;
|
||||
limit |= (ext & X86.DESC.EXT.LIMIT1619) << 16;
|
||||
if (ext & X86.DESC.EXT.GRANULARITY) limit = (limit << 12) | 0xfff;
|
||||
if (ext & X86.DESC.EXT.LIMITPAGES) limit = (limit << 12) | 0xfff;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
all: tests.json
|
||||
|
||||
tests.rom: tests.nasm
|
||||
nasm -f bin tests.nasm -l tests.lst -o tests.rom
|
||||
tests.com: tests.nasm
|
||||
nasm -f bin tests.nasm -l tests.lst -o tests.com
|
||||
|
||||
tests.json: tests.rom
|
||||
node ../../../modules/filedump/bin/filedump --file=tests.rom --output=tests.json --overwrite
|
||||
tests.json: tests.com
|
||||
node ../../../modules/filedump/bin/filedump --file=tests.com --output=tests.json --overwrite
|
||||
|
|
|
|||
|
|
@ -1,21 +1,85 @@
|
|||
cpu 386
|
||||
|
||||
org 0x0000
|
||||
;
|
||||
; This file is designed to run as a ROM replacement, but it has a .COM extension because it's
|
||||
; also designed to run as a COM file under DOS (hence the "org 0x100").
|
||||
;
|
||||
org 0x100
|
||||
section .text
|
||||
|
||||
bits 16
|
||||
|
||||
DPL0 equ 0
|
||||
DPL1 equ 1
|
||||
DPL2 equ 2
|
||||
DPL3 equ 3
|
||||
|
||||
ACC_TYPE_SEG equ 0x1000
|
||||
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_BIG equ 0x0040
|
||||
|
||||
SEG_CODE_REAL equ 0xf000
|
||||
SEG_CODE_PROT equ 0x0008
|
||||
SEG_DATA_PROT equ 0x0010
|
||||
|
||||
CR0_MSW_PE equ 0x0001
|
||||
|
||||
;
|
||||
; descDT defines a descriptor, given a base (%1), limit (%2), type (%3), dpl (%4), and bigness (%5)
|
||||
;
|
||||
%macro defDesc 1-5 0,0,0,0
|
||||
dw (%2 & 0x0000ffff)
|
||||
dw (%1 & 0x0000ffff)
|
||||
dw ((%1 & 0x00ff0000) >> 16) | %3 | (%4 << 13)
|
||||
dw ((%2 & 0x000f0000) >> 16) | %5 | ((%1 & 0xff000000) >> 16)
|
||||
%endmacro
|
||||
|
||||
|
||||
start: mov eax,0x44332211
|
||||
mov ecx,0x88776655
|
||||
mul ecx
|
||||
div ecx
|
||||
jnz near goProt
|
||||
|
||||
call dword 0xf000:start
|
||||
times 32768 nop
|
||||
|
||||
times 0xfff0-($-$$) nop
|
||||
romGDT: defDesc 0
|
||||
defDesc 0x000f0000,0x0000ffff,ACC_TYPE_CODE_READABLE,0
|
||||
defDesc 0x00000000,0x000fffff,ACC_TYPE_DATA_WRITABLE,0
|
||||
|
||||
goProt: lgdt [cs:romGDT]
|
||||
mov eax,cr0
|
||||
or eax,CR0_MSW_PE
|
||||
mov cr0,eax
|
||||
jmp dword SEG_CODE_PROT:inProt
|
||||
|
||||
inProt: mov ax,SEG_DATA_PROT
|
||||
mov ds,ax
|
||||
;
|
||||
; Do some protected-mode tests...
|
||||
;
|
||||
|
||||
goReal: mov eax,cr0
|
||||
and eax,~CR0_MSW_PE
|
||||
mov cr0,eax
|
||||
jmp dword SEG_CODE_REAL:inReal
|
||||
|
||||
inReal: or eax,1
|
||||
jnz start
|
||||
|
||||
;
|
||||
; 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.
|
||||
;
|
||||
times 0xfff0-0x100-($-$$) nop
|
||||
|
||||
bits 16
|
||||
jmp 0xf000:start
|
||||
jmp SEG_CODE_REAL:start
|
||||
|
||||
db 0x20
|
||||
db '04/04/15'
|
||||
|
|
|
|||
Loading…
Reference in a new issue