Refine Arty A7 bring-up and memory-map assumptions
Replace the first broad project sketch with more concrete hardware assumptions for implementation on the Arty A7 100T. Document the 50 MHz MMCM-derived clock, synchronous active-high reset after the board reset synchronizer, and a split instruction/data BRAM map with reset PC at 0x2000_0000. Update the UART layout to separate TX, RX, and status registers, and make the README/roadmap agree on the address ranges that firmware and the future linker script will use. Also split the M extension out of the combinational ALU into a dedicated multi-cycle unit with start/busy/done handshaking, describe BRAM latency and stall behavior in the single-cycle logical model, and add riscv-tests as the planned compliance check once GCC-generated programs are running.
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
## Project Overview
|
||||
|
||||
This is a custom RISC-V RV32IM CPU core written in SystemVerilog, targeting the
|
||||
Digilent Arty A7 100T (xc7a100tcsg324-1) with Vivado 2025.2.1.
|
||||
Digilent Arty A7 100T (xc7a100tcsg324-1) with Vivado 2025.2 or later.
|
||||
|
||||
The goal is incremental development from a single-cycle core to a Linux-capable SoC.
|
||||
See ROADMAP.md for the full phased plan.
|
||||
@@ -18,25 +18,31 @@ See ROADMAP.md for the full phased plan.
|
||||
- Module naming: `rv32_<block>` (e.g., `rv32_alu`, `rv32_decode`, `rv32_regfile`).
|
||||
- File naming: one module per file, filename matches module name.
|
||||
- Testbenches: `tb/tb_<module>.sv`. Use Vivado simulator.
|
||||
- Clock: single clock domain, active rising edge, signal named `clk`.
|
||||
- Reset: synchronous active-high, signal named `rst`.
|
||||
- Clock: single clock domain, active rising edge, signal named `clk`. Target
|
||||
frequency: 50 MHz (derived from the Arty's 100 MHz oscillator via MMCM/2).
|
||||
- Reset: synchronous active-high, signal named `rst`. The Arty's `CK_RST` button
|
||||
is active-low; the top-level wraps it through a 2-FF synchronizer and inverts
|
||||
to produce the internal `rst`. The rest of the design only sees synchronous
|
||||
active-high.
|
||||
- BRAM init files: `mem/*.mem` in hex format, one 32-bit word per line.
|
||||
- Firmware source: `fw/` directory. Built with riscv64-unknown-elf-gcc,
|
||||
-march=rv32im -mabi=ilp32.
|
||||
- Firmware source: `fw/` directory. Built with `riscv64-unknown-elf-gcc`
|
||||
(multilib build required), `-march=rv32im_zicsr_zifencei -mabi=ilp32`. The
|
||||
full march string is required by GCC 11+ even before CSRs are implemented;
|
||||
`Zifencei` is a NOP until caches exist (Phase 13+).
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
rtl/ — synthesizable source
|
||||
pkg/ — packages (rv32_pkg.sv)
|
||||
core/ — CPU core modules (ALU, decoder, regfile, datapath)
|
||||
periph/ — peripherals (UART, timer, etc.)
|
||||
top/ — top-level and SoC integration
|
||||
tb/ — testbenches
|
||||
mem/ — BRAM init files (.mem)
|
||||
fw/ — firmware source (C, assembly, linker scripts)
|
||||
constraints/ — Vivado XDC constraint files
|
||||
docs/ — block diagrams, notes
|
||||
rtl/ — synthesizable source
|
||||
pkg/ — packages (rv32_pkg.sv)
|
||||
core/ — CPU core modules (ALU, M unit, decoder, regfile, datapath)
|
||||
periph/ — peripherals (UART, timer, PLIC, etc.)
|
||||
top/ — top-level and SoC integration
|
||||
tb/ — testbenches (tb_<module>.sv)
|
||||
mem/ — BRAM init files (.mem)
|
||||
fw/ — firmware source (C, assembly, linker scripts)
|
||||
constraints/ — Vivado XDC constraint files
|
||||
docs/ — block diagrams, notes
|
||||
```
|
||||
|
||||
## ISA Target
|
||||
@@ -51,12 +57,38 @@ RV32IM base. Extensions added incrementally:
|
||||
|
||||
- Single-cycle first, pipeline later (Phase 12). Stages are separated in the code
|
||||
even without pipeline registers between them.
|
||||
- "Single-cycle" is a logical model, not a literal one cycle per instruction.
|
||||
BRAM has a 1-cycle read latency, so fetch is registered and loads take 2
|
||||
cycles. The datapath stalls fetch while a multi-cycle operation is in flight.
|
||||
- Memory bus uses valid/ready handshake from day one, even though BRAM always
|
||||
responds in one cycle. This is for future DRAM compatibility.
|
||||
- M extension (multiply/divide) is in the ALU from the start to avoid rework.
|
||||
- M extension (multiply/divide) lives in a dedicated multi-cycle M unit
|
||||
alongside the combinational ALU, with a `start`/`busy`/`done` handshake.
|
||||
Multiply is 2-3 cycles via DSP48s; divide is iterative (~33 cycles). The
|
||||
datapath stalls when the M unit is busy. Building this from day one avoids
|
||||
retrofitting stall logic later.
|
||||
- Harvard architecture (separate instruction and data memory) initially. Unified
|
||||
memory when DRAM is added.
|
||||
|
||||
## Memory Map
|
||||
|
||||
```
|
||||
0x0000_0000 – 0x0FFF_FFFF reserved (future SPI flash boot region, Phase 13)
|
||||
0x1000_0000 – 0x1000_0FFF MMIO (UART; later: timer, PLIC)
|
||||
0x2000_0000 – 0x2000_FFFF instruction BRAM (64 KB)
|
||||
0x8000_0000 – 0x8000_FFFF data BRAM (64 KB) → grows to DRAM 0x8000_0000–0x8FFF_FFFF in Phase 13
|
||||
```
|
||||
|
||||
Reset PC = `0x2000_0000`. Linker script anchors text/rodata at `0x2000_0000`
|
||||
and data/bss/stack at `0x8000_0000` from Phase 8 onward.
|
||||
|
||||
UART register layout (split, not 16550-style):
|
||||
```
|
||||
0x1000_0000 TX data (W: byte to send)
|
||||
0x1000_0004 RX data (R: pops one byte from RX FIFO)
|
||||
0x1000_0008 status (R: bit0 = tx_busy, bit1 = rx_valid)
|
||||
```
|
||||
|
||||
## When Helping With This Project
|
||||
|
||||
- Always check rv32_pkg.sv first to understand current struct definitions and enums.
|
||||
@@ -65,7 +97,10 @@ RV32IM base. Extensions added incrementally:
|
||||
before integration.
|
||||
- Don't add Verilog-style code (reg, wire, always @). Use SV equivalents.
|
||||
- When suggesting fixes, consider that the design is single-cycle — there are no
|
||||
pipeline hazards yet.
|
||||
pipeline hazards yet, but the M unit and BRAM both introduce stalls.
|
||||
- ISA correctness is verified against `riscv-tests` (rv32ui, rv32um) starting at
|
||||
Phase 8.5. Hand-written testbenches are for module-level checks; the official
|
||||
suite is the source of truth for instruction behavior.
|
||||
- Vivado quirks: use (* dont_touch = "true" *) for signals that Vivado optimizes
|
||||
away during debug. ILA/VIO probes need to be on nets that survive synthesis.
|
||||
- The Arty A7 100T has: 101,440 logic cells, 4,860 Kbit BRAM, 240 DSP slices,
|
||||
|
||||
Reference in New Issue
Block a user