Skip to content
This repository has been archived by the owner on Aug 20, 2024. It is now read-only.

Upgrade to Latest RISC-V Spec #49

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[submodule "riscv-tests"]
path = riscv-tests
url = [email protected]:riscv-software-src/riscv-tests
ignore = dirty
84 changes: 55 additions & 29 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,56 +1,82 @@
default: compile

base_dir = $(abspath .)
src_dir = $(base_dir)/src/main
gen_dir = $(base_dir)/generated-src
out_dir = $(base_dir)/outputs
src_dir = $(abspath .)/src/main
gen_dir = $(abspath .)/generated-src
out_dir = outputs

SBT = sbt
SBT_FLAGS = -ivy $(base_dir)/.ivy2
SBT_FLAGS = -ivy ./.ivy2

# sbt
sbt:
$(SBT) $(SBT_FLAGS)

compile: $(gen_dir)/Tile.v

# generate RTL from Chisel
$(gen_dir)/Tile.v: $(wildcard $(src_dir)/scala/*.scala)
$(SBT) $(SBT_FLAGS) "run $(gen_dir)"

CXXFLAGS += -std=c++11 -Wall -Wno-unused-variable
compile: $(gen_dir)/Tile.v

# compile verilator
# build verilator simulation binary
CXXFLAGS += -std=c++11 -Wall -Wno-unused-variable
VERILATOR = verilator --cc --exe
VERILATOR_FLAGS = --assert -Wno-STMTDLY -O3 --trace \
--top-module Tile -Mdir $(gen_dir)/VTile.csrc \
-CFLAGS "$(CXXFLAGS) -include $(gen_dir)/VTile.csrc/VTile.h"
-CFLAGS "$(CXXFLAGS) -include $(gen_dir)/VTile.csrc/VTile.h"

$(base_dir)/VTile: $(gen_dir)/Tile.v $(src_dir)/cc/top.cc $(src_dir)/cc/mm.cc $(src_dir)/cc/mm.h
VTile: $(gen_dir)/Tile.v $(src_dir)/cc/top.cc $(src_dir)/cc/mm.cc $(src_dir)/cc/mm.h
$(VERILATOR) $(VERILATOR_FLAGS) -o $@ $< $(word 2, $^) $(word 3, $^)
$(MAKE) -C $(gen_dir)/VTile.csrc -f VTile.mk
ln -s generated-src/VTile.csrc/VTile VTile

verilator: $(base_dir)/VTile
verilator: ./VTile

# isa tests + benchmarks with verilator
test_hex_files = $(wildcard $(base_dir)/tests/*.hex)
test_out_files = $(foreach f,$(test_hex_files),$(patsubst %.hex,%.out,$(out_dir)/$(notdir $f)))
# run ISA tests in riscv-tests
rv32ui = $(wildcard riscv-tests/isa/rv32ui/*.S)
rv32mi = $(wildcard riscv-tests/isa/rv32mi/*.S)
rv32ui_bin = $(patsubst riscv-tests/isa/rv32ui/%.S,riscv-tests/isa/rv32ui-p-%,$(rv32ui))
rv32mi_bin = $(patsubst riscv-tests/isa/rv32mi/%.S,riscv-tests/isa/rv32mi-p-%,$(rv32mi))
rv32ui_hex = $(addsuffix .hex,$(rv32ui_bin))
rv32mi_hex = $(addsuffix .hex,$(rv32mi_bin))
isa_tests_hex = $(rv32ui_hex) $(rv32mi_hex)
isa_tests_out = $(patsubst riscv-tests/isa/%.hex,outputs/isa/%.out,$(isa_tests_hex))

$(test_out_files): $(out_dir)/%.out: $(base_dir)/VTile $(base_dir)/tests/%.hex
mkdir -p $(out_dir)
$^ $(patsubst %.out,%.vcd,$@) 2> $@
$(rv32ui_bin) $(rv32mi_bin):
git apply --directory riscv-tests/env patches/env_p.patch || git apply --reverse --check --directory riscv-tests/env patches/env_p.patch
$(MAKE) -C riscv-tests/isa rv32ui
$(MAKE) -C riscv-tests/isa rv32mi

run-tests: $(test_out_files)
riscv-tests/isa/%.hex: riscv-tests/isa/% $(rv32ui_bin) $(rv32mi_bin)
riscv64-unknown-elf-elf2hex --bit-width 32 --input $< --output $@

# run custom benchamrk
custom_bmark_hex ?= $(base_dir)/custom-bmark/main.hex
custom_bmark_out = $(patsubst %.hex,%.out,$(out_dir)/$(notdir $(custom_bmark_hex)))
$(custom_bmark_hex):
$(MAKE) -C custom-bmark
$(out_dir)/isa/%.out: ./VTile riscv-tests/isa/%.hex
mkdir -p $(out_dir)/isa
-./$^ $(patsubst %.out,%.vcd,$@) 2>&1 | tee -a $@

$(custom_bmark_out): $(base_dir)/VTile $(custom_bmark_hex)
mkdir -p $(out_dir)
$^ $(patsubst %.out,%.vcd,$@) 2> $@
isa-tests-hex: $(isa_tests_hex)
isa-tests: $(isa_tests_out)

run-custom-bmark: $(custom_bmark_out)
# isa tests + benchmarks with verilator
# test_hex_files = $(wildcard $(base_dir)/tests/*.hex)
# test_out_files = $(foreach f,$(test_hex_files),$(patsubst %.hex,%.out,$(out_dir)/$(notdir $f)))
#
# $(test_out_files): $(out_dir)/%.out: $(base_dir)/VTile $(base_dir)/tests/%.hex
# mkdir -p $(out_dir)
# $^ $(patsubst %.out,%.vcd,$@) 2> $@
#
# run-tests: $(test_out_files)
#
# # run custom benchamrk
# custom_bmark_hex ?= $(base_dir)/custom-bmark/main.hex
# custom_bmark_out = $(patsubst %.hex,%.out,$(out_dir)/$(notdir $(custom_bmark_hex)))
# $(custom_bmark_hex):
# $(MAKE) -C custom-bmark
#
# $(custom_bmark_out): $(base_dir)/VTile $(custom_bmark_hex)
# mkdir -p $(out_dir)
# $^ $(patsubst %.out,%.vcd,$@) 2> $@
#
# run-custom-bmark: $(custom_bmark_out)

# unit tests + integration tests
test:
Expand All @@ -62,4 +88,4 @@ clean:
cleanall: clean
rm -rf target project/target

.PHONY: sbt compile verilator run-tests run-custom-bmark test clean cleanall
.PHONY: sbt compile verilator isa-tests isa-tests-hex run-custom-bmark test clean cleanall
56 changes: 45 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,63 @@ It is developed as an intermediate example before diving into [rocket-chip](http

## Getting Started

$ git clone https://github.com/ucb-bar/riscv-mini.git
$ cd riscv-mini
$ make # generate firrtl & verilog files in generated-src

```shell
$ git clone https://github.com/ucb-bar/riscv-mini.git
$ cd riscv-mini
$ make # generate firrtl & verilog files in generated-src
```

The verilog output file can be used for verilator simulation or the ASIC tool flow.

## Running Verilator Simulation

First, generate the verilator binary:

$ make verilator

```shell
$ make verilator
```

This will generate `VTile` in the top-level directory.

Now, you can run verilator simulation for a given hex file as follows:

$ ./VTile <hex file> [<vcd file> 2> <log file>]

```shell
$ ./VTile <hex file> [<vcd file> 2> <log file>]
```

`<vcd file>` and the pipe to `<log file>` are optional. The waveform is dumped to `dump.vcd` and the execution trace is printed in the screen by default.

The following command runs the whole test hex files in verilator and dumps the traces and the waveforms to the 'outputs' directory:
### riscv-tests

#### Prerequisites
1. Download the [latest RISC-V GCC toolchain from SiFive](https://www.sifive.com/software) (see 'Prebuilt RISC-V GCC Toolchain and Emulator) and install them by unpacking the archive.
2. Clone and build [`elf2hex`](https://github.com/sifive/elf2hex) according to the instructions in its README.

To run the ISA tests (rv32ui, rv32mi) and benchmarks from [`riscv-tests`](https://github.com/riscv-software-src/riscv-tests), clone the submodule:

```shell
git submodule update --init --recursive .
```

Then compile the tests (which will appear in `riscv-tests/isa/rv32{u,m}i-p-<test_name>.{dump,hex}`):

```shell
make isa-tests-hex
```

and run the tests using the Verilator simulator:

```shell
make isa-tests
```

The test outputs (stdout/stderr log and VCD waveform) will appear in `outputs/isa/rv32{u,m}i-p-<test_name>.{out,vcd}`.
You can check the test results using grep:

$ make run-tests
```shell
grep -r "FAIL" outputs/isa
grep -r "PASS" outputs/isa
```

## Unit and Integration Tests with `sbt`

Expand Down
18 changes: 18 additions & 0 deletions patches/env_p.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
diff --git a/p/link.ld b/p/link.ld
index b3e315e..8924a6b 100644
--- a/p/link.ld
+++ b/p/link.ld
@@ -3,11 +3,11 @@ ENTRY(_start)

SECTIONS
{
+ . = 0x7ffff000;
+ .tohost : { *(.tohost) }
. = 0x80000000;
.text.init : { *(.text.init) }
. = ALIGN(0x1000);
- .tohost : { *(.tohost) }
- . = ALIGN(0x1000);
.text : { *(.text) }
. = ALIGN(0x1000);
.data : { *(.data) }
1 change: 1 addition & 0 deletions riscv-tests
Submodule riscv-tests added at f0c75d
37 changes: 17 additions & 20 deletions src/main/cc/mm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,44 +9,43 @@
#include <cassert>

mm_magic_t::mm_magic_t(size_t size, size_t word_size):
data(new char[size]),
data(new uint8_t[size]),
size(size),
word_size(word_size),
word_size(word_size),
store_inflight(false)
{
dummy_data.resize(word_size);
}

mm_magic_t::~mm_magic_t()
{
mm_magic_t::~mm_magic_t() {
delete [] data;
}

void mm_magic_t::write(uint64_t addr, char *data) {
void mm_magic_t::write(uint64_t addr, uint8_t *data) {
addr %= this->size;

char* base = this->data + addr;
uint8_t* base = this->data + addr;
memcpy(base, data, word_size);
printf("Writing to addr %lx\n", addr);
}

void mm_magic_t::write(uint64_t addr, char *data, uint64_t strb, uint64_t size)
{
void mm_magic_t::write(uint64_t addr, uint8_t *data, uint64_t strb, uint64_t size) {
strb &= ((1L << size) - 1) << (addr % word_size);
addr %= this->size;

char *base = this->data + addr;
uint8_t *base = this->data + addr;
for (int i = 0; i < word_size; i++) {
if (strb & 1) base[i] = data[i];
strb >>= 1;
}
}

std::vector<char> mm_magic_t::read(uint64_t addr)
{
std::vector<uint8_t> mm_magic_t::read(uint64_t addr) {
addr %= this->size;

char *base = this->data + addr;
return std::vector<char>(base, base + word_size);
uint8_t *base = this->data + addr;
// printf("Reading from addr %lx\n", addr);
return std::vector<uint8_t>(base, base + word_size);
}

void mm_magic_t::tick(
Expand Down Expand Up @@ -94,7 +93,7 @@ void mm_magic_t::tick(
}

if (w_fire) {
write(store_addr, (char*)w_data, w_strb, store_size);
write(store_addr, (uint8_t*)w_data, w_strb, store_size);
store_addr += store_size;
store_count--;

Expand All @@ -120,12 +119,10 @@ void mm_magic_t::tick(
}
}

void load_mem(char* mem, const char* fn)
{
int start = 0;
void mm_magic_t::load_mem(const char* fn, const uint64_t base_addr) {
uint64_t start = base_addr;
std::ifstream in(fn);
if (!in)
{
if (!in) {
std::cerr << "could not open " << fn << std::endl;
exit(EXIT_FAILURE);
}
Expand All @@ -135,7 +132,7 @@ void load_mem(char* mem, const char* fn)
{
#define parse_nibble(c) ((c) >= 'a' ? (c)-'a'+10 : (c)-'0')
for (int i = line.length()-2, j = 0; i >= 0; i -= 2, j++) {
mem[start + j] = (parse_nibble(line[i]) << 4) | parse_nibble(line[i+1]);
this->data[start + j] = (parse_nibble(line[i]) << 4) | parse_nibble(line[i+1]);
}
start += line.length()/2;
}
Expand Down
18 changes: 9 additions & 9 deletions src/main/cc/mm.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
struct mm_rresp_t
{
uint64_t id;
std::vector<char> data;
std::vector<uint8_t> data;
bool last;

mm_rresp_t(uint64_t id, std::vector<char> data, bool last)
mm_rresp_t(uint64_t id, std::vector<uint8_t> data, bool last)
{
this->id = id;
this->data = data;
Expand All @@ -33,7 +33,7 @@ class mm_magic_t
mm_magic_t(size_t size, size_t word_size);
~mm_magic_t();
void init(size_t sz, int word_size);
char* get_data() { return data; }
uint8_t* get_data() { return data; }
size_t get_size() { return size; }

bool ar_ready() { return true; }
Expand Down Expand Up @@ -73,12 +73,13 @@ class mm_magic_t
bool b_ready
);

void write(uint64_t addr, char *data);
void write(uint64_t addr, char *data, uint64_t strb, uint64_t size);
std::vector<char> read(uint64_t addr);
void write(uint64_t addr, uint8_t *data);
void write(uint64_t addr, uint8_t *data, uint64_t strb, uint64_t size);
std::vector<uint8_t> read(uint64_t addr);
void load_mem(const char* fn, const uint64_t base_addr);

private:
char* data;
uint8_t* data;
size_t size;
size_t word_size;

Expand All @@ -87,13 +88,12 @@ class mm_magic_t
uint64_t store_id;
uint64_t store_size;
uint64_t store_count;
std::vector<char> dummy_data;
std::vector<uint8_t> dummy_data;
std::queue<uint64_t> bresp;

std::queue<mm_rresp_t> rresp;

uint64_t cycle;
};

void load_mem(char* mem, const char* fn);
#endif
Loading