|
|
|
@ -1,108 +1,108 @@
|
|
|
|
|
Thingamajig |
|
|
|
|
=========== |
|
|
|
|
|
|
|
|
|
Thingamajig is a RISC-y and MISC-y homebrew computer architecture. Its |
|
|
|
|
git repository can be found at |
|
|
|
|
https://ahti.space/git/crazyettin/Thingamajig. |
|
|
|
|
|
|
|
|
|
Included Software |
|
|
|
|
----------------- |
|
|
|
|
|
|
|
|
|
The repository includes an emulator implementation of Thingamajig, a |
|
|
|
|
control program for the emulated punched tape reader and punch, and an |
|
|
|
|
assembler and a disassembler, all written in FreePascal. It also |
|
|
|
|
includes couple of simple example programs for Thingamajig written in |
|
|
|
|
Assembly. |
|
|
|
|
|
|
|
|
|
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 locations 0-FFFF |
|
|
|
|
|
|
|
|
|
Multi-byte values are big-endian. Memory addresses FFF0-FFFF are |
|
|
|
|
reserved for memory mapped devices; the instruction and return pointers |
|
|
|
|
cannot have values higher than FFEF and FFF0 respectively to avoid them. |
|
|
|
|
The instruction and return pointers are initialised as 0 and FFF0 |
|
|
|
|
respectively, while other registers and memory are unitialised. |
|
|
|
|
|
|
|
|
|
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 += 2 |
|
|
|
|
|
|
|
|
|
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 -= 2; *RP = IP; IP = ADDR} |
|
|
|
|
F CLNEQ RX, RY, ADDR if (RX != RY) {RP -= 2; *RP = IP; IP = ADDR} |
|
|
|
|
|
|
|
|
|
Assembly Language |
|
|
|
|
----------------- |
|
|
|
|
|
|
|
|
|
Lines of assembly are of the following form: |
|
|
|
|
|
|
|
|
|
LABEL: OPER ARG1, ARG2, ARG3 ;Comment |
|
|
|
|
|
|
|
|
|
The language is case-insensitive and uses hexadecimal numbers. A label |
|
|
|
|
can consist of any alphanumeric characters as long as it is not |
|
|
|
|
interpretable as a hexadecimal number. The label, instruction, and |
|
|
|
|
comment elements are all optional, as is spacing between the arguments. |
|
|
|
|
For the arguments of each instruction see the previous section. |
|
|
|
|
|
|
|
|
|
Address arguments can be either absolute addresses or references to or |
|
|
|
|
relative to a label. Relative references are of the form LABEL +/- N, |
|
|
|
|
the spacing being optional. Note that the assembler does not check for |
|
|
|
|
addresses or references to reserved addresses. |
|
|
|
|
|
|
|
|
|
In addition to the true instructions there are three |
|
|
|
|
pseudo-instructions. ORG defines the starting address of the program: it |
|
|
|
|
can only occur as the first instruction and cannot have a label, and is |
|
|
|
|
not required if the starting address is 0. DATA introduces a byte of |
|
|
|
|
data. ADDR introduces two bytes of data containing the address of a |
|
|
|
|
reference to or relative to a label. |
|
|
|
|
|
|
|
|
|
Memory-Mapped Devices |
|
|
|
|
--------------------- |
|
|
|
|
|
|
|
|
|
Input (when read from) and output (when written to) are mapped to |
|
|
|
|
address FFFF. The emulator emulates a dumb terminal with local echo for |
|
|
|
|
this. |
|
|
|
|
|
|
|
|
|
Arbitrary devices can be mapped to the other reserved addresses. |
|
|
|
|
|
|
|
|
|
In Linux the emulator can be compiled with support for a line printer |
|
|
|
|
and an emulated punched tape reader and punch with the arguments |
|
|
|
|
-dprinter and -dtape respectively. The printer prints into /dev/usb/lp0 |
|
|
|
|
and the tape files read from and punched to are (re)set using the |
|
|
|
|
settape program. The printer is mapped to address FFFE in the emulator |
|
|
|
|
and the tape reader and punch to FFFD. If you wish to use a different |
|
|
|
|
setup you have to modify the code yourself. |
|
|
|
|
|
|
|
|
|
Initial Program Loader |
|
|
|
|
---------------------- |
|
|
|
|
|
|
|
|
|
At boot the initial program loader loads a program to the memory |
|
|
|
|
starting from address 0 after which is cedes control to the CPU. The |
|
|
|
|
emulator loads the program from a file. |
|
|
|
|
Thingamajig |
|
|
|
|
=========== |
|
|
|
|
|
|
|
|
|
Thingamajig is a RISC-y and MISC-y homebrew computer architecture. Its |
|
|
|
|
git repository can be found at |
|
|
|
|
https://ahti.space/git/crazyettin/Thingamajig. |
|
|
|
|
|
|
|
|
|
Included Software |
|
|
|
|
----------------- |
|
|
|
|
|
|
|
|
|
The repository includes an emulator implementation of Thingamajig, a |
|
|
|
|
control program for the emulated punched tape reader and punch, and an |
|
|
|
|
assembler and a disassembler, all written in FreePascal. It also |
|
|
|
|
includes couple of simple example programs for Thingamajig written in |
|
|
|
|
Assembly. |
|
|
|
|
|
|
|
|
|
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 locations 0-FFFF |
|
|
|
|
|
|
|
|
|
Multi-byte values are big-endian. Memory addresses FFF0-FFFF are |
|
|
|
|
reserved for memory mapped devices; the instruction and return pointers |
|
|
|
|
cannot have values higher than FFEF and FFF0 respectively to avoid them. |
|
|
|
|
The instruction and return pointers are initialised as 0 and FFF0 |
|
|
|
|
respectively, while other registers and memory are unitialised. |
|
|
|
|
|
|
|
|
|
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 += 2 |
|
|
|
|
|
|
|
|
|
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 -= 2; *RP = IP; IP = ADDR} |
|
|
|
|
F CLNEQ RX, RY, ADDR if (RX != RY) {RP -= 2; *RP = IP; IP = ADDR} |
|
|
|
|
|
|
|
|
|
Assembly Language |
|
|
|
|
----------------- |
|
|
|
|
|
|
|
|
|
Lines of assembly are of the following form: |
|
|
|
|
|
|
|
|
|
LABEL: OPER ARG1, ARG2, ARG3 ;Comment |
|
|
|
|
|
|
|
|
|
The language is case-insensitive and uses hexadecimal numbers. A label |
|
|
|
|
can consist of any alphanumeric characters as long as it is not |
|
|
|
|
interpretable as a hexadecimal number. The label, instruction, and |
|
|
|
|
comment elements are all optional, as is spacing between the arguments. |
|
|
|
|
For the arguments of each instruction see the previous section. |
|
|
|
|
|
|
|
|
|
Address arguments can be either absolute addresses or references to or |
|
|
|
|
relative to a label. Relative references are of the form LABEL +/- N, |
|
|
|
|
the spacing being optional. Note that the assembler does not check for |
|
|
|
|
addresses or references to reserved addresses. |
|
|
|
|
|
|
|
|
|
In addition to the true instructions there are three |
|
|
|
|
pseudo-instructions. ORG defines the starting address of the program: it |
|
|
|
|
can only occur as the first instruction and cannot have a label, and is |
|
|
|
|
not required if the starting address is 0. DATA introduces a byte of |
|
|
|
|
data. ADDR introduces two bytes of data containing the address of a |
|
|
|
|
reference to or relative to a label. |
|
|
|
|
|
|
|
|
|
Memory-Mapped Devices |
|
|
|
|
--------------------- |
|
|
|
|
|
|
|
|
|
Input (when read from) and output (when written to) are mapped to |
|
|
|
|
address FFFF. The emulator emulates a dumb terminal with local echo. |
|
|
|
|
|
|
|
|
|
Arbitrary devices can be mapped to the other reserved addresses. |
|
|
|
|
|
|
|
|
|
In Linux the emulator can be compiled with support for a line printer |
|
|
|
|
and an emulated punched tape reader and punch with the arguments |
|
|
|
|
-dprinter and -dtape respectively. The printer is mapped to address FFFE |
|
|
|
|
and the tape reader and punch to FFFD. The printer prints into |
|
|
|
|
/dev/usb/lp0 and the tape files read from and punched to are (re)set |
|
|
|
|
using the settape program. If you wish to use a different setup you have |
|
|
|
|
to modify the code yourself. |
|
|
|
|
|
|
|
|
|
Initial Program Loader |
|
|
|
|
---------------------- |
|
|
|
|
|
|
|
|
|
At boot the initial program loader loads a program to the memory |
|
|
|
|
starting from address 0 after which is cedes control to the CPU. The |
|
|
|
|
emulator loads the program from a file. |
|
|
|
|
|