VR16 CPU Home Page
VR16-ISA 🔗
Arithmetic instructions 🔗
add:0000 | 00 | 00 | 00 | xxxxxx opcode | store_at | operand_one | operand_two | dont-care valuesaddi:0001 | 00 | 0000000000 opcode | store_at | 10-bit immediate valuesub:0010 | 00 | 00 | 00 | xxxxxx opcode | store_at | operand_one | operand_two | dont-care valuessubi:0011 | 00 | 0000000000 opcode | store_at | 10-bit immediate valuemul:0100 | 00 | 00 | 00 | xxxxxx opcode | store_at | operand_one | operand_two | dont-care valuesmuli:0101 | 00 | 0000000000 opcode | store_at | 10-bit immediate valuediv:0110 | 00 | 00 | 00 | xxxxxx opcode | store_at | operand_one | operand_two | dont-care valuesdivi:0111 | 00 | 0000000000 opcode | store_at | 10-bit immediate value
Exact immediate arithmetic semantics (ADDI, SUBI, MULI, DIVI) 🔗
For all immediate arithmetic opcodes (0001, 0011, 0101, 0111), the encoding and execution model are intentionally accumulator-style:
- Bits
[11:10](store_at) are both:- the destination register, and
- the source register (
operand_one).
- Bits
[9:0]are a 10-bit unsigned immediate. - Assembly literals for
imm10are accepted in base-10 only (e.g.,0,17,1023). - Valid
imm10range is0..1023, interpreted as an unsigned value. - Immediate is zero-extended to 16 bits before ALU use.
- Execution formulas:
ADDI rd, imm10:R[rd] <- R[rd] + zero_extend(imm10)SUBI rd, imm10:R[rd] <- R[rd] - zero_extend(imm10)MULI rd, imm10:R[rd] <- R[rd] * zero_extend(imm10)DIVI rd, imm10:R[rd] <- R[rd] / zero_extend(imm10)
[!NOTE] Assembler validation rule (immediate arithmetic family): non-base-10 literals or values outside
0..1023raiseInvalid immediate ... Expected a base-10 integer in range 0 to 1023.
Worked examples 🔗
addi r1, 5
- Before:
R1 = 12 - Encoded fields:
- opcode=
0001 store_at(r1) =01- imm10 (
5) =0000000101
- opcode=
- 16-bit instruction:
0001 01 0000000101 - ALU inputs:
operand_one = R1 = 12operand_two = zero_extend(5) = 5
- After:
R1 = 17
subi r2, 3
- Before:
R2 = 20 - 16-bit instruction:
0011 10 0000000011 - After:
R2 = 17
muli r0, 4
- Before:
R0 = 7 - 16-bit instruction:
0101 00 0000000100 - After:
R0 = 28
divi r3, 6
- Before:
R3 = 30 - 16-bit instruction:
0111 11 0000000110 - After:
R3 = 5
shift:1000 | 00 | 0 | 00000000 opcode | shift_at | direction | 9-bit shift amountjmp:1001 | 000000000000 | opcode | jump_to_12_bit_address for now
- Assembly literals for
jump_addressare accepted in base-10 only. - Valid
jump_addressrange is0..4095, interpreted as an unsigned address.
[!NOTE] Assembler validation rule (jump family): non-base-10 literals or values outside
0..4095raiseInvalid jump address ... Expected a base-10 integer in range 0 to 4095.
Rule for future immediate/address-bearing instructions 🔗
Any future instruction that carries an immediate/address field should follow the same assembler-facing contract:
- literal input is base-10 only,
- the accepted range is the instruction field width interpreted as unsigned,
- out-of-range or non-decimal input should raise an
Invalid ... Expected a base-10 integer in range ...error matching the extractor style.
cjmp:1010 | 00 | 00 | 00000000 opcode | reg_to_check | condition | 8-bit jump address
jeq- 00 - jump equal - ifx == yjne- 01 - jump not equal to - ifx != yjgt- 10 - jump greater than - ifx > yjlt- 11 - jump less than - ifx < y
and:1011 | 00 | 00 | 00 | xxxxxx opcode | store_at | operand_one | operand_two | dont-care valuesor:1100 | 00 | 00 | 00 | xxxxxx opcode | store_at | operand_one | operand_two | dont-care valuesnot:1101 | 00 | 00 | xxxxxxxx opcode | store_at | operand_one | dont-care valuesxor:1110 | 00 | 00 | 00 | xxxxxx opcode | store_at | operand_one | operand_two | dont-care valueshalt:1111 | xxxxxxxxxxxx opcode | dont-care values
Kept only basic LOGIC operations as others can be done from these.