|
|
|
|
Thingamajig v2.0
|
|
|
|
|
================
|
|
|
|
|
|
|
|
|
|
Thingamajig v2.0 is a RISC/MISC 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 with
|
|
|
|
|
device control programs, 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 locations 0-FFEF are used for
|
|
|
|
|
RAM while FFF0-FFFF are reserved for memory mapped devices.
|
|
|
|
|
|
|
|
|
|
Input and output are mapped to address FFFF, while arbitrary devices can
|
|
|
|
|
be mapped to the other reserved addresses. When interacting with memory
|
|
|
|
|
mapped devices Thingamajig will stop processing to wait for the device
|
|
|
|
|
to be ready if needed.
|
|
|
|
|
|
|
|
|
|
Instructions
|
|
|
|
|
------------
|
|
|
|
|
|
|
|
|
|
Instructions without an immediate or address argument are 8-bit, those
|
|
|
|
|
with an immediate one 16-bit, and those with an address one 24-bit. The
|
|
|
|
|
instruction pointer is incremented before being accessed or modified.
|
|
|
|
|
|
|
|
|
|
0 HALT
|
|
|
|
|
1 RET IP = *RP; RP += 2
|
|
|
|
|
|
|
|
|
|
2 SHL RX, N RX <<= N (logical) Shifts of 1-4 steps,
|
|
|
|
|
3 SHR RX, N RX >>= N (logical) with 4 encoded as 0
|
|
|
|
|
4 ROL RX, N RX <<= N (rotating) in machine code.
|
|
|
|
|
5 ROR RX, N RX >>= N (rotating)
|
|
|
|
|
|
|
|
|
|
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, ~0, IMM RX = IMM Written as "LOAD RX, #IMM"
|
|
|
|
|
0, ADDR RX = *ADDR Written as "LOAD RX, ADDR"
|
|
|
|
|
B STORE RY, ADDR *ADDR = RY Written as "STORE ADDR, RY"
|
|
|
|
|
|
|
|
|
|
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 is optional.
|
|
|
|
|
|
|
|
|
|
In addition to the true instructions there are three
|
|
|
|
|
pseudo-instructions. ORG sets the location of the following code and
|
|
|
|
|
data; as it has no direct equivalent in machine code it cannot have a
|
|
|
|
|
label. The default starting address of 0 does not need to be indicated
|
|
|
|
|
with ORG. DATA introduces a byte of data. ADDR introduces two bytes of
|
|
|
|
|
data containing the address of a reference to or relative to a label.
|
|
|
|
|
|
|
|
|
|
Boot
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
At boot the initial program loader (IPL) loads a program to RAM starting
|
|
|
|
|
at address 0 after which is cedes control to the CPU. If an
|
|
|
|
|
implementation has a front panel the IPL is optional. The instruction
|
|
|
|
|
and return pointers are initialised as 0 and the first address after RAM
|
|
|
|
|
respectively, while other registers and RAM are uninitialised.
|
|
|
|
|
|
|
|
|
|
Emulator and Device Control Programs
|
|
|
|
|
------------------------------------
|
|
|
|
|
|
|
|
|
|
Usage:
|
|
|
|
|
* emulator (-v) program (2> verbose_output)
|
|
|
|
|
* tapectl (-r tape) (-p tape)
|
|
|
|
|
* floppyctl (-0 disc) (-1 disc)
|
|
|
|
|
* modemctl -o/[-a address:port]/[-d address:port]/-h
|
|
|
|
|
|
|
|
|
|
By default the emulator runs at roughly 500 KIPS and has 2 KiB of RAM.
|
|
|
|
|
The arguments -dRAM4, -dRAM8, -dRAM16, -dRAM32, and -dRAM64 can be used
|
|
|
|
|
to compile the emulator with 4, 8, 16, 32, or 64 KiB (minus the reserved
|
|
|
|
|
addresses) of RAM respectively instead and the speed limitations can be
|
|
|
|
|
removed with the argument -dfast. When run with the argument -v the
|
|
|
|
|
current state of the registers is output to stderr before each
|
|
|
|
|
instruction.
|
|
|
|
|
|
|
|
|
|
Input and output are handled by an emulated roughly 1000 CPS
|
|
|
|
|
ASCII-compatible glass teletype terminal with local echo on by default.
|
|
|
|
|
Of the control characters bell (^G), backspace (^H), line feed (^J),
|
|
|
|
|
carriage return (^M), and device control characters two (^R) and four
|
|
|
|
|
(^T) are used by the terminal: the device control characters are used to
|
|
|
|
|
turn the local echo on and off respectively while the rest have their
|
|
|
|
|
standard uses. The backspace and delete keys input their respective
|
|
|
|
|
characters and non-character keys null.
|
|
|
|
|
|
|
|
|
|
In Linux the emulator can be compiled with support for a character
|
|
|
|
|
printer, an emulated high speed 8-bit paper tape reader and punch, an
|
|
|
|
|
emulated two-drive 8" floppy disc system, a modem, and an input status
|
|
|
|
|
register with the arguments -dprinter, -dtape, -dfloppy, -dmodem, and
|
|
|
|
|
-dstatus respectively. Full 64 KiB of RAM and all of these options can
|
|
|
|
|
also be enabled with the argument -dfull. The printer is mapped to
|
|
|
|
|
address FFFE, the tape reader and punch to FFFD, the disc system to FFFB
|
|
|
|
|
and FFFC, the modem to FFF9 and FFFA, and the input status register to
|
|
|
|
|
FFF8.
|
|
|
|
|
|
|
|
|
|
The printer prints into /dev/usb/lp0. The tape files read from and
|
|
|
|
|
punched to are (re)set using the program tapectl with the arguments -r
|
|
|
|
|
and -p respectively and the disc files in drives 0 and 1 using the
|
|
|
|
|
program floppyctl with the arguments -0 and -1 respectively. The disc
|
|
|
|
|
system uses hard sectored single-sided discs with 77 tracks of 32
|
|
|
|
|
sectors of 137 bytes, or 337568 bytes in total: the disc files must be
|
|
|
|
|
of this size. The modem is controlled by the program modemctl: the
|
|
|
|
|
options -o and -a are used to set the originate and answer modes, the
|
|
|
|
|
latter with the address and port to be listened; -d to dial an address
|
|
|
|
|
and port to be called; and -h to hang. Dialing when in answer mode
|
|
|
|
|
automatically switches the modem to originate mode. The modem hangs
|
|
|
|
|
automatically if the connection is lost or hanged from the other side,
|
|
|
|
|
if another address and port are dialed, if a mode change command is
|
|
|
|
|
given, or if the emulator is halted.
|
|
|
|
|
|
|
|
|
|
The floppy disc system uses two ports: command at FFFB and data at FFFC.
|
|
|
|
|
Only the low nibble of the command port is used, consisting of a
|
|
|
|
|
three-bit command followed by a one-bit drive number used as an argument
|
|
|
|
|
by instructions 1 and 4-7. The track or sector to be accessed is input
|
|
|
|
|
to and the buffer accessed sequentially through the data port after the
|
|
|
|
|
relevant command is input to the command port. New commands other than
|
|
|
|
|
resetting the system are ignored until the current command is fully
|
|
|
|
|
executed. Note that each sector begins with a synchronisation bit that
|
|
|
|
|
must always be set.
|
|
|
|
|
|
|
|
|
|
The commands for the disc system are:
|
|
|
|
|
0: Reset the system.
|
|
|
|
|
1: Format a disc.
|
|
|
|
|
2: Read a sector from the buffer to the computer.
|
|
|
|
|
3: Write a sector from the computer to the buffer.
|
|
|
|
|
4: Set the track to be accessed.
|
|
|
|
|
5: Set the sector to be accessed.
|
|
|
|
|
6: Read a sector from a disc to the buffer.
|
|
|
|
|
7: Write a sector from the buffer to a disc.
|
|
|
|
|
|
|
|
|
|
The modem also uses two ports: status at FFF9 and data at FFFA. Only the
|
|
|
|
|
least significant bit of the status port is used, indicating whether
|
|
|
|
|
the modem is connected or not. Unsetting the bit hangs the modem while
|
|
|
|
|
setting it in answer mode hangs any current call and listens for an
|
|
|
|
|
incoming call to answer. Setting the bit in originate mode is ignored.
|
|
|
|
|
|
|
|
|
|
The input status register can be used to check if a device is ready to
|
|
|
|
|
be read from. The reserved addresses FFF8-FFFF are mapped to the bits
|
|
|
|
|
7-0: a set bit means either that the device is ready or that no input
|
|
|
|
|
device is mapped to the address in question.
|
|
|
|
|
|
|
|
|
|
The IPL loads the program specified as an argument when running the
|
|
|
|
|
emulator.
|
|
|
|
|
|
|
|
|
|
Assembler and Disassembler
|
|
|
|
|
--------------------------
|
|
|
|
|
|
|
|
|
|
Usage:
|
|
|
|
|
* assembler program (< input)
|
|
|
|
|
* disassembler program (> output)
|
|
|
|
|
|
|
|
|
|
Both the assembler and the disassembler are run with a program as their
|
|
|
|
|
sole argument: they take their input from and print their output to
|
|
|
|
|
stdin and stdout respectively.
|
|
|
|
|
|
|
|
|
|
An initial gap created with ORG is not included in an assembled program.
|
|
|
|
|
All possible interpretations of a disassembled program are included in
|
|
|
|
|
its listing, resulting in overlapping information.
|
|
|
|
|
|
|
|
|
|
Changelog
|
|
|
|
|
---------
|
|
|
|
|
|
|
|
|
|
v2.0
|
|
|
|
|
* Added the ability to shift a register multiple steps in one
|
|
|
|
|
instruction
|
|
|
|
|
* Changed the register argument of STORE from RX to RY
|
|
|
|
|
* Added support for an emulated floppy disc system and modem and an
|
|
|
|
|
input status register to the emulator
|
|
|
|
|
* Added the ability to use ORG non-initially to the assembler
|
|
|
|
|
* Changed tapectl so that it uses arguments for input
|
|
|
|
|
|
|
|
|
|
v1.0
|
|
|
|
|
* Initial release
|
|
|
|
|
|