Thingamajig/disassembler.pas

106 lines
2.8 KiB
Plaintext

program Disassembler;
uses Crt, Sysutils;
var
Op, Regs: 0 .. $f; //Opcode, and register arguments in a single variable
X, Y: 0 .. 3; //Register arguments in separate variables
Addr, IP, EP: word; //Address argument and instruction and end pointers
Opcodes: array [0 .. $f] of string; //Opcodes in human readable form
Bin: array [0 .. $ffef] of byte; //Program in binary form
Prog: file of byte; //Program file
begin
//Populate the opcode array
Opcodes [0] := 'HALT ';
Opcodes [1] := 'RET ';
Opcodes [2] := 'SHL ';
Opcodes [3] := 'SHR ';
Opcodes [4] := 'ROL ';
Opcodes [5] := 'ROR ';
Opcodes [6] := 'NAND ';
Opcodes [7] := 'AND ';
Opcodes [8] := 'OR ';
Opcodes [9] := 'XOR ';
Opcodes [$a] := 'LOAD ';
Opcodes [$b] := 'STORE ';
Opcodes [$c] := 'BREQ ';
Opcodes [$d] := 'BRNEQ ';
Opcodes [$e] := 'CLEQ ';
Opcodes [$f] := 'CLNEQ ';
//Initialise the instruction pointer
IP := 0;
//Read a program file and check for errors
if ParamCount <> 1 then begin
writeln ('Usage: disassembler program');
exit;
end;
{$i-}
assign (Prog, ParamStr (1));
reset (Prog);
{$i+}
if IOResult <> 0 then begin
writeln ('Usage: disassembler program');
exit;
end;
repeat
read (Prog, Bin [IP]);
IP := IP + 1;
until (eof (Prog)) or (IP = $fff0);
//Save the end point and reinitialise the instruction pointer
EP := IP;
IP := 0;
//Begin the main loop
repeat
//Print the memory location
if IP < $1000 then write (' ');
if IP < $100 then write (' ');
if IP < $10 then write (' ');
write (IntToHex (IP, 1), ' ');
//Fetch the instruction and increment the instruction pointer
//Opcode
Op := Bin [IP] and $f0 shr 4;
//Register arguments
Regs := Bin [IP] and $f;
X := Bin [IP] and $c shr 2;
Y := Bin [IP] and 3;
IP := IP + 1;
//Address argument
if Op >= $a then begin
Addr := Bin [IP];
Addr := Addr shl 8;
IP := IP + 1;
Addr := Addr + Bin [IP];
IP := IP - 1;
end;
//Print the data
write (IntToHex (Op, 1), IntToHex (Regs, 1));
if Op >= $a then write (IntToHex (Addr, 4)) else write (' ');
write (' ');
//Print the instruction
write (Opcodes [Op]);
if Op = $b then writeln (IntToHex (Addr, 1), ', R', X)
else begin
if Op >= 2 then if Op <> $b then write ('R', X);
if Op >= 6 then if Op <= 9 then write (', R', Y);
if OP >= $c then write (', R', Y);
if Op >= $a then write (', ', IntToHex (Addr, 1));
writeln ();
end;
until (IP >= EP);
end.