Initial commit

This commit is contained in:
CrazyEttin 2022-07-23 23:05:32 +03:00
commit 75123a629a
4 changed files with 332 additions and 0 deletions

105
disassembler.pas Normal file
View File

@ -0,0 +1,105 @@
program Disassembler;
uses Crt, Sysutils;
var
Op, Regs: 0 .. $f; //Opcode
X, Y: 0 .. 3; //Register arguments
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 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.

146
emulator.pas Normal file
View File

@ -0,0 +1,146 @@
program Emulator;
uses Crt;
const
IO = $ffff;
var
Halt: boolean; //Halt flag
Op: 0 .. $f; //Opcode
X, Y: 0 .. 3; //Register arguments
Addr, IP, RP: word; //Address argument and instruction and return pointers
R: array [0 .. 3] of byte; //General-purpose registers
Mem: array [0 .. $ffef] of byte; //Memory
Prog: file of byte; //Program file
Ch: ansichar; //Character for input and output
begin
//Initialise the halt flag and the pointers
Halt := false;
IP := 0;
RP := $fff0;
//Read a program file and check for errors
if ParamCount <> 1 then begin
writeln ('Usage: emulator program');
exit;
end;
{$i-}
assign (Prog, ParamStr (1));
reset (Prog);
{$i+}
if IOResult <> 0 then begin
writeln ('Usage: emulator program');
exit;
end;
repeat
read (Prog, Mem [IP]);
IP := IP + 1;
until (eof (Prog)) or (IP = $fff0);
//Reinitialise the instruction pointer
IP := 0;
//Begin the main loop
while (Halt = false) do begin
//Fetch the instruction and increment the instruction pointer
//Opcode
Op := Mem [IP] and $f0 shr 4;
//Register arguments
X := Mem [IP] and $c shr 2;
Y := Mem [IP] and 3;
IP := IP + 1;
if IP > $ffef then break;
//Address argument
if Op >= $a then begin
Addr := Mem [IP];
Addr := Addr shl 8;
IP := IP + 1;
if IP > $ffef then break;
Addr := Addr + Mem [IP];
IP := IP + 1;
if IP > $ffef then break;
end;
//Decode and execute the instruction
//Halt
if Op = 0 then Halt := true
//Ret
else if Op = 1 then begin
IP := Mem [RP];
RP := RP + 1;
if RP > $fff0 then break;
end
//Shl
else if Op = 2 then R [X] := R [X] shl 1
//Shr
else if Op = 3 then R [X] := R [X] shr 1
//Rol
else if Op = 4 then R [X] := RolByte (R [X])
//Ror
else if Op = 5 then R [X] := RorByte (R [X])
//Nand
else if Op = 6 then R [X] := not (R [X] and R [Y])
//And
else if Op = 7 then R [X] := R [X] and R [Y]
//Or
else if Op = 8 then R [X] := R [X] or R [Y]
//Xor
else if Op = 9 then R [X] := R [X] xor R [Y]
//Load
else if Op = $a then begin
//Input
if Addr = IO then begin
Ch := ReadKey;
write (Ch);
R [X] := byte (Ch);
end
//Regular load
else R [X] := Mem [Addr];
end
//Store
else if Op = $b then begin
//Output
if Addr = IO then begin
Ch := ansichar (R [X]);
write (Ch);
end
//Regular store
else Mem [Addr] := R [X];
end
//Breq
else if Op = $c then begin
if R [X] = R [Y] then IP := Addr;
end
//Brneq
else if Op = $d then begin
if R [X] <> R [Y] then IP := Addr;
end
//Cleq
else if Op = $e then begin
if R [X] = R [Y] then begin
RP := RP - 1;
if RP > $fff0 then break;
Mem [RP] := IP;
IP := Addr;
if IP > $ffef then break;
end;
end
//Clneq
else if Op = $f then begin
if R [X] <> R [Y] then begin
RP := RP - 1;
if RP > $fff0 then break;
Mem [RP] := IP;
IP := Addr;
if IP > $ffef then break;
end;
end;
//End the main loop
end
end.

23
license.md Normal file
View File

@ -0,0 +1,23 @@
MIT License
===========
Copyright (c) 2022
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

58
readme.md Normal file
View File

@ -0,0 +1,58 @@
Thingamajig
===========
Thingamajig is a RISC-y and MISC-y hobbyist instruction set
architecture. Its git repository can be found at
https://ahti.space/git/crazyettin/Thingamajig.
Registers and Memory
--------------------
* 24-bit instruction register IR
* 16-bit instruction and return pointers IP and RP
* 8-bit general-purpose registers R0-R3
* 8-bit memory addresses 0-FFFF
Multi-byte values are big-endian. Memory addresses FFF0-FFFF are
reserved for memory mapped devices. The instruction and return pointers
should not have values higher than FFEF and FFF0 respectively to avoid
the reserved addresses. The instruction and return pointers are
initialised as 0 and FFF0 respectively; other registers and memory are
unitialised.
Memory-Mapped Devices
---------------------
Input (when read from) and output (when written to) are mapped to
address FFFF. Arbitrary devices can be mapped to the other reserved
addresses.
Instructions
------------
Instructions without an address argument are 8-bit and those with one
24-bit. The instruction pointer is incremented before being accessed or
modified.
0 HALT
1 RET IP = *RP; RP += 1
2 SHL RX RX <<= 1 Logical shifts
3 SHR RX RX >>= 1
4 ROL RX RX <<= 1 Rotating shifts
5 ROR RX RX >>= 1
6 NAND RX, RY RX = ~(RX & RY)
7 AND RX, RY RX &= RY
8 OR RX, RY RX |= RY
9 XOR RX, RY RX ^= RY
A LOAD RX, ADDR RX = *ADDR
B STORE RX, ADDR *ADDR = RX Written as "STORE ADDR, RX" in
assembly for the sake of
consistency.
C BREQ RX, RY, ADDR if (RX == RY) IP = ADDR
D BRNEQ RX, RY, ADDR if (RX != RY) IP = ADDR
E CLEQ RX, RY, ADDR if (RX == RY) {RP -= 1; *RP = IP; IP = ADDR}
F CLNEQ RX, RY, ADDR if (RX != RY) {RP -= 1; *RP = IP; IP = ADDR}