Skip to content

Instantly share code, notes, and snippets.

@balt-dev
Last active November 19, 2024 21:43
Show Gist options
  • Save balt-dev/7ac814b676e758a8d52efd9fae34674c to your computer and use it in GitHub Desktop.
Save balt-dev/7ac814b676e758a8d52efd9fae34674c to your computer and use it in GitHub Desktop.
twiddle - a fantasty 16-bit microprocessor

twiddle - a fantasty 16-bit microprocessor

8 bits in a byte, 2 bytes in a word.

Registers

All registers are 16-bit little-endian. There are 8 registers, being X, Y, Z, O, A, S, P, and C.

X, Y, and Z are general purpose, O is used as an offset in addressing, A is used for math, S is used as a hardware stack pointer (grows down), P is used as a bitfield for things like ADD and CHK (although bits 3 through 14 are left untouched by either, as to be usable by user code), and C is the index of the currently executed instruction.

The lowest bit of S is tied low, meaning that it is physically impossible for it to not lie on a two-byte boundary. If so inclined, STAC can be treated as having 16-bit bytes.

There's also a special register, CLIP, that can only be accessed via CPY, PST, CPA, and PSA.

Memory is split into three sections, being EXEC, HEAP, and STAC. Instruction decoding reads from EXEC, PSH and POP read from the STAC, and everything else uses HEAP.

Instruction Set

Each instruction is 8 bits, with the latter half being taken by an argument.

INT: 0000

Sends an interrupt to the connected interrupt handler. This reads the argument as a 4-bit integer.

CHK: 0001

Sets bit 0 of P if read value is zero. Sets bit 15 of P if read value bit 15 is set.

PSH: 0010

Pushes the value to the stack.

POP: 0011

Pops the value from the stack.

AND: 0100

Performs a bitwise AND with A and the given value.

IOR: 0101

Performs a bitwise OR with A and the given value.

NOT: 0110

Performs a bitwise NOT on the given value.

XOR: 0111

Performs a bitwise XOR with A and the given value.

ADD: 1000

Adds A and the given value. Sets bit 1 of P if unsigned overflow, sets bit 2 of P if signed overflow.

NEG: 1001

Negates the given value. Sets bit 2 of P if signed overflow.

IFC: 1010

Executes the following instruction if all bits set in the value are clear in P.

IFS: 1011

Executes the following instruction if all bits set in the value are set in P.

CPY: 1100

Stores the value to a special "clipboard" register.

PST: 1101

Stores the value of the "clipboard" register to the given value.

CPA: 1110

Stores the byte at the given address into the "clipboard" register's low byte.

PSA: 1111

Stores the low byte of the "clipboard" register to the given address.

Addressing modes

Registers: 0000 - 0111

Access registers X, Y, Z, O, A, S, P, and C respectively.

Constant: 1000, #

Read the next 2 bytes as the value.

At: 1001, @

Read the next 2 bytes as an address, then read 2 bytes there as the value.

Relative: 1010, ?

Read the next 2 bytes, then return the sum of the value and the current value of the P register, wrapping silently. This is an index into EXEC, which may not behave as expected for instructions expecting something from HEAP.

Relative At: 1010, ?@

Read the next 2 bytes, then at the address of the P register plus those bytes, read 2 bytes, wrapping silently.

Peek: 1100, ^

Read 2 bytes at S. This is an index into STAC, which may not behave as expected for instructions expecting something from HEAP.

Peek At: 1101, ^@

Read 2 bytes at S, then read 2 bytes there.

Relative Offset: 1110, $

Read the next 2 bytes, then return the sum of the value, the current value of register O, and the current value of the P register, wrapping silently. This is an index into EXEC, which may not behave as expected for instructions expecting something from HEAP.

Relative At Offset: 1111, $@

Read the next 2 bytes, then at the address of the P register plus those bytes, return the sum of the value and the current value of register O, wrapping silently.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment