A simple 16b CPU and ISA designed for Tiny Tapeout with a two-stage pipeline and 4b serial datapath.
- asm: Handwritten and auto-generated tests written in assembly language.
- podi: Rapsberry Pi Pico firmware for communicating with an Idli instance running on FPGA (unfinished).
- scripts: Contains a variety of python scripts and tools including:
- asm.py: Assembler, generates binary files.
- objdump.py: Disassembler for binaries generated by the assembler.
- sim.py: Behavioural model for the ISA.
- tb.py: cocotb test bench used during RTL simulation.
- tgen.py: Random test generator.
- src: RTL for the core, with the top level
idli_top_m. - test: Test bench and bias files for random test generation.
First assemble the input files in asm to binary files using make -j8 asm.
Outputs will be written into the build directory. A python venv will also be
created automatically.
Each test has an assembly file (.asm) and configuration file (.yaml) which
contains various options such as IO events.
Once the tests have been built they can be run in a few different ways. The test
to run can be configured using the SIM_TEST=<path> option.
Runs using the reference python simulator. This is not cycle accurate and runs a single instruction on each tick.
make run_sim SIM_TEST=build/asm/qsort.out DEBUG=1
The optional DEBUG argument enables verbose output for the simulator which
traces the instructions and core state during execution.
Builds and runs the SystemVerilog RTL using verilator.
make run_veri SIM_TEST=build/asm/qsort.out
Setting DEBUG=1 will automatically open the simulation waves using gtkwave
on test completion.
Converts the SystemVerilog to Verilog using sv2v, then runs on iverilog.
make run_icarus SIM_TEST=build/asm/qsort.out
Waves can be enabled here with DEBUG=1 as with verilator.
The register has the following register state.
- Sixteen 16b general purpose registers,
R0toR15, a few of which have special purposes:R0is also known as the zero registerZR. Reads always return a value of zero and writes are ignored.R14is the link register,LR.R15is the stack pointer,SP.
- One 1b predicate register
P. - One 4b count register,
COUNT. - One 8b conditional execution mask register,
COND. - One 16b program counter,
PC.
Register operands typically appear in instructions as A, B, and C. If C
is set to SP it is ignored and the 16b following the instruction is treated as
an immediate operand instead.
Standard addition, subtraction, and logical operations.
ADD A, B, C # A = B + C
SUB A, B, C # A = B - C
AND A, B, C # A = B & C
ANDN A, B, C # A = B & ~C
OR A, B, C # A = B | C
XOR A, B, C # A = B ^ C
INC A, B # A = B + 1
DEC A, B # A = B - 1
NOT A, B # A = ~B
ADDPC A, C # A = PC + C
Memory access instructions with auto-increment and multiple variants.
LD A, B, C # A = [B + C]
LD+ A, B # A = [B++]
LD- A, B # A = [B--]
+LD A, B # A = [++B]
-LD A, B # A = [--B]
LDM R..S, B # R..S = [B..]
ST A, B, C # [B + C] = A
ST+ A, B # [B++] = A
ST- A, B # [B--] = A
+ST A, B # [++B] = A
-ST A, B # [--B] = A
STM R..S, B # [B..] = R..S
Single-bit shifts and rotates.
SRL A, B # A = { 1'b0, B[15:1]}
SRA A, B # A = {B[ 15], B[15:1]}
ROR A, B # A = {B[ 0], B[15:1]}
ROL A, B # A = {B[14:0], B[ 15]}
Compare operands and set predicate register to result.
EQ B, C # P = B == C
NE B, C # P = B != C
LT B, C # P = B < C (signed)
LTU B, C # P = B < C (unsigned)
GE B, C # P = B >= C (signed)
GEU B, C # P = B >= C (unsigned)
ANY B, C # P = |(B & C)
These instructions also have variants that implicitly set COND to T to
predicate the following instruction.
EQX B, C # EQ (B, C); COND(T)
NEX B, C # NE (B, C); COND(T)
LTX B, C # LT (B, C); COND(T)
LTUX B, C # LTU(B, C); COND(T)
GEX B, C # GE (B, C); COND(T)
GEUX B, C # GEU(B, C); COND(T)
ANYX B, C # ANY(B, C); COND(T)
Relative and absolute branches.
B C # PC += C
J C # PC = C
BL C # LR = NEXT_PC; B(C)
JL C # LR = NEXT_PC; J(C)
Input and output operations for accessing the UART and IO pins.
IN A, N # A = PIN(N)
INP N # P = PIN(N)
INPX A, N # INP(N); COND(T)
OUT N, C # PIN(N, C)
OUTN N, C # PIN(N, ~C)
OUTP N # PIN(N, C)
URX A # A = UART()
UTX C # UART(C)
Miscellaneous operations. Count operations set the COUNT register and operation
to modify the behaviour of the following J instructions.
GETP A # A = P
PUTP C # P = C[0]
CARRY J # sticky carry
ANDP J # update P with &= instead of =
ORP J # update P with |= instead of =
CEX M # predicate following instructions
Convenience synonyms for common operations.
MOV A, C # ADD A, ZR, C
RET # J LR
NOP # ADD ZR, ZR, ZR
PUSH A # -ST A, SP
POP A # LD+ A, SP
SLL A, B # ADD A, B, B