Register Operations
This booklet covers the register opcodes 0x100x21, the register-literal arithmetic opcodes 0x2A0x2E, and the dedicated 0x30 7-segment encoder and 0x32 three-register operation: writing literals, copying, incrementing, port transfer, shifting, bitwise logic, register-register and register-literal arithmetic, random numbers, byte composing and swapping.
All registers R00~RFF hold 16-bit values. When a register index travels in a 16-bit whole operand, it is written as 00 followed by the register index — e.g. 001C means register R1C. Operand interpretation modes and the port system table are defined once in Brief.
0x10 Write Register (FZ)
Write an immediate value into a register: R[P01] = P10P11.
- Mnemonic Form
- Instruction Form
000 FZ 001C 03E8
001 JS 0000 0000
000 10 001C 03E8
001 0F 0000 0000
Line 000 writes the value 03E8 (1000 in decimal) into R1C. The result can be checked in real time on the register pages of the secondary display.
| Operands | Value/Range | Remark |
|---|---|---|
| P00 | 00 | Don't care, ignored |
| P01 | 00~FF | Target register index |
| P10P11 | 0000~FFFF | 16-bit whole: immediate value |
0x11 Register Copy (RFZ)
Copy the value of one register into another: R[A] = R[B].
- Mnemonic Form
- Instruction Form
000 RFZ 001D 001C
001 JS 0000 0000
000 11 001D 001C
001 0F 0000 0000
Line 000 copies the value of R1C into R1D; R1C keeps its own value.
| Operands | Value/Range | Remark |
|---|---|---|
| P00 | 00 | Don't care, ignored |
| P01 | 00~FF | Target register A |
| P10 | 00 | Don't care, ignored |
| P11 | 00~FF | Source register B |
0x12 Increment / Decrement (ZJ)
Increase or decrease a register by a 16-bit amount; each instruction also chooses whether overflow is allowed.
- Mnemonic Form
- Instruction Form
000 FZ 001C FF00 R1C = FF00
001 ZJ 001C 03E8 increase R1C by 03E8, overflow NOT allowed
002 JS 0000 0000
000 10 001C FF00 R1C = FF00
001 12 001C 03E8 increase R1C by 03E8, overflow NOT allowed
002 0F 0000 0000
FF00 + 03E8 = 1 02E8, which exceeds the 16-bit range. With overflow not allowed the value is capped at FFFF; with overflow allowed the register simply wraps around to 02E8.
| Operands | Value/Range | Remark |
|---|---|---|
| P00 | 00 | Increase, overflow NOT allowed (capped at FFFF) |
01 | Increase, overflow allowed (wraps around) | |
10 | Decrease, overflow NOT allowed (floored at 0000) | |
11 | Decrease, overflow allowed (wraps around) | |
| P01 | 00~FF | Register index |
| P10P11 | 0000~FFFF | 16-bit whole: amount to add or subtract |
0x13 Send to Port (SS)
Write the whole value of a register to a port (see the port system table):
- Port1 receives the low 8 bits (8 digital IO, the LED network). Writing Port1 first restores the output direction and refreshes the hardware immediately, undoing an input switch made by
0x14QS. - Port2 receives the low 4 bits (4 IO/PWM pins).
- Port4~6 drive the 16 channels of PCA9685 module 0/1/2, one channel per bit.
- Port0 / Port3 are read-only; a write is ignored.
- Mnemonic Form
- Instruction Form
000 FZ 0004 00FF R04 = 00FF
001 SS 0004 0001 Port1 = R04, all 8 LEDs on
002 JS 0000 0000
000 10 0004 00FF R04 = 00FF
001 13 0004 0001 Port1 = R04, all 8 LEDs on
002 0F 0000 0000
| Operands | Value/Range | Remark |
|---|---|---|
| P00 | 00 | Don't care, ignored |
| P01 | 00~7F | Source register index |
| P10 | 00 | Don't care, ignored |
| P11 | 01 | Port1 — 8 digital IO (LED network) |
02 | Port2 — 4 IO/PWM pins | |
04~06 | Port4~6 — PCA9685 modules 0/1/2, 16 channels each | |
00 / 03 | Read-only ports, write ignored |
0x14 Fetch from Port (QS)
Read a whole port into a register; each pin of the port becomes one bit of the value (pin 0 → bit 0):
- Port0 — 7 onboard buttons (bit0~bit6, bit7 = 0).
- Port1 — 8 digital IO. Reading Port1 first switches all 8 pins to input direction with pull-up (the LED network goes high-impedance and can be driven by an external device); a later
0x13SS restores the output direction. - Port2 — 4 IO/PWM pins (bit0~bit3).
- Port3 — 16 ADS1115 channels: bit n = 1 when the millivolt reading of channel n is above 2500.
- Port4~6 are write-only and cannot be read.
- Mnemonic Form
- Instruction Form
000 QS 0001 0000 R01 = Port0 (7 buttons)
001 JS 0000 0000
000 14 0001 0000 R01 = Port0 (7 buttons)
001 0F 0000 0000
| Operands | Value/Range | Remark |
|---|---|---|
| P00 | 00 | Don't care, ignored |
| P01 | 00~7F | Target register index |
| P10 | 00 | Don't care, ignored |
| P11 | 00 | Port0 — 7 onboard buttons |
01 | Port1 — 8 digital IO (switches to input direction first) | |
02 | Port2 — 4 IO/PWM pins | |
03 | Port3 — ADS1115 channels, above 2500 mV = 1 |
0x15 Bit Shift (XHYW)
Shift the bits of a register left or right, circular or not, by 1~15 bit positions.
- Mnemonic Form
- Instruction Form
000 FZ 0007 8009 R07 = 8009
001 XHYW 0007 0002 shift R07 right by 2 bits
002 JS 0000 0000
000 10 0007 8009 R07 = 8009
001 15 0007 0002 shift R07 right by 2 bits
002 0F 0000 0000
Suppose R07 = 8009 = 1000 0000 0000 1001. A plain right shift by 2 drops the two lowest bits and gives 0010 0000 0000 0010 = 2002; in circular mode the two shifted-out bits re-enter from the left and give 0110 0000 0000 0010 = 6002.
| Operands | Value/Range | Remark |
|---|---|---|
| P00 | 00 | Shift right |
01 | Shift right, circular | |
10 | Shift left | |
11 | Shift left, circular | |
| P01 | 00~FF | Register index |
| P10 | 00 | Don't care, ignored |
| P11 | 00~0F | Number of bits to shift (values above 0F are not executed) |
0x16 Bit Inversion (QF)
Invert every bit of a register.
- Mnemonic Form
- Instruction Form
000 FZ 0007 8009 R07 = 8009
001 QF 0007 0000 invert all bits of R07
002 JS 0000 0000
000 10 0007 8009 R07 = 8009
001 16 0007 0000 invert all bits of R07
002 0F 0000 0000
8009 = 1000 0000 0000 1001, inverted bit by bit → 0111 1111 1111 0110 = 7FF6, stored back into R07.
| Operands | Value/Range | Remark |
|---|---|---|
| P00 | 00 | Don't care, ignored |
| P01 | 00~FF | Register index |
| P10P11 | 0000 | Don't care, ignored |
0x17 Bitwise AND (WY)
Bitwise AND of two registers, result stored in the first one: R[dst] &= R[src].
- Mnemonic Form
- Instruction Form
000 FZ 0007 8009 R07 = 8009
001 FZ 0009 FF00 R09 = FF00
002 WY 0007 0009 R07 = R07 AND R09
003 JS 0000 0000
000 10 0007 8009 R07 = 8009
001 10 0009 FF00 R09 = FF00
002 17 0007 0009 R07 = R07 AND R09
003 0F 0000 0000
1000 0000 0000 1001 AND 1111 1111 0000 0000 = 1000 0000 0000 0000 — R07 becomes 8000, R09 keeps its value.
| Operands | Value/Range | Remark |
|---|---|---|
| P00 | 00 | Don't care, ignored |
| P01 | 00~FF | Target register (result) |
| P10 | 00 | Don't care, ignored |
| P11 | 00~FF | Source register |
0x18 Bitwise OR (WH)
Bitwise OR of two registers, result stored in the first one: R[dst] |= R[src]. Operand format is identical to 0x17.
- Mnemonic Form
- Instruction Form
000 FZ 0007 8009 R07 = 8009
001 FZ 0009 FF00 R09 = FF00
002 WH 0007 0009 R07 = R07 OR R09
003 JS 0000 0000
000 10 0007 8009 R07 = 8009
001 10 0009 FF00 R09 = FF00
002 18 0007 0009 R07 = R07 OR R09
003 0F 0000 0000
1000 0000 0000 1001 OR 1111 1111 0000 0000 = 1111 1111 0000 1001 — R07 becomes FF09.
| Operands | Value/Range | Remark |
|---|---|---|
| P00 | 00 | Don't care, ignored |
| P01 | 00~FF | Target register (result) |
| P10 | 00 | Don't care, ignored |
| P11 | 00~FF | Source register |
0x19 Bitwise XOR (WYH)
Bitwise XOR of two registers, result stored in the first one: R[dst] ^= R[src]. Operand format is identical to 0x17.
- Mnemonic Form
- Instruction Form
000 FZ 0007 8009 R07 = 8009
001 FZ 0009 FF00 R09 = FF00
002 WYH 0007 0009 R07 = R07 XOR R09
003 JS 0000 0000
000 10 0007 8009 R07 = 8009
001 10 0009 FF00 R09 = FF00
002 19 0007 0009 R07 = R07 XOR R09
003 0F 0000 0000
1000 0000 0000 1001 XOR 1111 1111 0000 0000 = 0111 1111 0000 1001 — R07 becomes 7F09.
| Operands | Value/Range | Remark |
|---|---|---|
| P00 | 00 | Don't care, ignored |
| P01 | 00~FF | Target register (result) |
| P10 | 00 | Don't care, ignored |
| P11 | 00~FF | Source register |
0x1A Register Addition (RJIA)
Add two registers, result stored in the first one: R[dst] += R[src].
- Mnemonic Form
- Instruction Form
000 FZ 0008 1234 R08 = 1234
001 FZ 0006 0020 R06 = 0020
002 RJIA 0008 0006 R08 = R08 + R06
003 JS 0000 0000
000 10 0008 1234 R08 = 1234
001 10 0006 0020 R06 = 0020
002 1A 0008 0006 R08 = R08 + R06
003 0F 0000 0000
1234 + 0020 = 1254 — R08 becomes 1254. The result is the low 16 bits of the true sum (a carry beyond 16 bits is lost).
| Operands | Value/Range | Remark |
|---|---|---|
| P00 | 00 | Don't care, ignored |
| P01 | 00~FF | Target register (result) |
| P10 | 00 | Don't care, ignored |
| P11 | 00~FF | Source register |
0x1B Register Subtraction (RJIAN)
Subtract two registers, result stored in the first one: R[dst] −= R[src]. Operand format is identical to 0x1A.
- Mnemonic Form
- Instruction Form
000 FZ 0008 1234 R08 = 1234
001 FZ 0006 0020 R06 = 0020
002 RJIAN 0008 0006 R08 = R08 - R06
003 JS 0000 0000
000 10 0008 1234 R08 = 1234
001 10 0006 0020 R06 = 0020
002 1B 0008 0006 R08 = R08 - R06
003 0F 0000 0000
1234 − 0020 = 1214 — R08 becomes 1214.
| Operands | Value/Range | Remark |
|---|---|---|
| P00 | 00 | Don't care, ignored |
| P01 | 00~FF | Target register (result) |
| P10 | 00 | Don't care, ignored |
| P11 | 00~FF | Source register |
0x1C Register Multiplication (RCHENG)
Multiply two registers, result stored in the first one: R[dst] ×= R[src]. Operand format is identical to 0x1A.
- Mnemonic Form
- Instruction Form
000 FZ 0008 1234 R08 = 1234
001 FZ 0006 0020 R06 = 0020
002 RCHENG 0008 0006 R08 = R08 * R06
003 JS 0000 0000
000 10 0008 1234 R08 = 1234
001 10 0006 0020 R06 = 0020
002 1C 0008 0006 R08 = R08 * R06
003 0F 0000 0000
1234 × 0020 = 2 4680 — the true product needs 17+ bits, so only the low 16 bits are kept and R08 becomes 4680.
| Operands | Value/Range | Remark |
|---|---|---|
| P00 | 00 | Don't care, ignored |
| P01 | 00~FF | Target register (result) |
| P10 | 00 | Don't care, ignored |
| P11 | 00~FF | Source register |
0x1D Register Division (RCHU)
Divide two registers, the integer quotient stored in the first one: R[dst] ÷= R[src]. Operand format is identical to 0x1A.
The division is between integers — only the quotient is kept, the remainder is dropped (use 0x1E RQY for it). If the source register is 0000, a divide-by-zero exception is flagged.
- Mnemonic Form
- Instruction Form
000 FZ 0008 1234 R08 = 1234
001 FZ 0006 0020 R06 = 0020
002 RCHU 0008 0006 R08 = R08 / R06 (quotient)
003 JS 0000 0000
000 10 0008 1234 R08 = 1234
001 10 0006 0020 R06 = 0020
002 1D 0008 0006 R08 = R08 / R06 (quotient)
003 0F 0000 0000
1234 ÷ 0020 = 0091 (4660 ÷ 32 = 145, remainder dropped) — R08 becomes 0091.
| Operands | Value/Range | Remark |
|---|---|---|
| P00 | 00 | Don't care, ignored |
| P01 | 00~FF | Target register (result) |
| P10 | 00 | Don't care, ignored |
| P11 | 00~FF | Source register (divisor, must not be 0000) |
0x1E Register Remainder (RQY)
Divide two registers and keep only the remainder, stored in the first one: R[dst] %= R[src]. Operand format is identical to 0x1A.
If the source register is 0000, a divide-by-zero exception is flagged.
- Mnemonic Form
- Instruction Form
000 FZ 0008 1234 R08 = 1234
001 FZ 0006 0020 R06 = 0020
002 RQY 0008 0006 R08 = R08 % R06
003 JS 0000 0000
000 10 0008 1234 R08 = 1234
001 10 0006 0020 R06 = 0020
002 1E 0008 0006 R08 = R08 % R06
003 0F 0000 0000
1234 % 0020 = 0014 (4660 mod 32 = 20) — R08 becomes 0014.
| Operands | Value/Range | Remark |
|---|---|---|
| P00 | 00 | Don't care, ignored |
| P01 | 00~FF | Target register (result) |
| P10 | 00 | Don't care, ignored |
| P11 | 00~FF | Source register (divisor, must not be 0000) |
0x1F Random Number (SJS)
Generate a random number and store it in the target register: R[reg] = rand() (low 16 bits).
- Mnemonic Form
- Instruction Form
000 SJS 0005 0000 R05 = random value
001 JS 0000 0000
000 1F 0005 0000 R05 = random value
001 0F 0000 0000
| Operands | Value/Range | Remark |
|---|---|---|
| P00P01 | 0000~007F | 16-bit whole: target register (write as 00, register index) |
| P10P11 | 0000 | Don't care, ignored |
0x20 Compose Word (GDCZ)
Compose one 16-bit word from the low bytes of two registers and store it in the target register: the low byte of the target register becomes the high 8 bits, the low byte of the source register becomes the low 8 bits.
- Mnemonic Form
- Instruction Form
000 FZ 0005 2450 R05 = 2450
001 FZ 0006 FF00 R06 = FF00
002 GDCZ 0005 0006 R05 = low(R05) : low(R06)
003 JS 0000 0000
000 10 0005 2450 R05 = 2450
001 10 0006 FF00 R06 = FF00
002 20 0005 0006 R05 = low(R05) : low(R06)
003 0F 0000 0000
The low byte of R05 (50) becomes the high byte of the result and the low byte of R06 (00) becomes the low byte — R05 becomes 5000.
The dual 16-bit-whole operand format of 0x20/0x21 comes from firmware code analysis; on-device verification is recommended.
| Operands | Value/Range | Remark |
|---|---|---|
| P00P01 | 0000~007F | 16-bit whole: target register (write as 00, register index) |
| P10P11 | 0000~007F | 16-bit whole: source register (write as 00, register index) |
0x21 Byte Swap (GDJH)
Swap the high and low bytes of the target register.
- Mnemonic Form
- Instruction Form
000 FZ 0005 1234 R05 = 1234
001 GDJH 0005 0000 R05 = 3412
002 JS 0000 0000
000 10 0005 1234 R05 = 1234
001 21 0005 0000 R05 = 3412
002 0F 0000 0000
The dual 16-bit-whole operand format of 0x20/0x21 comes from firmware code analysis; on-device verification is recommended.
| Operands | Value/Range | Remark |
|---|---|---|
| P00P01 | 0000~007F | 16-bit whole: target register (write as 00, register index) |
| P10P11 | 0000 | Don't care, ignored |
0x2A Add Literal (JIA)
Add a literal value to a register: R[reg] += P10P11.
- Mnemonic Form
- Instruction Form
000 FZ 0007 8009 R07 = 8009
001 JIA 0007 03E8 R07 += 03E8
002 JS 0000 0000
000 10 0007 8009 R07 = 8009
001 2A 0007 03E8 R07 += 03E8
002 0F 0000 0000
8009 + 03E8 = 83F1 — R07 becomes 83F1.
| Operands | Value/Range | Remark |
|---|---|---|
| P00 | 00 | Don't care, ignored |
| P01 | 00~FF | Register index |
| P10P11 | 0000~FFFF | 16-bit whole: literal value |
0x2B Subtract Literal (JIAN)
Subtract a literal value from a register: R[reg] −= P10P11. Operand format is identical to 0x2A.
- Mnemonic Form
- Instruction Form
000 FZ 0007 83F1 R07 = 83F1
001 JIAN 0007 03E8 R07 -= 03E8
002 JS 0000 0000
000 10 0007 83F1 R07 = 83F1
001 2B 0007 03E8 R07 -= 03E8
002 0F 0000 0000
83F1 − 03E8 = 8009 — R07 becomes 8009.
| Operands | Value/Range | Remark |
|---|---|---|
| P00 | 00 | Don't care, ignored |
| P01 | 00~FF | Register index |
| P10P11 | 0000~FFFF | 16-bit whole: literal value |
0x2C Multiply Literal (CHENG)
Multiply a register by a literal value: R[reg] ×= P10P11. Operand format is identical to 0x2A.
- Mnemonic Form
- Instruction Form
000 FZ 0007 03E8 R07 = 03E8 (1000 in decimal)
001 CHENG 0007 0003 R07 *= 0003
002 JS 0000 0000
000 10 0007 03E8 R07 = 03E8 (1000 in decimal)
001 2C 0007 0003 R07 *= 0003
002 0F 0000 0000
1000 × 3 = 3000 = 0BB8 — R07 becomes 0BB8.
| Operands | Value/Range | Remark |
|---|---|---|
| P00 | 00 | Don't care, ignored |
| P01 | 00~FF | Register index |
| P10P11 | 0000~FFFF | 16-bit whole: literal value |
0x2D Divide by Literal (CHU)
Divide a register by a literal value, keeping the integer quotient: R[reg] ÷= P10P11. Operand format is identical to 0x2A.
If the literal divisor is 0000, a divide-by-zero exception is flagged.
- Mnemonic Form
- Instruction Form
000 FZ 0007 0BB8 R07 = 0BB8 (3000 in decimal)
001 CHU 0007 0003 R07 /= 0003
002 JS 0000 0000
000 10 0007 0BB8 R07 = 0BB8 (3000 in decimal)
001 2D 0007 0003 R07 /= 0003
002 0F 0000 0000
3000 ÷ 3 = 1000 = 03E8 — R07 becomes 03E8.
| Operands | Value/Range | Remark |
|---|---|---|
| P00 | 00 | Don't care, ignored |
| P01 | 00~FF | Register index |
| P10P11 | 0000~FFFF | 16-bit whole: literal value (divisor, must not be 0000) |
0x2E Modulo Literal (QY)
Compute the remainder of a register divided by a literal value: R[reg] %= P10P11. Operand format is identical to 0x2A.
If the literal divisor is 0000, a divide-by-zero exception is flagged.
- Mnemonic Form
- Instruction Form
000 FZ 0007 03E9 R07 = 03E9 (1001 in decimal)
001 QY 0007 0003 R07 %= 0003
002 JS 0000 0000
000 10 0007 03E9 R07 = 03E9 (1001 in decimal)
001 2E 0007 0003 R07 %= 0003
002 0F 0000 0000
1001 mod 3 = 2 = 0002 — R07 becomes 0002.
| Operands | Value/Range | Remark |
|---|---|---|
| P00 | 00 | Don't care, ignored |
| P01 | 00~FF | Register index |
| P10P11 | 0000~FFFF | 16-bit whole: literal value (divisor, must not be 0000) |
0x30 7-Segment Encode (BMQD)
Convert a value into two 7-segment segment codes, ready for the onboard 4-digit display driven by 0x44 SSE.
The value of the source register is split into two digits and each digit is looked up in the segment code table; the two codes are packed into the target register:
- High 8 bits = segment code of the tens / high digit.
- Low 8 bits = segment code of the ones / low digit.
- Segment bit order: bit7 = a … bit0 = dp.
Two split modes are selected by P11: decimal (00) splits the value 099 into tens and ones; hexadecimal (01) splits the low byte of the source register into a high nibble and a low nibble (00FF).
With P10 = 01 the whole 16-bit result is inverted — use this on the common-anode display where a segment lights when its line is LOW; P10 = 00 outputs the codes directly (common-cathode convention).
- Mnemonic Form
- Instruction Form
000 FZ 0001 003C R01 = 60
001 BMQD 0102 0100 R02 = segments of 60, inverted (common anode)
002 JS 0000 0000
000 10 0001 003C R01 = 60
001 30 0102 0100 R02 = segments of 60, inverted (common anode)
002 0F 0000 0000
Line 001 splits R01 = 60 into 6 and 0, looks up the segment codes (0xBE for 6, 0xFC for 0) and inverts them for the common-anode hardware — R02 = 4103: high byte = tens segments, low byte = ones segments. A full scanning example built on this opcode is shown in 0x44 SSE.
| Operands | Value/Range | Remark |
|---|---|---|
| P00 | 00~FF | Source register number (its low 8 bits are split) |
| P01 | 00~FF | Target register number |
| P10 | 00 | Direct output (common-cathode convention) |
01 | Invert the whole 16-bit result (common-anode display) | |
| P11 | 00 | Decimal split: value 0~99 → tens + ones |
01 | Hex split: low byte → high nibble + low nibble |
0x32 Three-Register Operation (TJYS)
Perform one operation on two source registers: R[dst] = R[s0] op R[s1], where the operation is selected by an operation code.
| Operands | Value/Range | Remark |
|---|---|---|
| P00 | 00~FF | Target register (result) |
| P01 | 00~0D | Operation code, see table below |
| P10 | 00~FF | Source register 0 (left operand) |
| P11 | 00~FF | Source register 1 (right operand) |
Operation code table:
| Code | Operation | Code | Operation |
|---|---|---|---|
00 | Bitwise AND | 08 | Write (R[s0] = R[s1]) |
01 | Bitwise OR | 09 | Shift |
02 | Bitwise XOR | 0A | Copy |
03 | Addition | 0B | Compose word from low bytes |
04 | Subtraction | 0C | Byte swap of R[s0] |
05 | Multiplication | 0D | Remainder |
06 | Division | ||
07 | Bitwise NOT (invert R[s0]) |
Operation codes 07, 08, 0A, 0B and 0C write their result into source register 0 (P10), not into the target register — for these codes the P00 operand has no effect. For division (06) and remainder (0D) make sure source register 1 is not zero.
- Mnemonic Form
- Instruction Form
000 FZ 0001 0005 R01 = 5
001 FZ 0002 0003 R02 = 3
002 TJYS 0303 0102 R03 = R01 + R02
003 JS 0000 0000
000 10 0001 0005 R01 = 5
001 10 0002 0003 R02 = 3
002 32 0303 0102 R03 = R01 + R02
003 0F 0000 0000
Line 002 uses operation code 03 (addition) on source registers R01 and R02 and stores the result in the target register — R03 = 5 + 3 = 8.