Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
38c3cf9
gah
DustTheory Jan 4, 2026
2a660b4
Merge branch 'main' into add-debug-peripheral
DustTheory Jan 4, 2026
3669f2b
Fucking poetic
DustTheory Jan 4, 2026
5fe6fdb
Finally working setup?
DustTheory Jan 5, 2026
a62dc53
Finally a working peripheral. Add read pc function
DustTheory Jan 5, 2026
e98e00a
gah
DustTheory Jan 19, 2026
03dc0d4
Merge branch 'main' into add-debug-peripheral
DustTheory Jan 19, 2026
1261e07
flush pipeline?
DustTheory Jan 19, 2026
85c5640
read the register and vibe some tests
DustTheory Jan 19, 2026
80842b3
read any register, write registers
DustTheory Jan 22, 2026
00f2eca
cleanup
DustTheory Jan 22, 2026
90be966
write_pc command
DustTheory Jan 22, 2026
774e3c8
Add flush logic, and test for flush logic
DustTheory Jan 24, 2026
e4f4cad
fix tests
DustTheory Jan 24, 2026
8c1a7d3
Add github action
DustTheory Jan 24, 2026
966e661
Fix debug peripheral infinite write loop + synth error, fix gh action
DustTheory Jan 24, 2026
44e6626
fix fh action again?
DustTheory Jan 24, 2026
a200cb2
huh?
DustTheory Jan 24, 2026
f1a4d6b
fix unoptflat?
DustTheory Jan 24, 2026
9cbe62f
Revert "fix fh action again?"
DustTheory Jan 24, 2026
9f91ddf
I WIN
DustTheory Jan 24, 2026
b3a18bf
GAH
DustTheory Jan 24, 2026
b421b9e
now?
DustTheory Jan 24, 2026
a72d1f5
add checkout?
DustTheory Jan 24, 2026
f445c9d
Hm?
DustTheory Jan 24, 2026
339c690
yo!
DustTheory Jan 24, 2026
0110e97
Update
DustTheory Jan 24, 2026
f1835ef
:D
DustTheory Jan 24, 2026
fb6313a
asha!
DustTheory Jan 24, 2026
c1b134d
test!
DustTheory Jan 24, 2026
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
78 changes: 78 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Test

on:
push:
branches: ['**']
pull_request:
branches: [main]
workflow_dispatch:

permissions:
contents: read
checks: write
pull-requests: write

jobs:
test:
runs-on: ubuntu-22.04
strategy:
matrix:
test-type: [unit, integration]
fail-fast: false

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup OSS CAD Suite (Verilator)
uses: YosysHQ/setup-oss-cad-suite@v3

- name: Verify Verilator installation
run: verilator --version

- name: Setup Python 3.10
uses: actions/setup-python@v5
with:
python-version: '3.10'
cache: 'pip'
cache-dependency-path: tests/requirements.txt

- name: Install Python dependencies
run: |
cd tests
pip install -r requirements.txt

- name: Run ${{ matrix.test-type }} tests
id: test
continue-on-error: true
run: |
cd tests
make clean TEST_TYPE=${{ matrix.test-type }}
make TEST_TYPE=${{ matrix.test-type }} 2>&1 | tee test-output.log

- name: Generate test summary for job
if: always()
run: |
cd tests
echo "## ${{ matrix.test-type }} Test Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if grep -q "TESTS=" test-output.log; then
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
grep "TESTS=" test-output.log | tail -1 >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
else
echo "Test output not found" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY

- name: Publish test results
uses: EnricoMi/publish-unit-test-result-action@v2
if: always()
with:
files: tests/results.xml
check_name: Test Results (${{ matrix.test-type }})
action_fail_on_inconclusive: false

- name: Fail if tests failed
if: steps.test.outcome == 'failure'
run: exit 1
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
.github/

gpu/
**/*/__pycache__/
tests/test_env/
Expand Down
30 changes: 16 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# RISC-V FPGA Computer

[![Tests](https://github.com/DustTheory/computer/actions/workflows/test-coverage.yml/badge.svg)](https://github.com/DustTheory/computer/actions/workflows/test-coverage.yml)

Building a computer system from scratch on an FPGA, for fun. Features a custom RISC-V RV32I soft-core CPU, VGA video output, and game peripherals.

## What's This?
Expand All @@ -14,12 +16,13 @@ This is a learning project to understand computer architecture from the ground u

## Current Status

**Working on**: DDR3 memory controller initialization
**Working on**: Booting CPU from DDR3

- CPU core: Implemented and passing tests
- Testing: 14 unit tests + 40+ integration tests passing
- Video: VGA module done, framebuffer designed
- Memory: Blocked on MIG (Memory Interface Generator) integration
- CPU core: RV32I implemented and passing tests
- Memory: DDR3 operational @ 81.25 MHz
- Testing: 57 unit tests + 50+ integration tests passing
- Video: VGA module done, framebuffer designed (not yet DDR3-backed)
- Debug: UART debug peripheral working (`tools/debugger/`)

## Development Approach

Expand All @@ -34,7 +37,7 @@ While auxiliary tools like the debugger are coded with AI assistance, the CPU it

**Testing:** Good test coverage prevents regression. Manual testing on FPGA takes too long, so automated tests are a necessity. Tests are written in Python using cocotb and simulated with Verilator. Unit tests verify individual modules, integration tests verify full instruction execution.

**Debug Tools:** A UART-based debugger (`tools/debugger/`) allows real-time inspection of the CPU on FPGA - halt/resume, read/write registers and memory, step through instructions. See [docs/ai/debug-protocol.md](docs/ai/debug-protocol.md).
**Debug Tools:** A UART-based debugger (`tools/debugger/`) allows real-time inspection of the CPU on FPGA - halt/resume, read/write registers and memory, step through instructions.

## Repository Contents

Expand All @@ -50,15 +53,14 @@ Test dependencies: Verilator, Python 3, cocotb

```bash
cd tests
make # Run all tests
make cpu # CPU tests only
make clean # Clean build artifacts
source test_env/bin/activate
make TEST_TYPE=unit # Run unit tests
make TEST_TYPE=integration # Run integration tests
make TEST_TYPE=all # Run all tests
```

## Documentation

- [docs/everyone/](docs/everyone/) - Setup guides and getting started
- [docs/ai/](docs/ai/) - Detailed architecture and protocol specs
- [CLAUDE.md](CLAUDE.md) - Project context and AI instructions

See [docs/everyone/architecture.md](docs/everyone/architecture.md) for CPU details, memory map, and video system design.
- [docs/getting-started.md](docs/getting-started.md) - Setup and getting started
- [docs/architecture.md](docs/architecture.md) - CPU details, memory map, and system design
- [CLAUDE.md](CLAUDE.md) - Project context for AI assistants
54 changes: 22 additions & 32 deletions config/arty-s7-50.xdc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ connect_debug_port u_ila_0/probe3 [get_nets [list {computer_i/proc_sys_reset_0/p





create_debug_core u_ila_0 ila
set_property ALL_PROBE_SAME_MU true [get_debug_cores u_ila_0]
set_property ALL_PROBE_SAME_MU_CNT 1 [get_debug_cores u_ila_0]
Expand All @@ -25,43 +27,31 @@ set_property C_INPUT_PIPE_STAGES 0 [get_debug_cores u_ila_0]
set_property C_TRIGIN_EN false [get_debug_cores u_ila_0]
set_property C_TRIGOUT_EN false [get_debug_cores u_ila_0]
set_property port_width 1 [get_debug_ports u_ila_0/clk]
connect_debug_port u_ila_0/clk [get_nets [list computer_i/mig_7series_0/u_computer_mig_7series_0_0_mig/u_ddr3_infrastructure/CLK]]
connect_debug_port u_ila_0/clk [get_nets [list computer_i/clk_wiz_0/inst/CLK_100]]
set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe0]
set_property port_width 1 [get_debug_ports u_ila_0/probe0]
connect_debug_port u_ila_0/probe0 [get_nets [list {computer_i/proc_sys_reset_0/peripheral_aresetn[0]}]]
connect_debug_port u_ila_0/probe0 [get_nets [list {computer_i/proc_sys_reset_0/interconnect_aresetn[0]}]]
create_debug_port u_ila_0 probe
set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe1]
set_property port_width 1 [get_debug_ports u_ila_0/probe1]
connect_debug_port u_ila_0/probe1 [get_nets [list computer_i/mig_7series_0/init_calib_complete]]
create_debug_core u_ila_1 ila
set_property ALL_PROBE_SAME_MU true [get_debug_cores u_ila_1]
set_property ALL_PROBE_SAME_MU_CNT 1 [get_debug_cores u_ila_1]
set_property C_ADV_TRIGGER false [get_debug_cores u_ila_1]
set_property C_DATA_DEPTH 1024 [get_debug_cores u_ila_1]
set_property C_EN_STRG_QUAL false [get_debug_cores u_ila_1]
set_property C_INPUT_PIPE_STAGES 0 [get_debug_cores u_ila_1]
set_property C_TRIGIN_EN false [get_debug_cores u_ila_1]
set_property C_TRIGOUT_EN false [get_debug_cores u_ila_1]
set_property port_width 1 [get_debug_ports u_ila_1/clk]
connect_debug_port u_ila_1/clk [get_nets [list computer_i/clk_wiz_0/inst/clkfbout_buf_computer_clk_wiz_0_0]]
set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_1/probe0]
set_property port_width 1 [get_debug_ports u_ila_1/probe0]
connect_debug_port u_ila_1/probe0 [get_nets [list computer_i/clk_wiz_0/locked]]
create_debug_core u_ila_2 ila
set_property ALL_PROBE_SAME_MU true [get_debug_cores u_ila_2]
set_property ALL_PROBE_SAME_MU_CNT 1 [get_debug_cores u_ila_2]
set_property C_ADV_TRIGGER false [get_debug_cores u_ila_2]
set_property C_DATA_DEPTH 1024 [get_debug_cores u_ila_2]
set_property C_EN_STRG_QUAL false [get_debug_cores u_ila_2]
set_property C_INPUT_PIPE_STAGES 0 [get_debug_cores u_ila_2]
set_property C_TRIGIN_EN false [get_debug_cores u_ila_2]
set_property C_TRIGOUT_EN false [get_debug_cores u_ila_2]
set_property port_width 1 [get_debug_ports u_ila_2/clk]
connect_debug_port u_ila_2/clk [get_nets [list computer_i/clk_wiz_0/inst/CLK_100]]
set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_2/probe0]
set_property port_width 1 [get_debug_ports u_ila_2/probe0]
connect_debug_port u_ila_2/probe0 [get_nets [list computer_i/reset_timer_0/o_Mig_Reset]]
connect_debug_port u_ila_0/probe1 [get_nets [list {computer_i/proc_sys_reset_0/peripheral_aresetn[0]}]]
create_debug_port u_ila_0 probe
set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe2]
set_property port_width 1 [get_debug_ports u_ila_0/probe2]
connect_debug_port u_ila_0/probe2 [get_nets [list computer_i/proc_sys_reset_0/ext_reset_in]]
create_debug_port u_ila_0 probe
set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe3]
set_property port_width 1 [get_debug_ports u_ila_0/probe3]
connect_debug_port u_ila_0/probe3 [get_nets [list computer_i/mig_7series_0/init_calib_complete]]
create_debug_port u_ila_0 probe
set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe4]
set_property port_width 1 [get_debug_ports u_ila_0/probe4]
connect_debug_port u_ila_0/probe4 [get_nets [list computer_i/clk_wiz_0/inst/locked]]
create_debug_port u_ila_0 probe
set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe5]
set_property port_width 1 [get_debug_ports u_ila_0/probe5]
connect_debug_port u_ila_0/probe5 [get_nets [list computer_i/mig_7series_0/sys_rst]]
set_property C_CLK_INPUT_FREQ_HZ 300000000 [get_debug_cores dbg_hub]
set_property C_ENABLE_CLK_DIVIDER false [get_debug_cores dbg_hub]
set_property C_USER_SCAN_CHAIN 1 [get_debug_cores dbg_hub]
connect_debug_port dbg_hub/clk [get_nets u_ila_2_CLK_100]
connect_debug_port dbg_hub/clk [get_nets u_ila_0_CLK_100]
16 changes: 15 additions & 1 deletion hdl/cpu/control_unit/control_unit.v
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ module control_unit (
input [OP_CODE_WIDTH:0] i_Op_Code,
input [FUNC3_WIDTH:0] i_Funct3,
input i_Funct7_Bit_5,
/* verilator lint_off UNOPTFLAT */
input i_Branch_Enable,
/* verilator lint_on UNOPTFLAT */
output reg o_Port_A_Select,
output reg o_Port_B_Select,
output reg [REG_ADDR_WIDTH-1:0] o_Reg_Write_Select,
Expand All @@ -20,7 +22,8 @@ module control_unit (
output reg [LS_SEL_WIDTH:0] o_Load_Store_Type,
output reg o_Pc_Alu_Mux_Select,
output reg o_Reg_Write_Enable,
output reg o_Mem_Write_Enable
output reg o_Mem_Write_Enable,
output reg o_Flush_Pipeline
);

always @* begin
Expand All @@ -33,6 +36,7 @@ module control_unit (
o_Pc_Alu_Mux_Select = 1'b0;
o_Imm_Select = IMM_UNKNOWN_TYPE;
o_Load_Store_Type = LS_TYPE_NONE;
o_Flush_Pipeline = 1'b0;
case (i_Funct3)
FUNC3_ALU_ADD_SUB: begin
o_Alu_Select = (i_Funct7_Bit_5) ? ALU_SEL_SUB : ALU_SEL_ADD;
Expand Down Expand Up @@ -101,6 +105,7 @@ module control_unit (
o_Imm_Select = IMM_U_TYPE;
o_Reg_Write_Select = REG_WRITE_IMM;
o_Load_Store_Type = LS_TYPE_NONE;
o_Flush_Pipeline = 1'b0;
end
OP_U_TYPE_AUIPC: begin
o_Port_A_Select = 1'b0;
Expand All @@ -113,6 +118,7 @@ module control_unit (
o_Imm_Select = IMM_U_TYPE;
o_Reg_Write_Select = REG_WRITE_ALU;
o_Load_Store_Type = LS_TYPE_NONE;
o_Flush_Pipeline = 1'b0;
end
OP_J_TYPE: begin
o_Port_A_Select = 1'b0;
Expand All @@ -125,6 +131,7 @@ module control_unit (
o_Imm_Select = IMM_J_TYPE;
o_Reg_Write_Select = REG_WRITE_PC_NEXT;
o_Load_Store_Type = LS_TYPE_NONE;
o_Flush_Pipeline = 1'b1;
end
OP_I_TYPE_ALU: begin
o_Port_A_Select = 1'b1;
Expand All @@ -134,6 +141,7 @@ module control_unit (
o_Pc_Alu_Mux_Select = 1'b0;
o_Imm_Select = IMM_I_TYPE;
o_Load_Store_Type = LS_TYPE_NONE;
o_Flush_Pipeline = 1'b0;
case (i_Funct3)
FUNC3_ALU_ADD_SUB: begin
o_Alu_Select = (i_Funct7_Bit_5) ? ALU_SEL_SUB : ALU_SEL_ADD;
Expand Down Expand Up @@ -195,6 +203,7 @@ module control_unit (
o_Imm_Select = IMM_I_TYPE;
o_Reg_Write_Select = REG_WRITE_PC_NEXT;
o_Load_Store_Type = LS_TYPE_NONE;
o_Flush_Pipeline = 1'b1;
end
OP_I_TYPE_LOAD: begin
o_Port_A_Select = 1'b1;
Expand All @@ -214,6 +223,7 @@ module control_unit (
FUNC3_LS_HU: o_Load_Store_Type = LS_TYPE_LOAD_HALF_UNSIGNED;
default: o_Load_Store_Type = LS_TYPE_NONE;
endcase
o_Flush_Pipeline = 1'b0;
end
OP_S_TYPE: begin
o_Port_A_Select = 1'b1;
Expand All @@ -231,6 +241,7 @@ module control_unit (
FUNC3_LS_W: o_Load_Store_Type = LS_TYPE_STORE_WORD;
default: o_Load_Store_Type = LS_TYPE_NONE;
endcase
o_Flush_Pipeline = 1'b0;
end
OP_B_TYPE: begin
o_Port_A_Select = 1'b0;
Expand All @@ -251,6 +262,7 @@ module control_unit (
FUNC3_BRANCH_BGEU: o_Cmp_Select = CMP_SEL_GEU;
default: o_Cmp_Select = CMP_SEL_UNKNOWN;
endcase
o_Flush_Pipeline = i_Branch_Enable;
end
default: begin
o_Port_A_Select = 1'b0;
Expand All @@ -263,6 +275,7 @@ module control_unit (
o_Imm_Select = IMM_UNKNOWN_TYPE;
o_Load_Store_Type = LS_TYPE_NONE;
o_Reg_Write_Select = REG_WRITE_NONE;
o_Flush_Pipeline = 1'b0;
end
endcase
end else begin
Expand All @@ -276,6 +289,7 @@ module control_unit (
o_Imm_Select = IMM_UNKNOWN_TYPE;
o_Load_Store_Type = LS_TYPE_NONE;
o_Reg_Write_Select = REG_WRITE_NONE;
o_Flush_Pipeline = 1'b0;
end
end

Expand Down
Loading