Skip to content

Pippadi/bf8b

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

bf8b

A simple RISC-V CPU core. Currently implements barebones rv32i.

My first Verilog project. I have no idea what I'm doing.

Formerly Baby's First 8-Bit computer

Details

  • 4-stage pipeline with fetch, decode, execute, and writeback
  • 32-bit data bus
  • 32-bit address bus
  • LRU Instruction cache
  • In-order execution
  • No exceptions or interrupts yet

Programming

The test/prog2verilog.py script converts a RISC-V assembly program into a set of hex files that can be read by the simulator. The process it uses is based off of what I learned here. You need the RISC-V GCC toolchain installed to use it (called cross-riscv64-elf-gcc15 for me on openSUSE).

Use like so:

python3 test/prog2verilog.py test/fibonacci.s -d

Edit the testbench so that the $readmemh directives read the correct hex files.

Execution begins at address 0x00 (specified in the linker script). Ensure that you specify an adequate number of clock pulses in the simulation for your program. Dump bytes of mem relevant to you to the VCD file with $dumpvars(0, mem[ADDR]).

Build with the Makefile. This is written to use Icarus Verilog and GTKWave. The latest commits on the main branch should synthesize in Vivado as well.

make clean
make
make bf8b.vcd
make sim

Architectural Notes

The LRU instruction cache has a default size of 8 instructions. On-the-fly modification of instructions is not supported, as the fetch stage does not check for consistency between cached instructions and memory.

LRU behavior is implemented by building the cache around a modified shift register. Each level in the shift register holds an address and the corresponding data. Further, each level can be enabled or disabled individually, meaning that shifts can be selectively performed within the register.

Data to be cached is shifted in. Writing data whose address is not present in the cache results in the oldest data getting shifted out. When there is a hit on data, the hit data is shifted into the top, and all the data above it, are shifted. In other words, the hit data is shifted to the top of the shift register, its old position being overwritten while all the older cells remain untouched. It is the position of the data within the shift register that determines age. There are no separate bits spent on tracking age.

Basic branch prediction and a D cache are future goals.

About

A barebones RISC-V rv32i core

Resources

License

Stars

Watchers

Forks