TinyRV1 ISA
The TinyRV1 ISA is a very limited subset of the RISC-V ISA, an open-source instruction set architecture that has gained significant popularity in the last decade.
1. TinyRV1 Architectural State
1.1. Data Formats
TinyRV1 only supports 4B (four-byte) signed and unsigned integer values. There are no byte nor half-word values and no floating-point.
1.2. General-Purpose Registers
There are 31 general-purpose registers (GPRs) x1-x31 (called x
registers), which hold integer values. Register x0 is hardwired to the
constant zero. Each register is 32 bits wide. TinyRV1 uses the same calling
convention and symbolic register names as RISC-V:
+----------+----------+--------------------------------------------------------+
| Register | ABI Name | Description |
|----------|----------|--------------------------------------------------------|
| x0 | zero | The constant value 0 |
| x1 | ra | Return address (caller saved) |
| x2 | sp | Stack pointer (callee saved) |
| x3 | gp | Global pointer |
| x4 | tp | Thread pointer |
| x5 | t0 | Temporary registers (caller saved) |
| x6 | t1 | ↑ |
| x7 | t2 | ↑ |
| x8 | s0/fp | Saved register or frame pointer (callee saved) |
| x9 | s1 | Saved register (callee saved) |
| x10 | a0 | Function arguments and/or return values (caller saved) |
| x11 | a1 | ↑ |
| x12 | a2 | Function arguments (caller saved) |
| x13 | a3 | ↑ |
| x14 | a4 | ↑ |
| x15 | a5 | ↑ |
| x16 | a6 | ↑ |
| x17 | a7 | ↑ |
| x18 | s2 | Saved registers (callee saved) |
| x19 | s3 | ↑ |
| x20 | s4 | ↑ |
| x21 | s5 | ↑ |
| x22 | s6 | ↑ |
| x23 | s7 | ↑ |
| x24 | s8 | ↑ |
| x25 | s9 | ↑ |
| x26 | s10 | ↑ |
| x27 | s11 | ↑ |
| x28 | t3 | Temporary registers (caller saved) |
| x29 | t4 | ↑ |
| x30 | t5 | ↑ |
| x31 | t6 | ↑ |
+----------+----------+--------------------------------------------------------+
1.3. Memory
While TinyRV1 supports a 32-bit virtual memory address space, only the
first 512B of this address space (i.e., addresses 0x00000000 to
0x00001fff) are actually available for storage. The remaining portion
of the virtual memory address space is undefined with the exception of
the memory-mapped IO addresses described in the TinyRV1 "Privileged ISA".
TinyRV1 uses a little endian memory
system.
2. TinyRV1 Encoding
The TinyRV1 ISA uses the same instruction encoding as RISC-V. There are four instruction types and four immediate encodings. Each instruction has a specific instruction type, and if that instruction includes an immediate, then it will also have an immediate type.
2.1. Instruction Formats
R-type
I-type
S-type
U-type
2.2. Immediate Formats
RISC-V has an asymmetric immediate encoding which means that the immediates are formed by concatenating different bits in an asymmetric order based on the specific immediate formats. Note that in RISC-V, all immediates are always sign extended, and the sign-bit for the immediate is always in bit 31 of the instruction.
For this, let's separate out the different sections of an instruction:
The following diagrams represent how to re-arrange these sections to create different immediates, based on the encoding for the particular instruction. Here:
0is used to indicate that a particular bit is 0<-[n]->is used to indicate that bitnshould be replicated for all bits in the field
I-immediate
S-immediate
J-immediate
B-immediate
3. TinyRV1 Instructions
For each instruction we include a brief summary, assembly syntax, instruction semantics, instruction and immediate encoding format, and the actual encoding for the instruction. We use the following conventions when specifying the instruction semantics:
R[rx]: general-purpose register value for register specifierrxsext: sign extend to 32 bitsM[addr]: 4-byte memory value at addressaddrPC: current program counterimm: immediate according to the immediate typeaddr: 32-bit absolute memory address
3.1. ADDI
- Summary: Add constant
- Assembly:
addi rd, rs1, imm - Format: I-type, I-immediate
- Semantics:
3.2. ADD
- Summary: Addition with 3 GPRs (no overflow)
- Assembly:
add rd, rs1, rs2 - Format: R-type
- Semantics:
3.3. MUL
- Summary: Signed multiplication with 3 GPRs (no overflow)
- Assembly:
mul rd, rs1, rs2 - Format: R-type
- Semantics:
3.4. LW
- Summary: Load word from memory
- Assembly:
lw rd, imm(rs1) - Format: I-type, I-immediate
- Semantics:
TinyRV1 does not support unaligned memory access. The address used in any LW instruction must be 4-byte aligned (i.e., the bottom two bits must be zero). An unaligned LW address results in undefined behavior.
3.5. SW
- Summary: Store word in memory
- Assembly:
sw rs2, imm(rs1) - Format: S-type, S-immediate
- Semantics:
TinyRV1 does not support self-modifying code. Using a SW instruction to writing memory locations which will eventually be fetched as instructions results in undefined behavior. TinyRV1 does not support unaligned memory access. The address used in any SW instruction must be 4-byte aligned (i.e., the bottom two bits must be zero). An unaligned SW address results in undefined behavior.
3.6. JAL
- Summary: Jump to address, place return address in GPR
- Assembly:
jal rd, addr - Format: U-type, J-immediate
- Semantics:
The encoded immediate imm is calculated during assembly such that PC +
sext(imm) = addr. TinyRV1 requires the JAL target address to always be
four-byte aligned (i.e., the bottom two bits must be zero). An unaligned
JAL target address results in undefined behavior.
3.7. JR
- Summary: Jump to address
- Assembly:
jr rs1 - Format: I-type
- Semantics:
TinyRV1 requires the JR target address to always be four-byte aligned (i.e., the bottom two bits must be zero). An unaligned JR target address results in undefined behavior.
3.8. BNE
- Summary: Branch if two GPRs are not equal
- Assembly:
bne rs1, rs2, addr - Format: S-type, B-immediate
- Semantics:
The encoded immediate imm is calculated during assembly such that PC +
sext(imm) = addr. TinyRV1 requires the BNE target address to always be
four-byte aligned (i.e., the bottom two bits must be zero). An unaligned
BNE target address results in undefined behavior.
4. TinyRV1 "Privileged" ISA
TinyRV1 does not support any kind of distinction between user and privileged mode (which is why privileged is in quotes). Using the terminology in the RISC-V vol 2 ISA manual, TinyRV1 only supports M-mode.
4.1. Reset Vector
RISC-V specifies that on reset, PC will reset to an
implementation-defined value. TinyRV1 defines this to be at 0x00000000.
4.2. Memory-Mapped I/O
TBD
4.3. Address Translation
TinyRV1 only supports the most basic form of address translation. Every
logical address is directly mapped to the corresponding physical address.
As mentioned above, while TinyRV1 supports a 32-bit address space, only
the first 512B can be used for storage. So the virtual addresses from
0x00000000 to `0x00001fff are directly mapped to the corresponding
physical addresses. All other addresses are undefined with the exception
of the memory-mapped IO addresses. In the RISC-V vol 2 ISA manual this is
called a Mbare addressing environment.
5. TinyRV1 Pseudo-Instructions
It is very important to understand the relationship between the "real"
instructions presented in this manual, the "real" instructions in the
official RISC-V ISA manual, and pseudo-instructions. There are two
instructions we need to be careful with: NOP and JR. The
following table illustrates which ISAs contain which of these two
instructions, and whether or not the instruction is considered a "real"
instruction or a "pseudo-instruction".
NOP is always a pseudo-instruction. It is always equivalent to the
following use of the ADDI instruction:
JR is a "real" instruction in TinyRV1, but it is a pseudo-instruction
in RISC-V for the following use of the JALR instruction:
None of this changes the encodings. In TinyRV1, JR is encoded the same
way as the corresponding use of the JALR instruction in RISC-V.