5 Commits

Author SHA1 Message Date
5cb8b7dd77 start adding parallel ATA stuff 2023-01-23 18:26:44 -07:00
51103c378d update comment 2023-01-23 18:26:14 -07:00
71bc903f14 ignore overrun at end of skidbuffer test 2022-12-28 22:24:55 -07:00
3b476cfc32 update gtkw paths 2022-12-28 22:10:18 -07:00
02db181281 comment 2022-12-28 22:07:28 -07:00
29 changed files with 211 additions and 177 deletions

View File

@@ -1,68 +0,0 @@
name: Build
on: push
jobs:
# lint:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@master
# - uses: chipsalliance/verible-linter-action@main
# # with:
# # paths: |
# # ./src
# # ./lib
# # ./tests
# # extra_args: "--check_syntax=true"
# enumerate-tests:
# name: Enumerate tests
# runs-on: ubuntu-latest
# outputs:
# matrix: ${{ steps.set-matrix.outputs.matrix }}
# steps:
# - uses: actions/checkout@v2
# - id: set-matrix
# run: echo "::set-output name=matrix::$(ls tests | grep test_* | jq -R -s -c 'split("\n")[:-1]')"
test:
# needs: enumerate-tests
name: Run Test `${{ matrix.test }}`
runs-on: ubuntu-latest
strategy:
matrix:
# test: ${{ fromJson(needs.enumerate-tests.outputs.matrix) }}
test:
- test_basic
- test_c
max-parallel: 1
steps:
- uses: actions/checkout@v4
- name: Build executables
uses: docker://runtimeverificationinc/riscv-gnu-toolchain:ubuntu-jammy-2024.04.12
with:
entrypoint: sh
args: |
-c "\
cd tests/${{ matrix.test }} && \
make obj && \
riscv64-unknown-elf-ld -melf32lriscv -T tb.ld *.o -o tb.elf && \
riscv64-unknown-elf-objcopy --target=verilog tb.elf tb.hex && \
riscv64-unknown-elf-objdump -xhdtsf tb.elf && \
echo "done" \
"
- name: Run Simulation
uses: docker://brendanhaines/iverilog:latest
with:
entrypoint: bash
args: |
-c "\
cd tests/${{ matrix.test }} && \
iverilog -g2012 -o tb.out tb.sv ../../src/*.v -Y .sv -I ../../lib && \
./tb.out | tee tb.log &&\
grep -q "ERROR" tb.log || true &&\
grep -q "SUCCESS" tb.log &&\
echo "done"
"

20
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,20 @@
image: ubuntu
stages:
- simulate
testbench:
stage: simulate
script:
- echo "Installing dependencies..."
- apt update && apt install -y make iverilog gcc-10-riscv64-linux-gnu
- echo "Running tests..."
- make -C tests
testbench_libraries:
stage: simulate
script:
- echo "Installing dependencies..."
- apt update && apt install -y make iverilog
- echo "Running tests..."
- make -C lib/tb

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "riscv-gnu-toolchain"]
path = riscv-gnu-toolchain
url = https://github.com/riscv-collab/riscv-gnu-toolchain.git

View File

@@ -2,7 +2,6 @@
"recommendations": [
"mshr-h.veriloghdl",
"zhwu95.riscv",
"hediet.vscode-drawio",
"sunshaoce.risc-v"
"hediet.vscode-drawio"
]
}

View File

@@ -1,36 +1,25 @@
![pipeline status](https://gitlab.com/brendanhaines/0039_cpu/badges/master/pipeline.svg)
# RISC-V CPU
Short Term To Do:
- [ ] add stalls for memory access
- [ ] use AXI for memory access (depends on AXIL memory module for test)
- [ ] add tests for non-pipelined case
- [ ] get C working (may depend on memory stalls)
* add stalls for memory access
* use AXI for memory access (depends on AXIL memory module for test)
* add tests for non-pipelined case
* get C working (may depend on memory stalls)
Desired features:
- [ ] 1- or 5-stage pipeline selectable via parameter
- [ ] AXI-lite Master for both instruction and data memory
- [ ] 32, 64, (or 128?) bit word size
- [ ] floating point
- [ ] multiplication
- [ ] division
- [ ] instruction and data caches
- [ ] JTAG debug probe
* 1- or 5-stage pipeline selectable via parameter
* AXI-lite Master for both instruction and data memory
* 32, 64, (or 128?) bit word size
* floating point
* multiplication
* division
* instruction and data caches
* JTAG debug probe
## Development
### Testing
I'm using [act](https://github.com/nektos/act) for local testing. No special installation is required since everything gets built and tested in containers as part of the CI actions.
To run the tests, use
```bash
act push
```
## Installation
Run `setup.sh` to install GCC
## Resources
* [AXI4 Protocol Specification](https://developer.arm.com/documentation/ihi0022/e/AMBA-AXI3-and-AXI4-Protocol-Specification?lang=en)
* [JTAG Bus Description](https://web.archive.org/web/20230314233136/http://www.interfacebus.com/Design_Connector_JTAG_Bus.html)
* [1149.1-2013 - IEEE Standard for Test Access Port and Boundary-Scan Architecture](https://ieeexplore.ieee.org/document/6515989)
## Attribution
* [Icon](https://www.flaticon.com/free-icon/cpu_543275)

1
docs/cpu.drawio Normal file
View File

@@ -0,0 +1 @@
<mxfile host="www.draw.io" modified="2021-07-04T02:03:34.409Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36" etag="gyPD3FephFzBolRvCJxz" version="14.8.4" type="device"><diagram id="K6ND4OlvUQiSsjvqaGL3" name="Page-1">7Vpbc5s4FP41ntl9iAchwPjRl2SbnWa2M9mZbR8VkA1dGXmEnNj99SuMMCAJ16kh0G384EEHSaDvfOeig0Zwsdn/wdA2eqAhJiPbCvcjuBzZ9tQH4j8THHKBa8FcsGZxmItAKXiMv2EptKR0F4c4rXXklBIeb+vCgCYJDnhNhhijL/VuK0rqT92iNdYEjwEiuvSfOORRLvVdq5R/wPE6Kp4MLHlng4rOUpBGKKQvFRG8HcEFo5TnV5v9ApMMuwKXfNxdw93TizGc8EsGPN18Q/HKWzjLP7nvEJAs/rq/sZ18mmdEdnLF8m35oYCA0V0S4mwWawTnL1HM8eMWBdndF6FzIYv4hogWEJchSqNj36yxiglZUEKZaCc0ESPm8nGYcbxvXAg4wSNohekGc3YQXeQATwIqGVXg+1Kqx/GlLKqoxi6ESFJifZq5RE1cSOBeASK0WwaxitvIhqvVyg4CIU85o//i9hGdKIhCHVJoGSD1ukLUnnSLaOhiP3Q6RBROVZLqkALHAOm0M0i9nxxShaQGjjqeAVDQmdlPNfxwKGKHbFLGI7qmCSK3pXReR7js85HSrcT1K+b8IAMh2nFaRx3vY/45Gz52ZetL5c5yL2c+Ng5FIxHLrQzKml+q98phx1YxLuWI8VkWRIUgIChN46AQ38WkeKUchmzt5zUroKI7FuAzkBYRHrE15mf6uWamMEwQj5/r79G63oFmSAFlePx8nTm1YCF+3UIcg4WYXI7TmcvRgFoijoTkAW/o8cUXKIhw77idEDgo7aqztt8SOaghd58Iv7oLeEyT4QHoDw0/AN99c9u+2bnQN8M+fbO+nWkwnA8oCQlmQzMdYNjNvLHp6Gnhu+lcaTruhaZj95rWuJrtzD7fjzLy3Yl/cX3zUViDuPztAaUcs9/7JAqo0KQkjZkoFyo8jdA2e+iK4L3s3ToJGv2ANYbQkaZ3sb7lbJ9oLF6mUh9RfMpkOp64vmdbnj/1XNeG9RlzWspJqgWkYt6iI12tUsw1op0Wc0WmaPXJJWts/5DXsf8nbgdMr/Q7x6FiaehQ6bDN2JM201SrOqn1S7U/vK5/UcFq7K8VGGr9xUW+wlaJr/tcZYvkEaG5+ZNIVLx1djWUvEXdMwGv78RFLxm+NnyZAgBOwgab1cVXhinxqOITA/DGXu3n5/elK3PHPqz9Osj0z0QqT9e0qTp8El4Zz6BimI6lUChf0JkA1hQYVS4OIBIC30RjSV3VGVyRiJm4PuTkrEV6+21Eu++SS/s40kCutoij82aJn3brrEZERR5CyRCihqOC1H+l6KfMPAeeeF5axm8INNfGC1AnmfpJ7dJwoc4DJm9r0QD0S83Jr0zNboIEtBVK/Wgqo02kfuVs4OZrN2mOagPf2UQ53tn+3WyigP5p+5j6q+nSgtE0fUL9h0E1VzBEweLcVDUIwu7OW9hmBA2bp0eCnvF76e91TqehwNJ97Q/Cwdf+wFTjnqyB/J1Rnxw/c9LdlgjulHWRgZU/YO/fbWy9lJStfIuZ4WSCWDivY2I8tWM4v4dIvE4yWxJAiQ0FnGcwxgEiM3ljE4fh0d5NSqirqXZWsAOlXKoTuzOd6NT+JByPkOipna6SNqFeiT1g5bDWZDbzvUJeuG3Qggq0nNlw7s14OLOzkxT6aR2pArsHFZRQaypZOLOJc9eOIQD1QIbbmRZEszzCnIeE8hw4vP0P</diagram></mxfile>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 390 KiB

BIN
icon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

53
lib/axil_ata.sv Normal file
View File

@@ -0,0 +1,53 @@
module axil_ata(
///// AXI4-Lite Slave /////
// Write address
input logic axil_awvalid,
output logic axil_awready,
input logic [ADDR_WIDTH-1:0] axil_awaddr,
input logic [2:0] axil_awprot,
// Write data
input logic axil_wvalid,
output logic axil_wready,
input logic [DATA_WIDTH-1:0] axil_wdata,
input logic [DATA_WIDTH/8 - 1:0] axil_wstrb,
// Write response
output logic axil_bvalid,
input logic axil_bready,
output logic [1:0] axil_bresp,
// Read address
input logic axil_arvalid,
output logic axil_arready,
input logic [ADDR_WIDTH-1:0] axil_araddr,
input logic [2:0] axil_arprot,
// Read data
output logic axil_rvalid,
input logic axil_rready,
output logic [DATA_WIDTH-1:0] axil_rdata,
output logic [1:0] axil_rresp,
///// Parallel ATA Master /////
output logic ata_n_reset, // reset
inout wire [15:0] ata_data, // data
output logic ata_n_diow, // write strobe
output logic ata_n_dior, // read strobe
input wire ata_iordy, //
input wire ata_irq, // interrupt request
output logic [2:0] ata_addr, // address
output logic [1:0] ata_n_cs, // chip select
input wire ata_activity, // LED driver
xx wire ata_cable_select, //
xx wire ata_dmarq, // DMA request
xx wire ata_ddack, // DMA acknowledge
xx wire ata_gpio_dma66_detect, //
xx wire ata_n_iocs16 // IO ChipSelect 16
);
endmodule

View File

@@ -7,7 +7,7 @@ module axil_wb_bridge #(
input logic clk,
input logic reset,
///// AXI4-Lite /////
///// AXI4-Lite Slave /////
// Write address
input logic axil_awvalid,

View File

@@ -1,4 +1,4 @@
module skidbuffer #(
module axis_skidbuffer #(
parameter WIDTH = 1
)(
input logic clk,

21
lib/tb/axil_ata_tb.sv Normal file
View File

@@ -0,0 +1,21 @@
`include "bh_assert.sv"
`timescale 1ns/1ps
import bh_assert::bh_assert_equal;
import bh_assert::bh_assert_stats;
import bh_assert::bh_info;
module axil_ata_tb();
axil_ata dut();
initial begin
$dumpfile("axil_ata_tb.vcd");
$dumpvars(0, axil_ata_tb);
#10
bh_assert_stats();
$finish;
end
endmodule

View File

@@ -255,6 +255,10 @@ initial begin
#10
bh_assert_stats();
$finish;
// TODO: add more exhaustive testing
end
endmodule

View File

@@ -4,7 +4,7 @@
import bh_assert::bh_assert_equal;
import bh_assert::bh_assert_stats;
module skidbuffer_tb();
module axis_skidbuffer_tb();
parameter WIDTH = 15;
parameter TEST_LIST_LENGTH = 256;
@@ -17,7 +17,7 @@ module skidbuffer_tb();
wire out_valid;
logic out_ready = 0;
skidbuffer #(
axis_skidbuffer #(
.WIDTH(WIDTH)
) dut (
.clk(clk),
@@ -40,8 +40,8 @@ module skidbuffer_tb();
always #5 clk = !clk;
initial begin
$dumpfile("skidbuffer_tb.vcd");
$dumpvars(0, skidbuffer_tb);
$dumpfile("axis_skidbuffer_tb.vcd");
$dumpvars(0, axis_skidbuffer_tb);
for (i=0; i<TEST_LIST_LENGTH; i=i+1) begin
in_list[i] = $urandom();
@@ -71,8 +71,10 @@ module skidbuffer_tb();
end
if (reset == 0 && out_valid && out_ready) begin
bh_assert_equal(out, in_list[out_count], $sformatf("Output value [%3d]", out_count));
out_count <= out_count + 1;
if (out_count < TEST_LIST_LENGTH) begin
bh_assert_equal(out, in_list[out_count], $sformatf("Output value [%3d]", out_count));
out_count <= out_count + 1;
end
end
end

1
riscv-gnu-toolchain Submodule

Submodule riscv-gnu-toolchain added at 96d9f40c9d

7
setup.sh Executable file
View File

@@ -0,0 +1,7 @@
sudo apt-get install -y autoconf automake autotools-dev curl python3 libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev
SCRIPT=$(realpath "$0")
SCRIPTPATH=$(dirname "$SCRIPT")
cd $SCRIPTPATH/riscv-gnu-toolchain
./configure --prefix=$SCRIPTPATH/toolchain/riscv --enable-multilib
make

View File

@@ -120,6 +120,19 @@ reg s_if_stall = 0;
reg [31:0] s_if_next_pc;
reg [31:0] s_if_inst;
always @(*) begin
s_if_stall = s_id_stall;
if (s_ex_take_branch) begin
s_if_next_pc = s_ex_branch_addr;
end else begin
s_if_next_pc = r_if_pc + 4;
end
mem_inst_addr = r_if_pc;
s_if_inst = mem_inst_data;
end
// ID
reg s_id_stall;
reg [6:0] s_id_opcode;
@@ -164,39 +177,7 @@ localparam ALUOP_ADD = 4'b0000,
ALUOP_SLT = 4'b1000,
ALUOP_SLTU = 4'b1001;
// EX
reg s_ex_stall = 0;
reg [31:0] s_ex_data1, s_ex_data2;
reg [31:0] s_ex_alu_out;
reg s_ex_alu_zero;
reg s_ex_take_branch;
reg [31:0] s_ex_branch_addr;
reg [31:0] s_ex_ra;
// MEM
reg s_mem_stall = 0;
reg s_mem_bp;
reg [31:0] s_mem_load_data;
// WB
reg [31:0] s_wb_data;
reg s_wb_write;
// IF
always @(*) begin
s_if_stall = s_id_stall;
if (s_ex_take_branch) begin
s_if_next_pc = s_ex_branch_addr;
end else begin
s_if_next_pc = r_if_pc + 4;
end
mem_inst_addr = r_if_pc;
s_if_inst = mem_inst_data;
end
// ID
always @(*) begin
s_id_invalid = 0;
s_id_store = 0;
@@ -351,6 +332,14 @@ always @(*) begin
end
// EX
reg s_ex_stall = 0;
reg [31:0] s_ex_data1, s_ex_data2;
reg [31:0] s_ex_alu_out;
reg s_ex_alu_zero;
reg s_ex_take_branch;
reg [31:0] s_ex_branch_addr;
reg [31:0] s_ex_ra;
always @(*) begin
s_ex_stall = s_mem_stall;
@@ -405,6 +394,10 @@ always @(*) begin
end
// MEM
reg s_mem_stall = 0;
reg s_mem_bp;
reg [31:0] s_mem_load_data;
always @(*) begin
s_mem_stall = 0; // TODO: add stall logic when actually reading/writing
s_mem_bp = 0;
@@ -424,6 +417,9 @@ always @(*) begin
end
// WB
reg [31:0] s_wb_data;
reg s_wb_write;
always @(*) begin
// load instructions do not use output of alu in wb
@@ -479,8 +475,6 @@ always @(posedge clk) begin: pipeline_update
end
end else begin
// $display("%0t:\tPC=0x%h", $time, s_if_next_pc);
// IF
if (!s_if_stall) begin
r_if_pc <= s_if_next_pc;

6
tests/.gitignore vendored
View File

@@ -1,3 +1,3 @@
**/*.out
**/*.vcd
**/*.log
*.out
*.vcd
*.log

18
tests/Makefile Normal file
View File

@@ -0,0 +1,18 @@
all: verify
BENCH ?= $(sort $(dir $(wildcard test_*/)))
# override bench to disable test_c
BENCH = test_basic
verify:
$(foreach dir, $(BENCH), make -C $(dir) verify;)
clean:
$(foreach dir, $(BENCH), make -C $(dir) clean;)
help:
$(info BENCH options: [${BENCH}])
.SECONDARY:
.PHONY: all clean verify help

View File

@@ -2,10 +2,10 @@
[*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI
[*] Wed Aug 11 06:10:48 2021
[*]
[dumpfile] "/home/brendan/Documents/Projects/0039_cpu/testbench/basic_test/tb.vcd"
[dumpfile] "/home/brendan/Documents/projects/cpu/tests/test_basic/tb.vcd"
[dumpfile_mtime] "Wed Aug 11 06:09:59 2021"
[dumpfile_size] 511500
[savefile] "/home/brendan/Documents/Projects/0039_cpu/testbench/testbench_tb.gtkw"
[savefile] "/home/brendan/Documents/projects/cpu/tests/basic_test.gtkw"
[timestart] 0
[size] 1920 1052
[pos] -1970 -28

View File

@@ -11,15 +11,15 @@ OBJ = $(notdir $(SOURCE_AS:.S=.o))
OBJ += $(notdir $(SOURCE_C:.c=.o))
# Software compilation
CC = riscv64-unknown-elf-gcc
CC = riscv64-linux-gnu-gcc
CFLAGS = -march=rv32i -mabi=ilp32
CPPFLAGS =
AS = riscv64-unknown-elf-as
AS = riscv64-linux-gnu-as
ASFLAGS = -march=rv32i -mabi=ilp32
LD = riscv64-unknown-elf-ld
LD = riscv64-linux-gnu-ld
LDFLAGS = -melf32lriscv_ilp32
# $(info $$TESTBENCH_V is [${TESTBENCH_V}])
@@ -40,7 +40,7 @@ LDFLAGS = -melf32lriscv_ilp32
$(LD) $(LDFLAGS) -T $^ -o $@
%.hex: %.elf
riscv64-unknown-elf-objcopy --target=verilog $< $@
riscv64-linux-gnu-objcopy --target=verilog $< $@
# Hardware compilation
%.out: %.sv $(SOURCE_V)
@@ -57,7 +57,5 @@ verify: $(LOGS)
clean:
rm -rf *.vcd *.log *.out *.hex
obj: $(OBJ)
.SECONDARY: %.log %.vcd
.PHONY: all clean verify obj
.PHONY: all clean verify

View File

@@ -1,5 +1,5 @@
# basic_test
Verify basic usage of all instructions. Includes tests to ensure pipeline stalls sufficiently for correctness but does not test for unnecessary/excessive stalls.
Verify basic usage of all instructions. Includes tests to ensure pipeline stalls sufficiently for correctness but does not test for unnecessary stalls.
Currently store/load does not implement proper stalling so these operations are padded with `nop`
Currently store/load does not implement proper stalling so these operations are padded with nop

View File

@@ -31,7 +31,7 @@ initial $readmemh("tb.hex", mem);
// Instruction Memory
wire [31:0] mem_inst_addr;
reg [31:0] mem_inst_data;
always_comb begin
always @(*) begin
if (mem_inst_addr < MEM_LENGTH - 3) begin
mem_inst_data[ 7: 0] = mem[mem_inst_addr+0];
mem_inst_data[15: 8] = mem[mem_inst_addr+1];

View File

@@ -10,18 +10,18 @@ SOURCE_AS = $(wildcard *.S)
OBJ = $(notdir $(SOURCE_AS:.S=.o))
OBJ += $(notdir $(SOURCE_C:.c=.o))
CC = riscv64-unknown-elf-gcc
CC = riscv64-linux-gnu-gcc
CFLAGS = -march=rv32i -mabi=ilp32
# CFLAGS = -march=rv64i -mabi=lp64
# CFLAGS += -nostdlib -lgcc
CPPFLAGS =
AS = riscv64-unknown-elf-as
AS = riscv64-linux-gnu-as
ASFLAGS = -march=rv32i -mabi=ilp32
# ASFLAGS = -march=rv64i -mabi=lp64
LD = riscv64-unknown-elf-ld
LD = riscv64-linux-gnu-ld
LDFLAGS = -melf32lriscv_ilp32
# LDFLAGS =
@@ -45,7 +45,7 @@ LDFLAGS = -melf32lriscv_ilp32
$(LD) $(LDFLAGS) -T $^ -o $@
%.hex: %.elf
riscv64-unknown-elf-objcopy --target=verilog $< $@
riscv64-linux-gnu-objcopy --target=verilog $< $@
%.out: %.sv $(SOURCE_V)
iverilog -g2012 -o $@ $^
@@ -62,8 +62,6 @@ verify: $(LOGS)
clean:
rm -rf *.vcd *.log *.out *.hex
obj: $(OBJ)
.SECONDARY: %.log %.vcd
.PHONY: all clean verify obj
.PHONY: all clean verify

View File

@@ -1,5 +1,5 @@
# C test
# basic_test
Verify basic ability to use C
Verify basic usage of all instructions. Includes tests to ensure pipeline stalls sufficiently for correctness but does not test for unnecessary stalls.
Currently all C functions fail because store/load do not stall properly.
Currently store/load does not implement proper stalling so these operations are padded with nop

View File

@@ -1,6 +1,6 @@
#include <stdint.h>
// #include <stdint.h>
uint32_t addathing(uint32_t a)
unsigned int addathing(unsigned int a)
{
return a + 0x29;
}

View File

@@ -1,4 +1,5 @@
OUTPUT_ARCH( "riscv" )
ENTRY(_start)
MEMORY
{
@@ -13,7 +14,6 @@ SECTIONS
{
/* . = ALIGN(4); */
_text = .;
*(.text.startup)
*(.text*)
*(.rodata*)
_etext = .;

View File

@@ -31,7 +31,7 @@ initial $readmemh("tb.hex", mem);
// Instruction Memory
wire [31:0] mem_inst_addr;
reg [31:0] mem_inst_data;
always_comb begin
always @(*) begin
if (mem_inst_addr < MEM_LENGTH - 3) begin
mem_inst_data[ 7: 0] = mem[mem_inst_addr+0];
mem_inst_data[15: 8] = mem[mem_inst_addr+1];

View File

@@ -1,23 +1,17 @@
.global _start
.section .text.startup # start vector
j _start
nop
nop
nop
nop
nop
.global addathing
.text
_start:
addi a0, zero, 0x134
addi a1, zero, 0x0
nop
nop
nop
nop
nop
# call addathing # c compilation has sw/lw instructions. Missing stalls break execution
call addathing
nop
nop
nop