mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-26 18:04:07 +00:00
596 lines
12 KiB
Plaintext
596 lines
12 KiB
Plaintext
$title('8086 disassembler')
|
|
$date(5/14/81)
|
|
$compact
|
|
$optimize(2)
|
|
|
|
disem86: do;
|
|
|
|
declare
|
|
cr literally '0dh',
|
|
lf literally '0ah',
|
|
true literally '1',
|
|
false literally '0';
|
|
|
|
$include(optab.dat)
|
|
|
|
declare
|
|
tab$ptrs (5) address public initial (.ops2, .ops3, .ops4, .ops5, .ops6);
|
|
|
|
declare
|
|
left$bracket byte data ('['),
|
|
right$bracket byte data (']');
|
|
|
|
declare
|
|
alt$table$base address,
|
|
alt$table based alt$table$base (16) byte,
|
|
alt$table$ptrs (8) address external;
|
|
|
|
declare
|
|
mod$bits byte,
|
|
reg$bits byte,
|
|
rm$bits byte,
|
|
byte1$reg$bits byte,
|
|
d$bit byte,
|
|
s$bit byte,
|
|
v$bit byte,
|
|
w$bit byte,
|
|
z$bit byte;
|
|
|
|
declare
|
|
mnemonic$index byte, /* index into opcodes */
|
|
instr$type byte,
|
|
table$ptr address,
|
|
table$char based table$ptr byte,
|
|
disem$ptr pointer,
|
|
disem$offset address at (.disem$ptr),
|
|
disem$end address,
|
|
disem$byte based disem$ptr (1) byte,
|
|
disem$word based disem$ptr (1) address,
|
|
b$or$w$flag byte,
|
|
error$flag byte;
|
|
|
|
declare instr$table (512) byte external;
|
|
|
|
declare
|
|
ax$reg literally '0',
|
|
cx$reg literally '1',
|
|
dx$reg literally '2',
|
|
bx$reg literally '3',
|
|
sp$reg literally '4',
|
|
bp$reg literally '5',
|
|
si$reg literally '6',
|
|
di$reg literally '7';
|
|
|
|
declare
|
|
al$reg literally '0',
|
|
cl$reg literally '1',
|
|
dl$reg literally '2',
|
|
bl$reg literally '3',
|
|
ah$reg literally '4',
|
|
ch$reg literally '5',
|
|
dh$reg literally '6',
|
|
bh$reg literally '7';
|
|
|
|
declare
|
|
es$reg literally '0',
|
|
cs$reg literally '1',
|
|
ss$reg literally '2',
|
|
ds$reg literally '3';
|
|
|
|
declare
|
|
reg16 (*) byte public initial ('AX', 'CX', 'DX', 'BX', 'SP', 'BP', 'SI', 'DI'),
|
|
reg8 (*) byte public initial ('AL', 'CL', 'DL', 'BL', 'AH', 'CH', 'DH', 'BH'),
|
|
segreg (*) byte public initial ('ES', 'CS', 'SS', 'DS');
|
|
|
|
conout: procedure (c) external;
|
|
declare c byte;
|
|
end conout;
|
|
|
|
comma: procedure;
|
|
call conout (',');
|
|
end comma;
|
|
|
|
printm: procedure (a) PUBLIC;
|
|
declare a address;
|
|
declare b based a byte;
|
|
do while b <> '$';
|
|
call conout (b);
|
|
a = a + 1;
|
|
end;
|
|
end printm;
|
|
|
|
print$nibble: procedure (b);
|
|
declare b byte;
|
|
if b > 9 then call conout (b - 10 + 'A');
|
|
else call conout (b + '0');
|
|
end print$nibble;
|
|
|
|
print$byte: procedure (b);
|
|
declare b byte;
|
|
call print$nibble (shr (b, 4));
|
|
call print$nibble (b and 0fh);
|
|
end print$byte;
|
|
|
|
print$word: procedure (a) public;
|
|
declare a address;
|
|
call print$byte (high (a));
|
|
call print$byte (low (a));
|
|
end print$word;
|
|
|
|
error: procedure;
|
|
call printm (.('??= $'));
|
|
call print$byte (disem$byte (0));
|
|
disem$offset = disem$offset + 1;
|
|
end error;
|
|
|
|
set$bits: procedure;
|
|
byte1$reg$bits = disem$byte (0) and 7;
|
|
mod$bits = shr (disem$byte (1), 6);
|
|
reg$bits = shr (disem$byte (1), 3) and 7;
|
|
rm$bits = disem$byte (1) and 7;
|
|
w$bit, z$bit = disem$byte (0) and 1;
|
|
d$bit, s$bit, v$bit = shr (disem$byte (0), 1) and 1;
|
|
end set$bits;
|
|
|
|
print$b$or$w: procedure;
|
|
if w$bit then call printm (.('WORD $'));
|
|
else call printm (.('BYTE $'));
|
|
end print$b$or$w;
|
|
|
|
print$reg: procedure (reg$add, reg);
|
|
declare reg$add address, reg byte;
|
|
table$ptr = reg$add + shl (reg, 1);
|
|
call conout (table$char);
|
|
table$ptr = table$ptr + 1;
|
|
call conout (table$char);
|
|
end print$reg;
|
|
|
|
print$reg8: procedure (reg);
|
|
declare reg byte;
|
|
call print$reg (.reg8, reg);
|
|
end print$reg8;
|
|
|
|
print$reg16: procedure (reg);
|
|
declare reg byte;
|
|
call print$reg (.reg16, reg);
|
|
end print$reg16;
|
|
|
|
print$reg$8$or$16: procedure (reg$num);
|
|
declare reg$num byte;
|
|
if w$bit then call print$reg$16 (reg$num);
|
|
else call print$reg$8 (reg$num);
|
|
end print$reg$8$or$16;
|
|
|
|
print$2$reg$16: procedure (r1, r2);
|
|
declare (r1, r2) byte;
|
|
call print$reg$16 (r1);
|
|
call conout ('+');
|
|
call print$reg$16 (r2);
|
|
end print$2$reg$16;
|
|
|
|
print$A$reg: procedure;
|
|
if w$bit then call print$reg$16 (ax$reg);
|
|
else call print$reg$8 (al$reg);
|
|
end print$A$reg;
|
|
|
|
print$seg$reg: procedure (reg);
|
|
declare reg byte;
|
|
call print$reg (.seg$reg, reg);
|
|
end print$seg$reg;
|
|
|
|
print$data$8: procedure;
|
|
call print$byte (disem$byte (0));
|
|
disem$offset = disem$offset + 1;
|
|
end print$data$8;
|
|
|
|
print$data$16: procedure;
|
|
call print$word (disem$word (0));
|
|
disem$offset = disem$offset + 2;
|
|
end print$data$16;
|
|
|
|
print$data$8$or$16: procedure;
|
|
if w$bit then call print$data$16;
|
|
else call print$data$8;
|
|
end print$data$8$or$16;
|
|
|
|
print$data$sw: procedure;
|
|
if rol (disem$byte (0), 1) then call print$word (0ff00h or disem$byte (0));
|
|
else call print$word (disem$byte (0));
|
|
disem$offset = disem$offset + 1;
|
|
end print$data$sw;
|
|
|
|
print$signed$8: procedure;
|
|
declare a address;
|
|
a = disem$byte (0);
|
|
if low (a) >= 80h then a = a or 0ff00h; /* sign extend to 16 bits */
|
|
call print$word (disem$offset + a + 1);
|
|
disem$offset = disem$offset + 1;
|
|
end print$signed$8;
|
|
|
|
print$signed$16: procedure;
|
|
call print$word (disem$offset + disem$word (0) + 2);
|
|
disem$offset = disem$offset + 2;
|
|
end print$signed$16;
|
|
|
|
print$direct$addr: procedure;
|
|
call conout (left$bracket);
|
|
call print$word (disem$word (0));
|
|
call conout (right$bracket);
|
|
disem$offset = disem$offset + 2;
|
|
end print$direct$addr;
|
|
|
|
print$mod$rm: procedure;
|
|
disem$offset = disem$offset + 1; /* point past mod/reg/rm byte */
|
|
if mod$bits = 3 then
|
|
do;
|
|
call print$reg$8$or$16 (rm$bits);
|
|
return;
|
|
end;
|
|
if b$or$w$flag then call print$b$or$w;
|
|
if rm$bits = 6 and mod$bits = 0 then
|
|
do;
|
|
call print$direct$addr;
|
|
return;
|
|
end;
|
|
if mod$bits = 1 then
|
|
do;
|
|
if (rm$bits <> 6) or (disem$byte (0) <> 0)
|
|
then call print$byte (disem$byte (0));
|
|
disem$offset = disem$offset + 1;
|
|
end;
|
|
else if mod$bits = 2 then
|
|
do;
|
|
call print$word (disem$word (0));
|
|
disem$offset = disem$offset + 2;
|
|
end;
|
|
call conout (left$bracket);
|
|
do case rm$bits;
|
|
call print$2$reg$16 (3, 6);
|
|
call print$2$reg$16 (3, 7);
|
|
call print$2$reg$16 (5, 6);
|
|
call print$2$reg$16 (5, 7);
|
|
call print$reg$16 (6);
|
|
call print$reg$16 (7);
|
|
call print$reg$16 (5);
|
|
call print$reg$16 (3);
|
|
end;
|
|
call conout (right$bracket);
|
|
end print$mod$rm;
|
|
|
|
print$mod$reg$rm: procedure;
|
|
if d$bit then
|
|
do;
|
|
call print$reg$8$or$16 (reg$bits);
|
|
call conout (',');
|
|
call print$mod$rm;
|
|
end;
|
|
else
|
|
do;
|
|
call print$mod$rm;
|
|
call conout (',');
|
|
call print$reg$8$or$16 (reg$bits);
|
|
end;
|
|
end print$mod$reg$rm;
|
|
|
|
print$mnemonic: procedure;
|
|
declare (len, i) byte;
|
|
len = 2;
|
|
do while mnemonic$index >= opn$in (len - 1);
|
|
len = len + 1;
|
|
end;
|
|
table$ptr = tab$ptrs (len - 2) + (mnemonic$index - opn$in (len - 2))
|
|
* len;
|
|
do i = 1 to 7;
|
|
if i <= len then
|
|
do;
|
|
call conout (table$char);
|
|
table$ptr = table$ptr + 1;
|
|
end;
|
|
else call conout (' ');
|
|
end;
|
|
disem$offset = disem$offset + 1;
|
|
end print$mnemonic;
|
|
|
|
type1: procedure;
|
|
call print$mnemonic;
|
|
end type1;
|
|
|
|
type2: procedure;
|
|
if disem$byte (1) = 0ah then
|
|
do;
|
|
call print$mnemonic;
|
|
disem$offset = disem$offset + 1;
|
|
end;
|
|
else error$flag = true;
|
|
end type2;
|
|
|
|
type3: procedure;
|
|
call print$mnemonic;
|
|
call print$reg$16 (byte1$reg$bits);
|
|
end type3;
|
|
|
|
type4: procedure;
|
|
declare temp byte;
|
|
temp = shr (disem$byte (0), 3) and 3;
|
|
call print$mnemonic;
|
|
call print$segreg (temp);
|
|
end type4;
|
|
|
|
type5: procedure;
|
|
call print$mnemonic;
|
|
call print$signed$8;
|
|
end type5;
|
|
|
|
type6: procedure;
|
|
call print$mnemonic;
|
|
call print$signed$16;
|
|
end type6;
|
|
|
|
type8: procedure; /* 7, 9 */
|
|
call print$mnemonic;
|
|
call print$mod$rm;
|
|
end type8;
|
|
|
|
type10: procedure;
|
|
call print$mnemonic;
|
|
call print$data$8;
|
|
end type10;
|
|
|
|
type11: procedure;
|
|
call print$mnemonic;
|
|
call print$data$16;
|
|
end type11;
|
|
|
|
type12: procedure;
|
|
call print$mnemonic;
|
|
call conout ('3');
|
|
end type12;
|
|
|
|
type13: procedure;
|
|
declare temp address;
|
|
call print$mnemonic;
|
|
temp = disem$word (0);
|
|
disem$offset = disem$offset + 2;
|
|
call print$data$16;
|
|
call conout (':');
|
|
call print$word (temp);
|
|
end type13;
|
|
|
|
type14: procedure; /* 15, 16, 17 */
|
|
call print$mnemonic;
|
|
call print$mod$reg$rm;
|
|
end type14;
|
|
|
|
type18: procedure; /* 19, 20, 21 */
|
|
call print$mnemonic;
|
|
if d$bit then
|
|
do;
|
|
call print$direct$addr;
|
|
call comma;
|
|
call print$A$reg;
|
|
end;
|
|
else
|
|
do;
|
|
call print$A$reg;
|
|
call comma;
|
|
call print$direct$addr;
|
|
end;
|
|
end type18;
|
|
|
|
type22: procedure;
|
|
call print$mnemonic;
|
|
if d$bit then
|
|
do;
|
|
call print$data$8;
|
|
call comma;
|
|
call print$A$reg;
|
|
end;
|
|
else
|
|
do;
|
|
call print$A$reg;
|
|
call comma;
|
|
call print$data$8;
|
|
end;
|
|
end type22;
|
|
|
|
type23: procedure; /* 24 */
|
|
call print$mnemonic;
|
|
call print$A$reg;
|
|
call comma;
|
|
call print$data$8$or$16;
|
|
end type23;
|
|
|
|
type25: procedure; /* 26 */
|
|
call print$mnemonic;
|
|
if d$bit then
|
|
do;
|
|
call print$reg$16 (dx$reg);
|
|
call comma;
|
|
call print$A$reg;
|
|
end;
|
|
else
|
|
do;
|
|
call print$A$reg;
|
|
call comma;
|
|
call print$reg$16 (dx$reg);
|
|
end;
|
|
end type25;
|
|
|
|
type27: procedure; /* 28, 29, 30 */
|
|
call print$mnemonic;
|
|
b$or$w$flag = true;
|
|
call print$mod$rm;
|
|
call comma;
|
|
if v$bit then call print$reg$8 (cl$reg);
|
|
else call conout ('1');
|
|
end type27;
|
|
|
|
type31: procedure; /* 32 */
|
|
call setbits;
|
|
reg$bits = byte1$reg$bits;
|
|
w$bit = shr (disem$byte (0), 3) and 1;
|
|
call print$mnemonic;
|
|
call print$reg$8$or$16 (reg$bits);
|
|
call comma;
|
|
call print$data$8$or$16;
|
|
end type31;
|
|
|
|
type33: procedure;
|
|
call print$mnemonic;
|
|
call print$reg$16 (ax$reg);
|
|
call comma;
|
|
call print$reg$16 (byte1$reg$bits);
|
|
end type33;
|
|
|
|
type34: procedure; /* 35 */
|
|
call print$mnemonic;
|
|
b$or$w$flag = true;
|
|
call print$mod$rm;
|
|
call comma;
|
|
call print$data$8$or$16;
|
|
end type34;
|
|
|
|
type36: procedure; /* 37 */
|
|
w$bit = true; /* force 16 bit reg, mem */
|
|
if reg$bits > 3 then
|
|
do;
|
|
error$flag = true;
|
|
return;
|
|
end;
|
|
call print$mnemonic;
|
|
if d$bit then
|
|
do;
|
|
call print$seg$reg (reg$bits);
|
|
call comma;
|
|
call print$mod$rm;
|
|
end;
|
|
else
|
|
do;
|
|
call print$mod$rm;
|
|
call comma;
|
|
call print$seg$reg (reg$bits);
|
|
end;
|
|
end type36;
|
|
|
|
type38: procedure;
|
|
call print$mnemonic;
|
|
call print$mod$rm;
|
|
call comma;
|
|
call print$data$8;
|
|
end type38;
|
|
|
|
type39: procedure;
|
|
if mod$bits = 3 then
|
|
do;
|
|
error$flag = true;
|
|
return;
|
|
end;
|
|
call print$mnemonic;
|
|
call print$reg$16 (reg$bits);
|
|
call comma;
|
|
call print$mod$rm;
|
|
end type39;
|
|
|
|
type40: procedure; /* 41 */
|
|
if mod$bits = 3 then
|
|
do;
|
|
error$flag = true;
|
|
return;
|
|
end;
|
|
call print$mnemonic;
|
|
b$or$w$flag = true;
|
|
call print$mod$rm;
|
|
call comma;
|
|
call print$data$8$or$16;
|
|
end type40;
|
|
|
|
type42: procedure;
|
|
call print$mnemonic;
|
|
call print$byte (shl (byte1$reg$bits, 3) or reg$bits);
|
|
call comma;
|
|
call print$mod$rm;
|
|
end type42;
|
|
|
|
type44: procedure;
|
|
call print$mnemonic;
|
|
b$or$w$flag = true;
|
|
call print$modrm;
|
|
call comma;
|
|
if s$bit = 1 and w$bit = 1 then call print$data$sw;
|
|
else call print$data$8$or$16;
|
|
end type44;
|
|
|
|
type45: procedure;
|
|
b$or$w$flag = true;
|
|
call type8;
|
|
end type45;
|
|
|
|
dis: procedure;
|
|
error$flag, b$or$w$flag = false;
|
|
call set$bits;
|
|
if instr$type = 26 then
|
|
do;
|
|
alt$table$base = alt$table$ptrs (mnemonic$index);
|
|
mnemonic$index = alt$table (reg$bits * 2);
|
|
instr$type = alt$table (reg$bits * 2 + 1);
|
|
end;
|
|
if instr$type > 28 then error$flag = true;
|
|
else
|
|
do case instr$type;
|
|
error$flag = true;
|
|
call type1;
|
|
call type2;
|
|
call type3;
|
|
call type4;
|
|
call type5;
|
|
call type6;
|
|
call type8;
|
|
call type10;
|
|
call type11;
|
|
call type12;
|
|
call type13;
|
|
call type14;
|
|
call type18;
|
|
call type22;
|
|
call type23;
|
|
call type25;
|
|
call type27;
|
|
call type31;
|
|
call type33;
|
|
call type34;
|
|
call type36;
|
|
call type38;
|
|
call type39;
|
|
call type40;
|
|
call type42;
|
|
;
|
|
call type44;
|
|
call type45;
|
|
end;
|
|
if error$flag then call error;
|
|
end dis;
|
|
|
|
disem: procedure (disloc) address public;
|
|
declare disloc pointer;
|
|
declare nprefix byte;
|
|
disem$ptr = disloc;
|
|
nprefix = 0;
|
|
do while true;
|
|
mnemonic$index = instr$table (disem$byte (0) * 2);
|
|
instr$type = instr$table (disem$byte (0) * 2 + 1);
|
|
if instr$type = 0ffh and nprefix < 3 then
|
|
do;
|
|
call print$mnemonic;
|
|
nprefix = nprefix + 1;
|
|
end;
|
|
else
|
|
do;
|
|
if instr$type = 0ffh then instr$type = 1;
|
|
call dis;
|
|
return disem$offset;
|
|
end;
|
|
end;
|
|
end disem;
|
|
|
|
end disem86;
|